xen-vtx-unstable
annotate tools/python/xen/xend/server/controller.py @ 2225:f8bc691dd640
bitkeeper revision 1.1159.1.53 (411ccd729CC_RzyLGa4nViY2XcSdig)
Separate controller backend from the controller factory, allowing
each controller to have its own backend domain.
Separate controller backend from the controller factory, allowing
each controller to have its own backend domain.
author | mjw@wray-m-3.hpl.hp.com |
---|---|
date | Fri Aug 13 14:17:22 2004 +0000 (2004-08-13) |
parents | 6c85a89e99e3 |
children | af0729973950 703b333dc90c a6d73a771367 |
rev | line source |
---|---|
mjw@1654 | 1 # Copyright (C) 2004 Mike Wray <mike.wray@hp.com> |
mjw@1719 | 2 """General support for controllers, which handle devices |
mjw@1719 | 3 for a domain. |
mjw@1719 | 4 """ |
mjw@1654 | 5 |
mjw@1623 | 6 from twisted.internet import defer |
mjw@1721 | 7 #defer.Deferred.debug = 1 |
mjw@1623 | 8 |
mjw@1623 | 9 import channel |
mjw@1719 | 10 from messages import msgTypeName, printMsg |
mjw@1623 | 11 |
mjw@2224 | 12 DEBUG = 1 |
mjw@1677 | 13 |
mjw@1677 | 14 class Responder: |
mjw@1719 | 15 """Handler for a response to a message with a specified id. |
mjw@1677 | 16 """ |
mjw@1677 | 17 |
mjw@1677 | 18 def __init__(self, mid, deferred): |
mjw@1677 | 19 """Create a responder. |
mjw@1677 | 20 |
mjw@1719 | 21 @param mid: message id of response to handle |
mjw@1719 | 22 @type mid: int |
mjw@1719 | 23 @param deferred: deferred object holding the callbacks |
mjw@1719 | 24 @type deferred: Deferred |
mjw@1677 | 25 """ |
mjw@1677 | 26 self.mid = mid |
mjw@1677 | 27 self.deferred = deferred |
mjw@1677 | 28 |
mjw@1677 | 29 def responseReceived(self, msg): |
mjw@1719 | 30 """Entry point called when a response message with the right id arrives. |
mjw@1719 | 31 Calls callback on I{self.deferred} with the message. |
mjw@1719 | 32 |
mjw@1719 | 33 @param msg: response message |
mjw@1719 | 34 @type msg: xu message |
mjw@1719 | 35 """ |
mjw@1677 | 36 if self.deferred.called: return |
mjw@1677 | 37 self.deferred.callback(msg) |
mjw@1677 | 38 |
mjw@1677 | 39 def error(self, err): |
mjw@1719 | 40 """Entry point called when there has been an error. |
mjw@1719 | 41 Calls errback on I{self.deferred} with the error. |
mjw@1719 | 42 |
mjw@1719 | 43 @param err: error |
mjw@1719 | 44 @type err: Exception |
mjw@1719 | 45 """ |
mjw@1677 | 46 if self.deferred.called: return |
mjw@1677 | 47 self.deferred.errback(err) |
mjw@1677 | 48 |
mjw@1623 | 49 class CtrlMsgRcvr: |
mjw@1623 | 50 """Abstract class for things that deal with a control interface to a domain. |
mjw@1719 | 51 Once I{registerChannel} has been called, our message types are registered |
mjw@1719 | 52 with the channel to the domain. The channel will call I{requestReceived} |
mjw@1719 | 53 when a request arrives, or I{responseReceived} when a response arrives, |
mjw@1719 | 54 if they have one of our message types. |
mjw@1654 | 55 |
mjw@1719 | 56 @ivar dom: the domain we are a control interface for |
mjw@1719 | 57 @type dom: int |
mjw@1719 | 58 @ivar majorTypes: major message types we are interested in |
mjw@2224 | 59 @type majorTypes: {int:{int:method}} |
mjw@1719 | 60 @ivar timeout: timeout (in seconds) for message handlers |
mjw@1719 | 61 @type timeout: int |
mjw@1654 | 62 |
mjw@1719 | 63 @ivar channel: channel to the domain |
mjw@1719 | 64 @type channel: Channel |
mjw@1719 | 65 @ivar idx: channel index |
mjw@1719 | 66 @ivar idx: string |
mjw@1719 | 67 @ivar responders: table of message response handlers |
mjw@1719 | 68 @type responders: {int:Responder} |
mjw@1623 | 69 """ |
mjw@1623 | 70 |
mjw@1623 | 71 def __init__(self): |
mjw@1623 | 72 self.channelFactory = channel.channelFactory() |
mjw@2224 | 73 self.majorTypes = {} |
mjw@1623 | 74 self.dom = None |
mjw@1623 | 75 self.channel = None |
mjw@1623 | 76 self.idx = None |
mjw@1728 | 77 self.responders = {} |
mjw@1677 | 78 self.timeout = 10 |
mjw@1677 | 79 |
mjw@1677 | 80 def setTimeout(self, timeout): |
mjw@1677 | 81 self.timeout = timeout |
mjw@1623 | 82 |
mjw@2224 | 83 def getMethod(self, type, subtype): |
mjw@2224 | 84 """Get the method for a type and subtype. |
mjw@2224 | 85 |
mjw@2224 | 86 @param type: major message type |
mjw@2224 | 87 @param subtype: minor message type |
mjw@2224 | 88 @return: method or None |
mjw@2224 | 89 """ |
mjw@2224 | 90 method = None |
mjw@2224 | 91 subtypes = self.majorTypes.get(type) |
mjw@2224 | 92 if subtypes: |
mjw@2224 | 93 method = subtypes.get(subtype) |
mjw@2224 | 94 return method |
mjw@2224 | 95 |
mjw@2224 | 96 def addMethod(self, type, subtype, method): |
mjw@2224 | 97 """Add a method to handle a message type and subtype. |
mjw@2224 | 98 |
mjw@2224 | 99 @param type: major message type |
mjw@2224 | 100 @param subtype: minor message type |
mjw@2224 | 101 @param method: method |
mjw@2224 | 102 """ |
mjw@2224 | 103 subtypes = self.majorTypes.get(type) |
mjw@2224 | 104 if not subtypes: |
mjw@2224 | 105 subtypes = {} |
mjw@2224 | 106 self.majorTypes[type] = subtypes |
mjw@2224 | 107 subtypes[subtype] = method |
mjw@2224 | 108 |
mjw@2224 | 109 def getMajorTypes(self): |
mjw@2224 | 110 """Get the list of major message types handled. |
mjw@2224 | 111 """ |
mjw@2224 | 112 return self.majorTypes.keys() |
mjw@2224 | 113 |
mjw@1623 | 114 def requestReceived(self, msg, type, subtype): |
mjw@1719 | 115 """Dispatch a request message to handlers. |
mjw@1719 | 116 Called by the channel for requests with one of our types. |
mjw@1654 | 117 |
mjw@1719 | 118 @param msg: message |
mjw@1719 | 119 @type msg: xu message |
mjw@1719 | 120 @param type: major message type |
mjw@1719 | 121 @type type: int |
mjw@1719 | 122 @param subtype: minor message type |
mjw@1719 | 123 @type subtype: int |
mjw@1654 | 124 """ |
mjw@1677 | 125 if DEBUG: |
mjw@1719 | 126 print 'requestReceived>', |
mjw@1719 | 127 printMsg(msg, all=1) |
mjw@2224 | 128 method = self.getMethod(type, subtype) |
mjw@1623 | 129 if method: |
mjw@1623 | 130 method(msg, 1) |
mjw@1677 | 131 elif DEBUG: |
mjw@1623 | 132 print ('requestReceived> No handler: Message type %s %d:%d' |
mjw@1623 | 133 % (msgTypeName(type, subtype), type, subtype)), self |
mjw@1623 | 134 |
mjw@1623 | 135 def responseReceived(self, msg, type, subtype): |
mjw@1654 | 136 """Dispatch a response to handlers. |
mjw@1719 | 137 Called by the channel for responses with one of our types. |
mjw@1719 | 138 |
mjw@1719 | 139 First looks for a message responder for the message's id. |
mjw@1719 | 140 See L{callResponders}, L{addResponder}. |
mjw@1719 | 141 If there is no responder, looks for a message handler for |
mjw@1719 | 142 the message type/subtype. |
mjw@1654 | 143 |
mjw@1719 | 144 @param msg: message |
mjw@1719 | 145 @type msg: xu message |
mjw@1719 | 146 @param type: major message type |
mjw@1719 | 147 @type type: int |
mjw@1719 | 148 @param subtype: minor message type |
mjw@1719 | 149 @type subtype: int |
mjw@1654 | 150 """ |
mjw@1677 | 151 if DEBUG: |
mjw@1719 | 152 print 'responseReceived>', |
mjw@1719 | 153 printMsg(msg, all=1) |
mjw@1677 | 154 if self.callResponders(msg): |
mjw@1677 | 155 return |
mjw@2224 | 156 method = self.getMethod(type, subtype) |
mjw@1623 | 157 if method: |
mjw@1623 | 158 method(msg, 0) |
mjw@1677 | 159 elif DEBUG: |
mjw@1623 | 160 print ('responseReceived> No handler: Message type %s %d:%d' |
mjw@1623 | 161 % (msgTypeName(type, subtype), type, subtype)), self |
mjw@1623 | 162 |
mjw@1677 | 163 def addResponder(self, mid, deferred): |
mjw@1677 | 164 """Add a responder for a message id. |
mjw@1719 | 165 The I{deferred} is called with callback(msg) when a response |
mjw@1728 | 166 with message id I{mid} arrives. |
mjw@1677 | 167 |
mjw@1719 | 168 Responders have a timeout set and I{deferred} will error |
mjw@1719 | 169 on expiry. |
mjw@1677 | 170 |
mjw@1719 | 171 @param mid: message id of response expected |
mjw@1719 | 172 @type mid: int |
mjw@1719 | 173 @param deferred: handler for the response |
mjw@1719 | 174 @type deferred: Deferred |
mjw@1719 | 175 @return: responder |
mjw@1719 | 176 @rtype: Responder |
mjw@1677 | 177 """ |
mjw@1728 | 178 resp = Responder(mid, deferred) |
mjw@1728 | 179 self.responders[resp.mid] = resp |
mjw@1677 | 180 if self.timeout > 0: |
mjw@1677 | 181 deferred.setTimeout(self.timeout) |
mjw@1677 | 182 return resp |
mjw@1677 | 183 |
mjw@1677 | 184 def callResponders(self, msg): |
mjw@1677 | 185 """Call any waiting responders for a response message. |
mjw@1719 | 186 Looks for a responder registered for the message's id. |
mjw@1719 | 187 See L{addResponder}. |
mjw@1677 | 188 |
mjw@1719 | 189 @param msg: response message |
mjw@1719 | 190 @type msg: xu message |
mjw@1719 | 191 @return: 1 if there was a responder for the message, 0 otherwise |
mjw@1719 | 192 @rtype : bool |
mjw@1677 | 193 """ |
mjw@1677 | 194 hdr = msg.get_header() |
mjw@1677 | 195 mid = hdr['id'] |
mjw@1677 | 196 handled = 0 |
mjw@1728 | 197 resp = self.responders.get(mid) |
mjw@1728 | 198 if resp: |
mjw@1728 | 199 handled = 1 |
mjw@1728 | 200 resp.responseReceived(msg) |
mjw@1728 | 201 del self.responders[mid] |
mjw@1728 | 202 # Clean up called responders. |
mjw@1728 | 203 for resp in self.responders.values(): |
mjw@1728 | 204 if resp.deferred.called: |
mjw@1728 | 205 del self.responders[resp.mid] |
mjw@1677 | 206 return handled |
mjw@1677 | 207 |
mjw@1623 | 208 def lostChannel(self): |
mjw@1654 | 209 """Called when the channel to the domain is lost. |
mjw@1654 | 210 """ |
mjw@1623 | 211 pass |
mjw@1623 | 212 |
mjw@1623 | 213 def registerChannel(self): |
mjw@1654 | 214 """Register interest in our major message types with the |
mjw@1719 | 215 channel to our domain. Once we have registered, the channel |
mjw@1719 | 216 will call requestReceived or responseReceived for our messages. |
mjw@1654 | 217 """ |
mjw@1623 | 218 self.channel = self.channelFactory.domChannel(self.dom) |
mjw@1623 | 219 self.idx = self.channel.getIndex() |
mjw@1623 | 220 if self.majorTypes: |
mjw@2224 | 221 self.channel.registerDevice(self.getMajorTypes(), self) |
mjw@1623 | 222 |
mjw@1623 | 223 def deregisterChannel(self): |
mjw@1654 | 224 """Deregister interest in our major message types with the |
mjw@1719 | 225 channel to our domain. After this the channel won't call |
mjw@1719 | 226 us any more. |
mjw@1654 | 227 """ |
mjw@1623 | 228 if self.channel: |
mjw@1623 | 229 self.channel.deregisterDevice(self) |
mjw@1893 | 230 self.channel = None |
mjw@1623 | 231 |
mjw@1623 | 232 def produceRequests(self): |
mjw@1654 | 233 """Produce any queued requests. |
mjw@1654 | 234 |
mjw@1719 | 235 @return: number produced |
mjw@1719 | 236 @rtype: int |
mjw@1654 | 237 """ |
mjw@1623 | 238 return 0 |
mjw@1623 | 239 |
mjw@1677 | 240 def writeRequest(self, msg, response=None): |
mjw@1654 | 241 """Write a request to the channel. |
mjw@1677 | 242 |
mjw@1719 | 243 @param msg: request message |
mjw@1719 | 244 @type msg: xu message |
mjw@1719 | 245 @param response: response handler |
mjw@1719 | 246 @type response: Deferred |
mjw@1654 | 247 """ |
mjw@1623 | 248 if self.channel: |
mjw@1719 | 249 if DEBUG: |
mjw@1719 | 250 print 'CtrlMsgRcvr>writeRequest>', |
mjw@1719 | 251 printMsg(msg, all=1) |
mjw@1677 | 252 if response: |
mjw@1677 | 253 self.addResponder(msg.get_header()['id'], response) |
mjw@1623 | 254 self.channel.writeRequest(msg) |
mjw@1623 | 255 else: |
mjw@1623 | 256 print 'CtrlMsgRcvr>writeRequest>', 'no channel!', self |
mjw@1623 | 257 |
mjw@1623 | 258 def writeResponse(self, msg): |
mjw@1719 | 259 """Write a response to the channel. This acknowledges |
mjw@1719 | 260 a request message. |
mjw@1719 | 261 |
mjw@1719 | 262 @param msg: message |
mjw@1719 | 263 @type msg: xu message |
mjw@1654 | 264 """ |
mjw@1623 | 265 if self.channel: |
mjw@1719 | 266 if DEBUG: |
mjw@1719 | 267 print 'CtrlMsgRcvr>writeResponse>', |
mjw@1719 | 268 printMsg(msg, all=0) |
mjw@1623 | 269 self.channel.writeResponse(msg) |
mjw@1623 | 270 else: |
mjw@1623 | 271 print 'CtrlMsgRcvr>writeResponse>', 'no channel!', self |
mjw@1623 | 272 |
mjw@2225 | 273 class ControllerFactory: |
mjw@1719 | 274 """Abstract class for factories creating controllers for a domain. |
mjw@1623 | 275 Maintains a table of instances. |
mjw@1654 | 276 |
mjw@1719 | 277 @ivar instances: mapping of index to controller instance |
mjw@2185 | 278 @type instances: {String: Controller} |
mjw@1719 | 279 @ivar dom: domain |
mjw@1719 | 280 @type dom: int |
mjw@1623 | 281 """ |
mjw@1623 | 282 |
mjw@1623 | 283 def __init__(self): |
mjw@1623 | 284 self.instances = {} |
mjw@2225 | 285 self.backends = {} |
mjw@1623 | 286 self.dom = 0 |
mjw@1623 | 287 |
mjw@1623 | 288 def addInstance(self, instance): |
mjw@1654 | 289 """Add a controller instance (under its index). |
mjw@1654 | 290 """ |
mjw@1623 | 291 self.instances[instance.idx] = instance |
mjw@1623 | 292 |
mjw@1623 | 293 def getInstance(self, idx): |
mjw@1654 | 294 """Get a controller instance from its index. |
mjw@1654 | 295 """ |
mjw@1623 | 296 return self.instances.get(idx) |
mjw@1623 | 297 |
mjw@1623 | 298 def getInstances(self): |
mjw@1654 | 299 """Get a list of all controller instances. |
mjw@1654 | 300 """ |
mjw@1623 | 301 return self.instances.values() |
mjw@1623 | 302 |
mjw@1623 | 303 def getInstanceByDom(self, dom): |
mjw@1654 | 304 """Get the controller instance for the given domain. |
mjw@2185 | 305 |
mjw@2185 | 306 @param dom: domain id |
mjw@2185 | 307 @type dom: int |
mjw@2185 | 308 @return: controller or None |
mjw@1654 | 309 """ |
mjw@1623 | 310 for inst in self.instances.values(): |
mjw@1623 | 311 if inst.dom == dom: |
mjw@1623 | 312 return inst |
mjw@1623 | 313 return None |
mjw@1623 | 314 |
mjw@1623 | 315 def delInstance(self, instance): |
mjw@2185 | 316 """Delete a controller instance from the table. |
mjw@2185 | 317 |
mjw@2185 | 318 @param instance: controller instance |
mjw@1654 | 319 """ |
mjw@1623 | 320 if instance.idx in self.instances: |
mjw@1623 | 321 del self.instances[instance.idx] |
mjw@1623 | 322 |
mjw@1623 | 323 def createInstance(self, dom, recreate=0): |
mjw@1654 | 324 """Create an instance. Define in a subclass. |
mjw@1719 | 325 |
mjw@1719 | 326 @param dom: domain |
mjw@1719 | 327 @type dom: int |
mjw@1719 | 328 @param recreate: true if the instance is being recreated (after xend restart) |
mjw@1719 | 329 @type recreate: int |
mjw@2185 | 330 @return: controller instance |
mjw@2185 | 331 @rtype: Controller (or subclass) |
mjw@1654 | 332 """ |
mjw@1623 | 333 raise NotImplementedError() |
mjw@1623 | 334 |
mjw@1623 | 335 def instanceClosed(self, instance): |
mjw@1654 | 336 """Callback called when an instance is closed (usually by the instance). |
mjw@2185 | 337 |
mjw@2185 | 338 @param instance: controller instance |
mjw@1654 | 339 """ |
mjw@1623 | 340 self.delInstance(instance) |
mjw@1623 | 341 |
mjw@1623 | 342 class Controller(CtrlMsgRcvr): |
mjw@1623 | 343 """Abstract class for a device controller attached to a domain. |
mjw@2185 | 344 |
mjw@2185 | 345 @ivar factory: controller factory |
mjw@2185 | 346 @type factory: ControllerFactory |
mjw@2185 | 347 @ivar dom: domain |
mjw@2185 | 348 @type dom: int |
mjw@2185 | 349 @ivar channel: channel to the domain |
mjw@2185 | 350 @type channel: Channel |
mjw@2185 | 351 @ivar idx: channel index |
mjw@2185 | 352 @type idx: String |
mjw@1623 | 353 """ |
mjw@1623 | 354 |
mjw@1623 | 355 def __init__(self, factory, dom): |
mjw@1623 | 356 CtrlMsgRcvr.__init__(self) |
mjw@1623 | 357 self.factory = factory |
mjw@1623 | 358 self.dom = int(dom) |
mjw@1623 | 359 self.channel = None |
mjw@1623 | 360 self.idx = None |
mjw@1623 | 361 |
mjw@1623 | 362 def close(self): |
mjw@1654 | 363 """Close the controller. |
mjw@1654 | 364 """ |
mjw@1623 | 365 self.lostChannel() |
mjw@1623 | 366 |
mjw@1623 | 367 def lostChannel(self): |
mjw@1654 | 368 """The controller channel has been lost. |
mjw@1654 | 369 """ |
mjw@1664 | 370 self.deregisterChannel() |
mjw@1623 | 371 self.factory.instanceClosed(self) |
mjw@1623 | 372 |
mjw@2225 | 373 class SplitControllerFactory(ControllerFactory): |
mjw@2225 | 374 """Factory for SplitControllers. |
mjw@2225 | 375 |
mjw@2225 | 376 @ivar backends: mapping of domain id to backend |
mjw@2225 | 377 @type backends: {int: BackendController} |
mjw@2225 | 378 """ |
mjw@2225 | 379 |
mjw@2225 | 380 def __init__(self): |
mjw@2225 | 381 ControllerFactory.__init__(self) |
mjw@2225 | 382 self.backends = {} |
mjw@2225 | 383 |
mjw@2225 | 384 def createInstance(self, dom, recreate=0, backend=0): |
mjw@2225 | 385 """Create an instance. Define in a subclass. |
mjw@2225 | 386 |
mjw@2225 | 387 @param dom: domain |
mjw@2225 | 388 @type dom: int |
mjw@2225 | 389 @param recreate: true if the instance is being recreated (after xend restart) |
mjw@2225 | 390 @type recreate: int |
mjw@2225 | 391 @param backend: backend domain |
mjw@2225 | 392 @type backend: int |
mjw@2225 | 393 @return: controller instance |
mjw@2225 | 394 @rtype: SplitController (or subclass) |
mjw@2225 | 395 """ |
mjw@2225 | 396 raise NotImplementedError() |
mjw@2225 | 397 |
mjw@2225 | 398 def getBackendController(self, dom): |
mjw@2225 | 399 """Get the backend controller for a domain. |
mjw@2225 | 400 |
mjw@2225 | 401 @param dom: domain |
mjw@2225 | 402 @return: backend controller |
mjw@2225 | 403 """ |
mjw@2225 | 404 ctrlr = self.backends.get(dom) |
mjw@2225 | 405 if ctrlr is None: |
mjw@2225 | 406 ctrlr = self.createBackendController(dom) |
mjw@2225 | 407 self.backends[dom] = ctrlr |
mjw@2225 | 408 return ctrlr |
mjw@2225 | 409 |
mjw@2225 | 410 def createBackendController(self, dom): |
mjw@2225 | 411 """Create a backend controller. Define in a subclass. |
mjw@2225 | 412 |
mjw@2225 | 413 @param dom: domain |
mjw@2225 | 414 """ |
mjw@2225 | 415 raise NotImplementedError() |
mjw@2225 | 416 |
mjw@2225 | 417 def delBackendController(self, ctrlr): |
mjw@2225 | 418 """Remove a backend controller. |
mjw@2225 | 419 |
mjw@2225 | 420 @param ctrlr: backend controller |
mjw@2225 | 421 """ |
mjw@2225 | 422 if ctrlr.dom in self.backends: |
mjw@2225 | 423 del self.backends[ctrlr.dom] |
mjw@2225 | 424 |
mjw@2225 | 425 def backendControllerClosed(self, ctrlr): |
mjw@2225 | 426 """Callback called when a backend is closed. |
mjw@2225 | 427 """ |
mjw@2225 | 428 self.delBackendController(ctrlr) |
mjw@2225 | 429 |
mjw@2225 | 430 class BackendController(CtrlMsgRcvr): |
mjw@2225 | 431 """Abstract class for a backend device controller attached to a domain. |
mjw@2225 | 432 |
mjw@2225 | 433 @ivar factory: controller factory |
mjw@2225 | 434 @type factory: ControllerFactory |
mjw@2225 | 435 @ivar dom: domain |
mjw@2225 | 436 @type dom: int |
mjw@2225 | 437 @ivar channel: channel to the domain |
mjw@2225 | 438 @type channel: Channel |
mjw@2225 | 439 """ |
mjw@2225 | 440 |
mjw@2225 | 441 |
mjw@2225 | 442 def __init__(self, factory, dom): |
mjw@2225 | 443 CtrlMsgRcvr.__init__(self) |
mjw@2225 | 444 self.factory = factory |
mjw@2225 | 445 self.dom = int(dom) |
mjw@2225 | 446 self.channel = None |
mjw@2225 | 447 |
mjw@2225 | 448 def close(self): |
mjw@2225 | 449 self.lostChannel() |
mjw@2225 | 450 |
mjw@2225 | 451 def lostChannel(self): |
mjw@2225 | 452 self.deregisterChannel() |
mjw@2225 | 453 self.factory.instanceClosed(self) |
mjw@2225 | 454 |
mjw@2225 | 455 |
mjw@2225 | 456 class SplitController(Controller): |
mjw@2225 | 457 """Abstract class for a device controller attached to a domain. |
mjw@2225 | 458 A SplitController has a BackendContoller. |
mjw@2225 | 459 """ |
mjw@2225 | 460 |
mjw@2225 | 461 def __init__(self, factory, dom, backend): |
mjw@2225 | 462 Controller.__init__(self, factory, dom) |
mjw@2225 | 463 self.backendDomain = None |
mjw@2225 | 464 self.backendController = None |
mjw@2225 | 465 self.setBackendDomain(backend) |
mjw@2225 | 466 |
mjw@2225 | 467 def setBackendDomain(self, dom): |
mjw@2225 | 468 ctrlr = self.factory.getBackendController(dom) |
mjw@2225 | 469 self.backendDomain = ctrlr.dom |
mjw@2225 | 470 self.backendController = ctrlr |
mjw@2225 | 471 |
mjw@2225 | 472 def getBackendDomain(self): |
mjw@2225 | 473 return self.backendDomain |
mjw@2225 | 474 |
mjw@2225 | 475 def getBackendController(self): |
mjw@2225 | 476 return self.backendController |
mjw@2225 | 477 |
mjw@1623 | 478 class Dev: |
mjw@1654 | 479 """Abstract class for a device attached to a device controller. |
mjw@2185 | 480 |
mjw@2185 | 481 @ivar idx: identifier |
mjw@2185 | 482 @type idx: String |
mjw@2185 | 483 @ivar controller: device controller |
mjw@2185 | 484 @type controller: DeviceController |
mjw@2185 | 485 @ivar props: property table |
mjw@2185 | 486 @type props: { String: value } |
mjw@1654 | 487 """ |
mjw@1654 | 488 |
mjw@1975 | 489 def __init__(self, idx, controller): |
mjw@1975 | 490 self.idx = str(idx) |
mjw@1623 | 491 self.controller = controller |
mjw@1623 | 492 self.props = {} |
mjw@1623 | 493 |
mjw@1975 | 494 def getidx(self): |
mjw@1975 | 495 return self.idx |
mjw@1975 | 496 |
mjw@1623 | 497 def setprop(self, k, v): |
mjw@1623 | 498 self.props[k] = v |
mjw@1623 | 499 |
mjw@1623 | 500 def getprop(self, k, v=None): |
mjw@1623 | 501 return self.props.get(k, v) |
mjw@1623 | 502 |
mjw@1623 | 503 def hasprop(self, k): |
mjw@1623 | 504 return k in self.props |
mjw@1623 | 505 |
mjw@1623 | 506 def delprop(self, k): |
mjw@1623 | 507 if k in self.props: |
mjw@1623 | 508 del self.props[k] |
mjw@1623 | 509 |
mjw@1623 | 510 def sxpr(self): |
mjw@2185 | 511 """Get the s-expression for the deivice. |
mjw@2185 | 512 Implement in a subclass. |
mjw@2185 | 513 |
mjw@2185 | 514 @return: sxpr |
mjw@2185 | 515 """ |
mjw@1623 | 516 raise NotImplementedError() |
mjw@1623 | 517 |
mjw@1623 | 518 |