def _parseDriver(self, dic, device): if isinstance(dic, dict): name = dic.pop('name', 'noname') cls = dic.pop('type', None) if not cls: raise TypeNotFoundException("Driver '%s' must have a type." % (name)) host = dic.pop('host', self.chimera["host"]) port = dic.pop('port', self.chimera["port"]) driver = Location(name=name, cls=cls, host=host, port=port, config=dic) else: driver_name = 'noname' driver_cls = dic driver_device = device driver_config = {} if driver_device is not None: driver_config["device"] = driver_device driver = Location(name=driver_name, cls=driver_cls, config=driver_config) return driver
def __setlocation__(self, location): location = Location(location) self.__location__ = location self.setGUID("/%s/%s" % (location.cls, location.name)) return True
def addLocation(self, location, path=[], start=True): """ Add the class pointed by 'location' to the system configuring it using 'config'. Manager will look for the class in 'path' plus sys.path. @param path: The class search path. @type path: list @param start: start the object after initialization. @type start: bool @raises ChimeraObjectException: Internal error on managed (user) object. @raises ClassLoaderException: Class not found. @raises NotValidChimeraObjectException: When a object which doesn't inherites from ChimeraObject is given in location. @raises InvalidLocationException: When the requested location s invalid. @return: retuns a proxy for the object if sucessuful, False otherwise. @rtype: Proxy or bool """ if type(location) != Location: location = Location(location) if not self._belongsToMe(location): # remote object, just add it to resource list. # use a dummy instance to make things easier to Resources Manager getByClass feature. cls = self.classLoader.loadClass(location.cls, path) self.resources.add(location, cls(), None) return True # get the class cls = None cls = self.classLoader.loadClass(location.cls, path) return self.addClass(cls, location.name, location.config, start)
def addLocation(self, location, path=[], start=True): """ Add the class pointed by 'location' to the system configuring it using 'config'. Manager will look for the class in 'path' plus sys.path. @param path: The class search path. @type path: list @param start: start the object after initialization. @type start: bool @raises ChimeraObjectException: Internal error on managed (user) object. @raises ClassLoaderException: Class not found. @raises NotValidChimeraObjectException: When a object which doesn't inherites from ChimeraObject is given in location. @raises InvalidLocationException: When the requested location s invalid. @return: retuns a proxy for the object if sucessuful, False otherwise. @rtype: Proxy or bool """ if type(location) != Location: location = Location(location) # get the class cls = None cls = self.classLoader.loadClass(location.cls, path) return self.addClass(cls, location.name, location.config, start)
def _parseLocation(self, type, dic): name = dic.pop('name', self._getDefaultName(type)) # replace some invalid chars from object name name = name.replace(" ", "_") name = name.replace('"', "_") name = name.replace("'", "_") if type == "site": # keep name dic["name"] = name cls = dic.pop('type', None) if not cls: if type in self._specials or type == "site": cls = type.capitalize() else: raise TypeNotFoundException("%s %s must have a type." % (type, name)) host = dic.pop('host', self.chimera["host"]) port = dic.pop('port', self.chimera["port"]) return Location(name=name, cls=cls, host=host, port=port, config=dic)
def addClass(self, cls, name, config={}, start=True): """ Add the class 'cls' to the system configuring it using 'config'. @param cls: The class to add to the system. @type cls: ChimeraObject @param name: The name of the new class instance. @type name: str @param config: The configuration dictionary for the object. @type config: dict @param start: start the object after initialization. @type start: bool @raises ChimeraObjectException: Internal error on managed (user) object. @raises NotValidChimeraObjectException: When a object which doesn't inherites from ChimeraObject is given in location. @raises InvalidLocationException: When the requested location s invalid. @return: retuns a proxy for the object if sucessuful, False otherwise. @rtype: Proxy or bool """ location = Location(cls=cls.__name__, name=name, config=config) # names must not start with a digit if location.name[0] in "0123456789": raise InvalidLocationException( "Invalid instance name: %s (must start with a letter)" % location) if location in self.resources: raise InvalidLocationException( "Location %s is already in the system. Only one allowed (Tip: change the name!)." % location) # check if it's a valid ChimeraObject if not issubclass(cls, ChimeraObject): raise NotValidChimeraObjectException( "Cannot add the class %s. It doesn't descend from ChimeraObject." % cls.__name__) # run object __init__ and configure using location configuration # it runs on the same thread, so be a good boy # and don't block manager's thread try: obj = cls() except Exception: log.exception("Error in %s __init__." % location) raise ChimeraObjectException("Error in %s __init__." % location) try: for k, v in location.config.items(): obj[k] = v except (OptionConversionException, KeyError), e: log.exception("Error configuring %s." % location) raise ChimeraObjectException("Error configuring %s. (%s)" % (location, e))
def _validLocation(self, item): ret = item if not isinstance(item, Location): ret = Location(item) return ret
def check_location(option, opt_str, value, parser): try: l = Location(value) except InvalidLocationException: raise optparse.OptionValueError("%s isnt't a valid location." % value) eval('parser.values.%s.append ("%s")' % (option.dest, value))
def check_location(option, opt_str, value, parser): try: l = Location(value) except InvalidLocationException: raise optparse.OptionValueError("%s isnt't a valid location." % value) setattr(parser.values, "%s" % option.dest, value)
def _dispatch(self, request, params): # this dispatcher expects methods names like # ClassName.instance_name.method if self._ctrl['debug']: self._ctrl.log.debug('XML Request for %s : %s' % (str(request), str(params))) try: cls, instance, method = request.split(".") except ValueError: if self._ctrl['debug']: self._ctrl.log.debug('ValueError:Invalid Request') raise ValueError("Invalid Request") loc = Location(cls=cls, name=instance) if loc not in self._proxyCache: try: obj = self._ctrl.getManager().getProxy(loc) self._proxyCache[loc] = obj except ObjectNotFoundException: if self._ctrl['debug']: self._ctrl.log.debug( 'ObjectNotFoundException:Object Not Found') raise ValueError("Object Not Found") else: try: obj = self._proxyCache[loc] obj._transferThread() if not obj.ping(): raise Exception() # We need to remake the proxy except: try: obj = self._ctrl.getManager().getProxy(loc) self._proxyCache[loc] = obj except ObjectNotFoundException: if self._ctrl['debug']: self._ctrl.log.debug( 'ObjectNotFoundException:Object Not Found') raise ValueError("Object Not Found") handle = getattr(obj, method) obj._release() try: ret = handle(*params) except AttributeError: if self._ctrl['debug']: self._ctrl.log.debug('AttributeError:Method not found') raise ValueError("Method not found") except Exception, e: if self._ctrl['debug']: print ''.join(getPyroTraceback(e)) self._ctrl.log.debug('Other Error <%s>: %s' % (type(e), str(e))) raise
def test_valid(self): valid = [ "/Class/other?option1=value1,option2=value2", "/Class/other?", "/class/o?option=", "/Class/1??option=1", "/12345Class/o", "host.com.br:1000/Class/name", "host.com.br/Class/name", '200.100.100.100:1000/Class/name', '200.100.100.100/Class/name', Location("/Class/name"), # copy constructor ] for l in valid: loc = Location(l) assert loc, "'%s' is not valid" % l
def test_eq(self): l1 = Location( 'host.com.br:1000/Class/name?option1=value1,option2=value2') l2 = Location( 'othr.com.br:1001/Class/name?option3=value3,option4=value4') # equality tests apply only to class and name config doesn't matter assert hash(l1) == hash(l2) assert l1 == l2 l3 = Location( 'host.com.br:1000/Class/name?option1=value1,option2=value2') l4 = Location( 'host.com.br:1000/Class/othr?option1=value1,option2=value2') # equality tests apply only to class and name config doesn't matter assert l3 != l4
def _setupObjects(self, options): # CLI requested objects instruments = dict([(x.name, x) for x in list(self._parameters.values()) if x.type == ParameterType.INSTRUMENT]) controllers = dict([(x.name, x) for x in list(self._parameters.values()) if x.type == ParameterType.CONTROLLER]) # starts a local Manager (not using sysconfig) or a full sysconfig # backed if needed. self._startSystem(self.options) # create locations for inst in list(instruments.values()) + list(controllers.values()): # use user instrument if given if inst.default != getattr(options, inst.name): try: inst.location = Location(getattr(options, inst.name)) except InvalidLocationException: self.exit( "Invalid location: %s. See --help for more information" % getattr(options, inst.name)) else: # no instrument selected, ask remote Chimera instance for the # newest if self._remoteManager: insts = self._remoteManager.getResourcesByClass(inst.cls) if insts: # get the older inst.location = insts[0] if not inst.location and inst.required: self.exit( "Couldn't find %s configuration. " "Edit %s or see --help for more information" % (inst.name.capitalize(), os.path.abspath(options.config))) for inst in list(instruments.values()) + list(controllers.values()): inst_proxy = None try: inst_proxy = self._remoteManager.getProxy(inst.location) except ObjectNotFoundException: if inst.required == True: self.exit( "Couldn't find %s. (see --help for more information)" % inst.name.capitalize()) # save values in CLI object (which users are supposed to inherites # from). setattr(self, inst.name, inst_proxy)
def _setupObjects(self, options): # CLI requested objects instruments = dict([(x.name, x) for x in self._parameters.values() if x.type == ParameterType.INSTRUMENT]) controllers = dict([(x.name, x) for x in self._parameters.values() if x.type == ParameterType.CONTROLLER]) # we only need to autostart the Manager instance # if we are using going to use a local intrument (in other cases, the local manager started # by the CLI to handle events can handle everthing). needRemoteManager = (not options.noautostart) # starts a local Manager (not using sysconfig) or a full sysconfig backed if needed. self._startSystem(self.options, needRemoteManager) # create locations for inst in instruments.values() + controllers.values(): # use user instrument if given if inst.default != getattr(options, inst.name): try: inst.location = Location(getattr(options, inst.name)) except InvalidLocationException: self.exit( "Invalid location: %s. See --help for more information" % getattr(options, inst.name)) else: # no instrument selected, ask remote Chimera instance for the newest if self._remoteManager: insts = self._remoteManager.getResourcesByClass(inst.cls) if insts: inst.location = insts[-1] if not inst.location and inst.required: self.exit( "Couldn't find %s configuration. " "Edit %s or see --help for more information" % (inst.name.capitalize(), SYSTEM_CONFIG_DEFAULT_FILENAME)) for inst in instruments.values() + controllers.values(): inst_proxy = None try: inst_proxy = self._remoteManager.getProxy(inst.location) except ObjectNotFoundException: if inst.required == True: self.exit( "Couldn't find %s. (see --help for more information)" % inst.name.capitalize()) # save values in CLI object (which users are supposed to inherites from). setattr(self, inst.name, inst_proxy)
def __init__ (self, location = None, host=None, port=None, uri = None): Pyro.core.initClient (banner=0) if not uri: location = Location(location) host = (host or location.host) or MANAGER_DEFAULT_HOST port = (port or location.port) or MANAGER_DEFAULT_PORT uri = Pyro.core.PyroURI(host=host, port=port, objectID="/%s/%s" % (location.cls, location.name)) Pyro.core.DynamicProxy.__init__ (self, uri)
def _parseLocation(self, type, dic): name = dic.pop('name', 'noname') cls = dic.pop('type', None) if not cls: if type in self._specials: cls = type.capitalize() else: raise TypeNotFoundException("%s %s must have a type." % (type, name)) host = dic.pop('host', self.chimera["host"]) port = dic.pop('port', self.chimera["port"]) if 'driver' in dic: device = dic.pop('device', None) driver = self._parseDriver(dic.pop('driver'), device) self.drivers.append(driver) dic['driver'] = str(driver) return Location(name=name, cls=cls, host=host, port=port, config=dic)
def test_create(self): # simple strings l = Location('/Class/name?option1=value1,option2=value2') assert l assert l.host is None assert l.port is None assert l.cls == "Class" assert l.name == "name" assert l.config == dict(option1="value1", option2="value2") # simple strings l = Location( 'host.com.br:1000/Class/name?option1=value1,option2=value2') assert l assert l.host == 'host.com.br' assert l.port == 1000 assert l.cls == "Class" assert l.name == "name" assert l.config == dict(option1="value1", option2="value2") # from dict assert_raises(InvalidLocationException, Location, cls="Class", config=dict(option1="value1", option2="value2")) assert_raises(InvalidLocationException, Location, name="name", config=dict(option1="value1", option2="value2")) assert_raises(InvalidLocationException, Location, config=dict(option1="value1", option2="value2")) assert_raises(InvalidLocationException, Location, cls="Class", name="") assert_raises(InvalidLocationException, Location, cls="", name="name") assert_raises(InvalidLocationException, Location, cls="", name="") assert Location(cls="Class", name="0") # simple version l = Location(cls="Class", name="name", config=dict(option1="value1", option2="value2")) assert l assert l.cls == "Class" assert l.name == "name" assert l.config == dict(option1="value1", option2="value2") assert type(str(l)) is str # host version l = Location(host='host.com.br', port=1000, cls="Class", name="name", config=dict(option1="value1", option2="value2")) assert l assert l.host == 'host.com.br' assert l.port == 1000 assert l.cls == "Class" assert l.name == "name" assert l.config == dict(option1="value1", option2="value2") assert type(str(l)) is str l = Location(host='host.com.br', cls="Class", name="name", config=dict(option1="value1", option2="value2")) assert l assert l.host == 'host.com.br' assert l.port is None assert l.cls == "Class" assert l.name == "name" assert l.config == dict(option1="value1", option2="value2") assert type(str(l)) is str assert_raises(InvalidLocationException, Location, host='host.com.br', port="xyz", cls="Class", name="name", config=dict(option1="value1", option2="value2")) # copy constructor l1 = Location('/Class/name') l2 = Location(l1) assert l1 assert l2 assert l2.cls == l1.cls assert l2.name == l1.name assert l2.config == l1.config assert l2 == l1 assert id(l2) != id(l1)
def getProxy(self, location, name='0', host=None, port=None, lazy=False): """ Get a proxy for the object pointed by location. The given location can contain index instead of names, e.g. '/Object/0' to get objects when you don't know their names. location can also be a class. getProxy will return an instance named 'name' at the given host/port (or on the current manager, if None given). host and port parameters determines which Manager we will lookup for location/instance. If None, look at this Manager. host/port is only used when location is a class, otherwise, host and port are determined by location itself. lazy parameter determines if Manager will try to locate the selected Manager at host/port and ask them for a valid object/instance. If False, Manager just return an proxy for the selected parameters but can't guarantee that the returned Proxy have an active object bounded. For objects managed by this own Manager, lazy is always False. @param location: Object location or class. @type location: Location or class @param name: Instance name. @type name: str @param host: Manager's hostname. @type host: str @param port: Manager's port. @type port: int @param lazy: Manager's laziness (check for already bound objects on host/port Manager) @type lazy: bool @raises NotValidChimeraObjectException: When a object which doesn't inherites from ChimeraObject is given in location. @raises ObjectNotFoundException: When te request object or the Manager was not found. @raises InvalidLocationException: When the requested location s invalid. @return: Proxy for selected object. @rtype: Proxy """ if not location: raise ObjectNotFoundException("Couldn't find an object at the" " given location %s" % location) if not isinstance(location, StringType) and not isinstance( location, Location): if issubclass(location, ChimeraObject): location = Location(cls=location.__name__, name=name, host=host or self.getHostname(), port=port or self.getPort()) else: raise NotValidChimeraObjectException( "Can't get a proxy from non ChimeraObject's descendent object (%s)." % location) else: location = Location(location, host=host or self.getHostname(), port=port or self.getPort()) # who manages this location? if self._belongsToMe(location): ret = self.resources.get(location) if not ret: raise ObjectNotFoundException("Couldn't found an object at the" " given location %s" % location) p = Proxy(uri=ret.uri) if lazy: return p else: p.ping() return p else: if lazy: return Proxy(location) else: # contact other manager try: other = Proxy(location=MANAGER_LOCATION, host=location.host or host, port=location.port or port) except Pyro.errors.URIError, e: raise InvalidLocationException( "Invalid remote location given. '%s' (%s)." % (location, str(e))) if not other.ping(): raise ObjectNotFoundException( "Can't contact %s manager at %s." % (location, other.URI.address)) proxy = other.getProxy(location) if not proxy: raise ObjectNotFoundException( "Couldn't find an object at the" " given location %s" % location) else: return proxy
raise ChimeraObjectException("Error in %s __init__." % location) try: for k, v in location.config.items(): obj[k] = v except (OptionConversionException, KeyError), e: log.exception("Error configuring %s." % location) raise ChimeraObjectException("Error configuring %s. (%s)" % (location, e)) # connect obj.__setlocation__(location) next = len(self.resources.getByClass(location.cls)) uri = self.adapter.connect(obj, index=str( Location(cls=location.cls, name=next))) self.resources.add(location, obj, uri) if start: self.start(location) return Proxy(uri=uri) def remove(self, location): """ Remove the object pointed by 'location' from the system stopping it before if needed. @param location: The object to remove. @type location: Location,str
def _dispatch(self, request, params): # this dispatcher expects methods names like # ClassName.instance_name.method if self._ctrl['debug']: self._ctrl.log.debug('XML Request for %s : %s' % (str(request), str(params))) try: cls, instance, method = request.split(".") except ValueError: if self._ctrl['debug']: self._ctrl.log.debug('ValueError:Invalid Request') raise ValueError("Invalid Request") loc = Location(cls=cls, name=instance) if loc not in self._proxyCache: try: obj = self._ctrl.getManager().getProxy(loc) self._proxyCache[loc] = obj except ObjectNotFoundException: if self._ctrl['debug']: self._ctrl.log.debug( 'ObjectNotFoundException:Object Not Found') raise ValueError("Object Not Found") else: try: obj = self._proxyCache[loc] obj._transferThread() if not obj.ping(): raise Exception() # We need to remake the proxy except: try: obj = self._ctrl.getManager().getProxy(loc) self._proxyCache[loc] = obj except ObjectNotFoundException: if self._ctrl['debug']: self._ctrl.log.debug( 'ObjectNotFoundException:Object Not Found') raise ValueError("Object Not Found") handle = getattr(obj, method) obj._release() try: ret = handle(*params) except AttributeError: if self._ctrl['debug']: self._ctrl.log.debug('AttributeError:Method not found') raise ValueError("Method not found") except Exception as e: if self._ctrl['debug']: print(''.join(getPyroTraceback(e))) self._ctrl.log.debug('Other Error <%s>: %s' % (type(e), str(e))) raise # do some conversions to help Java XML Server if isinstance(ret, (tuple, list)): newret = [] for arg in ret: if isinstance(arg, (Position, Coord)): newret.append(str(arg)) elif isinstance(arg, Location): if "hash" in arg.config: newret.append(str(arg.config["hash"])) else: newret.append(str(ret)) elif isinstance(arg, type(None)): newret.append(True) else: newret.append(arg) if self._ctrl['debug']: self._ctrl.log.debug('Returning: %s' % str(newret)) return newret else: if isinstance(ret, (Position, Coord)): if self._ctrl['debug']: self._ctrl.log.debug('Returning: %s' % str(ret)) return str(ret) elif isinstance(ret, Location): if "hash" in ret.config: if self._ctrl['debug']: self._ctrl.log.debug('Returning: %s' % str(ret.config["hash"])) return str(ret.config["hash"]) else: if self._ctrl['debug']: self._ctrl.log.debug('Returning: %s' % str(ret)) return str(ret) elif isinstance(ret, type(None)): if self._ctrl['debug']: self._ctrl.log.debug('Returning: %s' % str(True)) return True else: if self._ctrl['debug']: self._ctrl.log.debug('Returning: %s' % str(ret)) return ret
class Manager(RemoteObject): """ This is the main class of Chimera. Use this class to get Proxies, add objects to the system, and so on. This class handles objects life-cycle as described in ILifecycle. @group Add/Remove: add*, remove @group Start/Stop: start, stop @group Proxy: getProxy @group Shutdown: wait, shutdown """ def __init__(self, host=None, port=None, local=False): RemoteObject.__init__(self) log.info("Starting manager.") self.resources = ResourcesManager() self.classLoader = ClassLoader() # identity self.setGUID(MANAGER_LOCATION) # shutdown event self.died = threading.Event() if not local: try: ManagerLocator.locate() raise ChimeraException("Chimera is already running" " on this system. Use chimera-admin" " to manage it.") except ManagerNotFoundException: # ok, we are alone. pass # our daemon server self.adapter = ManagerAdapter(self, host, port) self.adapterThread = threading.Thread(target=self.adapter.requestLoop) self.adapterThread.setDaemon(True) self.adapterThread.start() # finder beacon if not local: self.beacon = ManagerBeacon(self) self.beaconThread = threading.Thread(target=self.beacon.run) self.beaconThread.setDaemon(True) self.beaconThread.start() else: self.beacon = None # register ourself self.resources.add(MANAGER_LOCATION, self, getManagerURI(self.getHostname(), self.getPort())) # signals signal.signal(signal.SIGTERM, self._sighandler) signal.signal(signal.SIGINT, self._sighandler) atexit.register(self._sighandler) # private def __repr__(self): if hasattr(self, 'adapter') and self.adapter: return "<Manager for %s:%d at %s>" % ( self.adapter.hostname, self.adapter.port, hex(id(self))) else: return "<Manager at %s>" % hex(id(self)) def _sighandler(self, sig=None, frame=None): self.shutdown() # adapter host/port def getHostname(self): if self.adapter: return self.adapter.hostname else: return None def getPort(self): if self.adapter: return self.adapter.port else: return None # reflection (console) def getResources(self): """ Returns a list with the Location of all the available resources """ return self.resources.keys() def getResourcesByClass(self, cls): resources = self.getResources() toRet = [] for r in resources: if r.cls == cls: toRet.append(r) return toRet # helpers def getDaemon(self): return self.adapter def getProxy(self, location, name='0', host=None, port=None, lazy=False): """ Get a proxy for the object pointed by location. The given location can contain index instead of names, e.g. '/Object/0' to get objects when you don't know their names. location can also be a class. getProxy will return an instance named 'name' at the given host/port (or on the current manager, if None given). host and port parameters determines which Manager we will lookup for location/instance. If None, look at this Manager. host/port is only used when location is a class, otherwise, host and port are determined by location itself. lazy parameter determines if Manager will try to locate the selected Manager at host/port and ask them for a valid object/instance. If False, Manager just return an proxy for the selected parameters but can't guarantee that the returned Proxy have an active object bounded. For objects managed by this own Manager, lazy is always False. @param location: Object location or class. @type location: Location or class @param name: Instance name. @type name: str @param host: Manager's hostname. @type host: str @param port: Manager's port. @type port: int @param lazy: Manager's laziness (check for already bound objects on host/port Manager) @type lazy: bool @raises NotValidChimeraObjectException: When a object which doesn't inherites from ChimeraObject is given in location. @raises ObjectNotFoundException: When te request object or the Manager was not found. @raises InvalidLocationException: When the requested location s invalid. @return: Proxy for selected object. @rtype: Proxy """ if not location: raise ObjectNotFoundException("Couldn't find an object at the" " given location %s" % location) if not isinstance(location, StringType) and not isinstance( location, Location): if issubclass(location, ChimeraObject): location = Location(cls=location.__name__, name=name, host=host or self.getHostname(), port=port or self.getPort()) else: raise NotValidChimeraObjectException( "Can't get a proxy from non ChimeraObject's descendent object (%s)." % location) else: location = Location(location, host=host or self.getHostname(), port=port or self.getPort()) # who manages this location? if self._belongsToMe(location): ret = self.resources.get(location) if not ret: raise ObjectNotFoundException("Couldn't found an object at the" " given location %s" % location) return Proxy(uri=ret.uri) else: if lazy: return Proxy(location) else: # contact other manager other = Proxy(location=MANAGER_LOCATION, host=location.host or host, port=location.port or port) if not other.ping(): raise ObjectNotFoundException( "Can't contact %s manager at %s." % (location, other.URI.address)) proxy = other.getProxy(location) if not proxy: raise ObjectNotFoundException( "Couldn't found an object at the" " given location %s" % location) else: return proxy def _belongsToMe(self, location): meHost = self.getHostname() meName = socket.gethostbyname(meHost) mePort = self.getPort() return (location.host == None or location.host in (meHost, meName)) and \ (location.port == None or location.port == self.getPort()) # shutdown management def shutdown(self): """ Ask the system to shutdown. Closing all sockets and stopping all threads. @return: Nothing @rtype: None """ # die, but only if we are alive ;) if not self.died.isSet(): log.info("Shuting down manager.") # stop objects # damm 2.4, on 2.5 try/except/finally works try: try: elderly_first = sorted( list(self.resources.values()), cmp=lambda x, y: cmp(x.created, y.created), reverse=True) for resource in elderly_first: # except Manager if resource.location == MANAGER_LOCATION: continue # stop object self.stop(resource.location) except ChimeraException: pass finally: # kill our adapter self.adapter.shutdown(disconnect=True) if self.beacon: self.beacon.shutdown() self.beaconThread.join() # die! self.died.set() log.info("Manager finished.") def wait(self): """ Ask the system to wait until anyone calls L{shutdown}. If nobody calls L{shutdown}, you can stop the system using Ctrl+C. @return: Nothing @rtype: None """ try: while not self.died.isSet(): time.sleep(1) except IOError: # On Windows, Ctrl+C on a sleep call raise IOError 'cause # of the interrupted syscall pass # objects lifecycle def addLocation(self, location, path=[], start=True): """ Add the class pointed by 'location' to the system configuring it using 'config'. Manager will look for the class in 'path' plus sys.path. @param path: The class search path. @type path: list @param start: start the object after initialization. @type start: bool @raises ChimeraObjectException: Internal error on managed (user) object. @raises ClassLoaderException: Class not found. @raises NotValidChimeraObjectException: When a object which doesn't inherites from ChimeraObject is given in location. @raises InvalidLocationException: When the requested location s invalid. @return: retuns a proxy for the object if sucessuful, False otherwise. @rtype: Proxy or bool """ if type(location) != Location: location = Location(location) # get the class cls = None cls = self.classLoader.loadClass(location.cls, path) return self.addClass(cls, location.name, location.config, start) def addClass(self, cls, name, config={}, start=True): """ Add the class 'cls' to the system configuring it using 'config'. @param cls: The class to add to the system. @type cls: ChimeraObject @param name: The name of the new class instance. @type name: str @param config: The configuration dictionary for the object. @type config: dict @param start: start the object after initialization. @type start: bool @raises ChimeraObjectException: Internal error on managed (user) object. @raises NotValidChimeraObjectException: When a object which doesn't inherites from ChimeraObject is given in location. @raises InvalidLocationException: When the requested location s invalid. @return: retuns a proxy for the object if sucessuful, False otherwise. @rtype: Proxy or bool """ location = Location(cls=cls.__name__, name=name, config=config) # names must not start with a digit if location.name[0] in "0123456789": raise InvalidLocationException( "Invalid instance name: %s (must start with a letter)" % location) if location in self.resources: raise InvalidLocationException( "Location %s is already in the system. Only one allowed (Tip. change the name!)." % location) # check if it's a valid ChimeraObject if not issubclass(cls, ChimeraObject): raise NotValidChimeraObjectException( "Cannot add the class %s. It doesn't descend from ChimeraObject." % cls.__name__) # run object __init__ and configure using location configuration # it runs on the same thread, so be a good boy # and don't block manager's thread try: obj = cls() except Exception: log.exception("Error in %s __init__." % location) raise ChimeraObjectException("Error in %s __init__." % location) try: for k, v in location.config.items(): obj[k] = v except (OptionConversionException, KeyError), e: log.exception("Error configuring %s." % location) raise ChimeraObjectException("Error configuring %s. (%s)" % (location, e)) # connect obj.__setlocation__(location) next = len(self.resources.getByClass(location.cls)) uri = self.adapter.connect(obj, index=str( Location(cls=location.cls, name=next))) self.resources.add(location, obj, uri) if start: self.start(location) return Proxy(uri=uri)