Esempio n. 1
0
def monitorEngine(address, port, dbPassword, listener=None):
    if not listener:
        listener = _StandardOutListener()

    s = Session(address, port=port, service="Monitor")
    s.authorize("Cloud", dbPassword)

    monitor = SessionMonitor(s, listener=listener)
    monitor.start()

    s.doConnect()

    return EngineMonitor(monitor, s)
Esempio n. 2
0
def monitorDomainStats(broker, user, password, listener=None):
    if not listener:
        listener = _StandardOutListener()

    s = Session(broker, service="HostStats")
    s.authorize(user, password)

    s.doConnect()
    checkForError(s.recv())

    monitor = SessionMonitor(s, listener=listener)
    monitor.start()

    return monitor
Esempio n. 3
0
    def __init__(self, broker_addr, domain_user, domain_pwd, listener=None):
        """
        @type broker_addr str
        @type domain_user str
        @type domain_pwd str
        @type listener
        """
        if not domain_pwd:
            raise Exception("A password is required to join a domain")

        self.__session = Session(broker_addr, service="Monitor")
        self.__session.authorize(domain_user, domain_pwd)

        self.__user = domain_user
        self.__password = domain_pwd
        self.__listener = listener
        self.__peers = dict()
        """ @type : dict[str, Peer] """
        self.__databases = dict()
        """ @type : dict[str, Database] """

        self.__monitor = SessionMonitor(self.__session, self)
        
        # These will be set in handle status after joining the domain 
        self.__domain_name = None
        """ @type : str """
        self.__entry_peer = None
        """ @type : Peer """

        try:
            self.__session.doConnect()
            self.__handle_status(self.__session.recv())
        except Exception:
            self.__monitor.close()
            raise

        self.__monitor.start()
Esempio n. 4
0
    def __init__(self, broker_addr, domain_user, domain_pwd, listener=None):
        """
        @type broker_addr str
        @type domain_user str
        @type domain_pwd str
        @type listener
        """
        if not domain_pwd:
            raise Exception("A password is required to join a domain")

        self.__session = Session(broker_addr, service="Monitor")
        self.__session.authorize(domain_user, domain_pwd)

        self.__user = domain_user
        self.__password = domain_pwd
        self.__listener = listener
        self.__peers = dict()
        """ @type : dict[str, Peer] """
        self.__peers_by_addr = dict()
        """ @type : dict[str, Peer] """
        self.__databases = dict()
        """ @type : dict[str, Database] """

        self.__monitor = SessionMonitor(self.__session, self)

        # These will be set in handle status after joining the domain
        self.__domain_name = None
        """ @type : str """
        self.__entry_peer = None
        """ @type : Peer """

        try:
            self.__session.doConnect()
            self.__handle_status(self.__session.recv())
        except Exception:
            self.__monitor.close()
            raise

        self.__monitor.start()
Esempio n. 5
0
    def __init__(self, brokerAddr, domainUser, domainPwd, listener=None):
        if not domainPwd:
            raise Exception("A password is required to join a domain")

        self.__session = Session(brokerAddr, service="Monitor")
        self.__session.authorize(domainUser, domainPwd)

        self.__user = domainUser
        self.__password = domainPwd
        self.__listener = listener
        self.__peers = dict()
        self.__databases = dict()

        self.__monitor = SessionMonitor(self.__session, self)

        try:
            self.__session.doConnect()
            self.__handleStatus(self.__session.recv())
        except Exception:
            self.__monitor.close()
            raise

        self.__monitor.start()
Esempio n. 6
0
class Domain(BaseListener):
    """Represents the NuoDB domain.
    
    The domain is the top level NuoDB management object. The domain object 
    provides access to the peers and databases that are contained within.
    """

    def __init__(self, broker_addr, domain_user, domain_pwd, listener=None):
        """
        @type broker_addr str
        @type domain_user str
        @type domain_pwd str
        @type listener
        """
        if not domain_pwd:
            raise Exception("A password is required to join a domain")

        self.__session = Session(broker_addr, service="Monitor")
        self.__session.authorize(domain_user, domain_pwd)

        self.__user = domain_user
        self.__password = domain_pwd
        self.__listener = listener
        self.__peers = dict()
        """ @type : dict[str, Peer] """
        self.__databases = dict()
        """ @type : dict[str, Database] """

        self.__monitor = SessionMonitor(self.__session, self)
        
        # These will be set in handle status after joining the domain 
        self.__domain_name = None
        """ @type : str """
        self.__entry_peer = None
        """ @type : Peer """

        try:
            self.__session.doConnect()
            self.__handle_status(self.__session.recv())
        except Exception:
            self.__monitor.close()
            raise

        self.__monitor.start()

    def __str__(self):
        return self.domain_name + " [Entered through: " + self.entry_peer.connect_str + "]"

    def disconnect(self):
        """Disconnect from the domain."""
        self.__monitor.close()
        
    def _send_domain_message(self, service, attributes=None, text=None, children=None):
        session = Session(self.__entry_peer.address, port=self.__entry_peer.port, service=service)
        session.authorize(self.__user, self.__password)
        return session.doRequest(attributes, text, children)

    @property
    def user(self):
        """Return the domain user."""
        return self.__user

    @property
    def password(self):
        """Return the domain password."""
        return self.__password
    
    @property
    def domain_name(self):
        """Return the domain name."""
        return self.__domain_name

    def find_peer(self, address):
        """
        Find a peer by address
        @type: address str
        @rtype: Peer
        """

    def get_peer(self, agent_id):
        """
        Return a peer for a given agent_id.
        @type agent_id str
        @rtype: Peer
        """
        return self.__peers.get(agent_id)

    @property
    def peers(self):
        """
        Return a list of all peers in the domain.
        @rtype: list[Peer]
        """
        return self.__peers.values()

    @property
    def entry_peer(self):
        """
        Return the peer that was used to enter the domain.
        @rtype: Peer
        """
        return self.__entry_peer

    def get_database(self, name):
        """
        Return a database by name
        @type name str
        @rtype: Database
        """
        return self.__databases.get(name)

    @property
    def databases(self):
        """
        Return a list of databases in the domain
        @rtype: list[Database]
        """
        return self.__databases.values()

    def create_template(self, template_name, summary, requirements):
        """Create template by name"""
        response = self._send_domain_message(**Template.build_create_request(template_name, summary, requirements))
        return ElementTree.fromstring(response).tag == Template.success_message

    def update_template(self, template_name, summary, requirements):
        """Update template by name"""
        response = self._send_domain_message(**Template.build_update_request(template_name, summary, requirements))
        return ElementTree.fromstring(response).tag == Template.success_message

    def delete_template(self, template_name):
        """Delete template by name"""
        response = self._send_domain_message(**Template.build_delete_request(template_name))
        return ElementTree.fromstring(response).tag == Template.success_message

    def get_template(self, template_name):
        """Return a template by name"""
        response = self._send_domain_message(**Template.build_get_request(template_name))
        return Template.from_message(response)

    @property
    def templates(self):
        """Return a list of templates in the domain"""
        response = self._send_domain_message(**Template.build_list_request())
        return Template.from_list_message(response)

    def create_description(self, name, template_name, variables, dba_user, dba_password):
        response = self._send_domain_message(**Description.build_create_request(name, template_name, variables, dba_user, dba_password))
        return ElementTree.fromstring(response).tag == Description.success_message

    def update_description(self, name, template_name, variables):
        response = self._send_domain_message(**Description.build_update_request(name, template_name, variables))
        return ElementTree.fromstring(response).tag == Description.success_message

    def delete_description(self, name):
        response = self._send_domain_message(**Description.build_delete_request(name))
        return ElementTree.fromstring(response).tag == Description.success_message

    def get_description(self, name):
        response = self._send_domain_message(**Description.build_get_request(name))
        return Description.from_message(response)

    def start_description(self, name):
        response = self._send_domain_message(**Description.build_start_request(name))
        return ElementTree.fromstring(response).tag == Description.success_message

    def stop_description(self, name):
        response = self._send_domain_message(**Description.build_stop_request(name))
        return ElementTree.fromstring(response).tag == Description.success_message

    @property
    def descriptions(self):
        response = self._send_domain_message(**Description.build_list_request())
        return Description.from_list_message(response)

    def shutdown(self, graceful=True):
        """Shutdown all databases in the domain.
        
        graceful -- (default True) means that the database will first
        be quiesced and then shutdown.
        """
        for database in self.__databases.itervalues():
            database.shutdown(graceful)

    def message_received(self, root):
        """Process a management message from the broker.
        
        Override from session.BaseListener.
        """
        if root.tag == "Event":
            event_type = root.get("Type")
            if event_type == "NewBroker":
                self.__peer_joined(Peer.from_message(self, root.find("Broker")))
            elif event_type == "BrokerExit":
                self.__peer_left(Peer.from_message(self, root.find("Broker")))
            elif event_type == "StatusChanged":
                status = root.get("Status")

                process_element = root.find("Process")
                db = self.__databases[process_element.get("Database")]
                process = Process.from_message(db, process_element)

                self.__process_status_changed(process, status)
            elif event_type == "ProcessFailed":
                peer = Peer.from_message(self, root.find("Broker"))
                peer = self.get_peer(peer.id)

                reason = root.get("Reason")
                start_id = root.get("StartId")

                self.__process_failed(peer, start_id, reason)
            elif event_type == "NewProcess" or event_type == "ProcessExit":
                process_element = root.find("Process")
                db_name = process_element.get("Database")

                if db_name not in self.__databases:
                    self.__databases[db_name] = Database(self, db_name)
                    if self.__listener:
                        try:
                            self.__listener.database_joined(self.__databases[db_name])
                        except AttributeError:
                            pass
                            

                if event_type == "NewProcess":
                    start_id = process_element.get("StartId")
                    self.__process_joined(Process.from_message(self.__databases[db_name],
                                                       process_element), start_id)
                else:
                    self.__process_left(Process.from_message(self.__databases[db_name],
                                                     process_element))

    def closed(self):
        """Called when the session is closed.
        
        Override from session.BaseListener.
        """
        if self.__listener:
            try:
                self.__listener.closed()
            except AttributeError:
                pass

    def __handle_status(self, message):
        """Handle initial domain status on domain connection.
        
        Note that this is ONLY for processing the initial status message. All
        further update messages are processed by message_received()."""
        root = ElementTree.fromstring(message)
        if root.tag != "Status":
            raise Exception("Expected status message; got " + root.tag)

        self.__domain_name = root.get("Domain")

        self.__entry_peer = Peer(self, self.__session.address, root.get("AgentId"),
                                (root.get("Role") == "Broker"), self.__session.port,
                                root.get("Hostname"), root.get("Version"))
        self.__peer_joined(self.__entry_peer)

        for child in list(root):
            if child.tag == "Broker":
                self.__peer_joined(Peer.from_message(self, child))

        for child in list(root):
            if child.tag == "Database":
                name = child.get("Name")
                if self.__listener:
                    try:
                        self.__listener.database_joined(self.__databases[name])
                    except AttributeError:
                        pass

                for process_element in list(child):
                    if process_element.tag == "Process":
                        if name not in self.__databases:
                            self.__databases[name] = Database(self, name)
                        self.__process_joined(Process.from_message(self.__databases[name], process_element), None)

    def __peer_joined(self, peer):
        """Called when a peer joins the domain."""
        self.__peers[peer.id] = peer
        if self.__listener:
            try:
                self.__listener.peer_joined(peer)
            except AttributeError:
                pass

    def __peer_left(self, peer):
        """Called when a peer leaves the domain."""
        del self.__peers[peer.id]
        if self.__listener:
            try:
                self.__listener.peer_left(peer)
            except AttributeError:
                pass

    def __process_joined(self, process, start_id):
        """Called when a process joins the domain."""
        process.database._add_process(process)
        process.peer._notify_start_id(start_id, process)
        if self.__listener:
            try:
                self.__listener.process_joined(process)
            except AttributeError:
                pass
    
    def __process_left(self, process):
        """Called when a process leaves the domain."""
        database = process.database
        database._remove_process(process)
        process.peer._remove_process(process)
        if self.__listener:
            try:
                self.__listener.process_left(process)
            except AttributeError:
                pass

        if len(database.processes) == 0:
            del self.__databases[database.name]
            if self.__listener:
                try:
                    self.__listener.database_left(database)
                except AttributeError:
                    pass

    def __process_failed(self, peer, start_id, reason):
        """Called when a process in the domain fails."""
        peer._notify_start_id(start_id, reason)
        if self.__listener:
            try:
                self.__listener.process_failed(peer, reason)
            except AttributeError:
                pass

    def __process_status_changed(self, process, status):
        """Called when a process in the domain changes status."""
        process._set_status(status)
        if self.__listener:
            try:
                self.__listener.process_status_changed(process, status)
            except AttributeError:
                pass


    def _send_management_message(self, message, peer, process):
        """Send a management message.
        
        Note that this is an initial verison only to support the shutdown 
        routine that doesn't need to watch for return messages ... right now 
        this module is only supporting the tests, which don't need the other 
        management routines at this point, so we'll flesh this out (as in the 
        Java implementation) in the second round when other utilites get 
        updated as well
        """
        root = ElementTree.fromstring("<ManagementRequest AgentId=\"%s\" ProcessId=\"%i\"/>" % (peer.id, process.pid))
        root.append(message)

        self.__session.send(ElementTree.tostring(root))
Esempio n. 7
0
class Domain(BaseListener):
    """Represents the NuoDB domain.
    
    The domain is the top level NuoDB management object. The domain object 
    provides access to the peers and databases that are contained within.
    """

    def __init__(self, broker_addr, domain_user, domain_pwd, listener=None):
        """
        @type broker_addr str
        @type domain_user str
        @type domain_pwd str
        @type listener
        """
        if not domain_pwd:
            raise Exception("A password is required to join a domain")

        self.__session = Session(broker_addr, service="Monitor")
        self.__session.authorize(domain_user, domain_pwd)

        self.__user = domain_user
        self.__password = domain_pwd
        self.__listener = listener
        self.__peers = dict()
        """ @type : dict[str, Peer] """
        self.__databases = dict()
        """ @type : dict[str, Database] """

        self.__monitor = SessionMonitor(self.__session, self)
        
        # These will be set in handle status after joining the domain 
        self.__domain_name = None
        """ @type : str """
        self.__entry_peer = None
        """ @type : Peer """

        try:
            self.__session.doConnect()
            self.__handle_status(self.__session.recv())
        except Exception:
            self.__monitor.close()
            raise

        self.__monitor.start()

    def __str__(self):
        return self.domain_name + " [Entered through: " + self.entry_peer.connect_str + "]"

    def disconnect(self):
        """Disconnect from the domain."""
        self.__monitor.close()
        
    def _send_domain_message(self, service, attributes=None, text=None, children=None):
        session = Session(self.__entry_peer.address, port=self.__entry_peer.port, service=service)
        session.authorize(self.__user, self.__password)
        return session.doRequest(attributes, text, children)

    @property
    def user(self):
        """Return the domain user."""
        return self.__user

    @property
    def password(self):
        """Return the domain password."""
        return self.__password
    
    @property
    def domain_name(self):
        """Return the domain name."""
        return self.__domain_name

    def find_peer(self, address):
        """
        Find a peer by address
        @type: address str
        @rtype: Peer
        """

    def get_peer(self, agent_id):
        """
        Return a peer for a given agent_id.
        @type agent_id str
        @rtype: Peer
        """
        return self.__peers.get(agent_id)

    @property
    def peers(self):
        """
        Return a list of all peers in the domain.
        @rtype: list[Peer]
        """
        return self.__peers.values()

    @property
    def entry_peer(self):
        """
        Return the peer that was used to enter the domain.
        @rtype: Peer
        """
        return self.__entry_peer

    def get_database(self, name):
        """
        Return a database by name
        @type name str
        @rtype: Database
        """
        return self.__databases.get(name)

    @property
    def databases(self):
        """
        Return a list of databases in the domain
        @rtype: list[Database]
        """
        return self.__databases.values()

    def create_template(self, template_name, summary, requirements):
        """Create template by name"""
        response = self._send_domain_message(**Template.build_create_request(template_name, summary, requirements))
        return ElementTree.fromstring(response).tag == Template.success_message

    def update_template(self, template_name, summary, requirements):
        """Update template by name"""
        response = self._send_domain_message(**Template.build_update_request(template_name, summary, requirements))
        return ElementTree.fromstring(response).tag == Template.success_message

    def delete_template(self, template_name):
        """Delete template by name"""
        response = self._send_domain_message(**Template.build_delete_request(template_name))
        return ElementTree.fromstring(response).tag == Template.success_message

    def get_template(self, template_name):
        """Return a template by name"""
        response = self._send_domain_message(**Template.build_get_request(template_name))
        return Template.from_message(response)

    @property
    def templates(self):
        """Return a list of templates in the domain"""
        response = self._send_domain_message(**Template.build_list_request())
        return Template.from_list_message(response)

    def create_description(self, name, template_name, variables, dba_user, dba_password):
        response = self._send_domain_message(**Description.build_create_request(name, template_name, variables, dba_user, dba_password))
        return ElementTree.fromstring(response).tag == Description.success_message

    def update_description(self, name, template_name, variables):
        response = self._send_domain_message(**Description.build_update_request(name, template_name, variables))
        return ElementTree.fromstring(response).tag == Description.success_message

    def delete_description(self, name):
        response = self._send_domain_message(**Description.build_delete_request(name))
        return ElementTree.fromstring(response).tag == Description.success_message

    def get_description(self, name):
        response = self._send_domain_message(**Description.build_get_request(name))
        return Description.from_message(response)

    def start_description(self, name):
        response = self._send_domain_message(**Description.build_start_request(name))
        return ElementTree.fromstring(response).tag == Description.success_message

    def stop_description(self, name):
        response = self._send_domain_message(**Description.build_stop_request(name))
        return ElementTree.fromstring(response).tag == Description.success_message

    @property
    def descriptions(self):
        response = self._send_domain_message(**Description.build_list_request())
        return Description.from_list_message(response)

    def shutdown(self, graceful=True):
        """Shutdown all databases in the domain.
        
        graceful -- (default True) means that the database will first
        be quiesced and then shutdown.
        """
        for database in self.__databases.itervalues():
            database.shutdown(graceful)

    def message_received(self, root):
        """Process a management message from the broker.
        
        Override from session.BaseListener.
        """
        if root.tag == "Event":
            event_type = root.get("Type")
            if event_type == "NewBroker":
                self.__peer_joined(Peer.from_message(self, root.find("Broker")))
            elif event_type == "BrokerExit":
                self.__peer_left(Peer.from_message(self, root.find("Broker")))
            elif event_type == "StatusChanged":
                status = root.get("Status")

                process_element = root.find("Process")
                db = self.__databases[process_element.get("Database")]
                process = Process.from_message(db, process_element)

                self.__process_status_changed(process, status)
            elif event_type == "ProcessFailed":
                peer = Peer.from_message(self, root.find("Broker"))
                peer = self.get_peer(peer.id)

                reason = root.get("Reason")
                start_id = root.get("StartId")

                self.__process_failed(peer, start_id, reason)
            elif event_type == "NewProcess" or event_type == "ProcessExit":
                process_element = root.find("Process")
                db_name = process_element.get("Database")

                if db_name not in self.__databases:
                    self.__databases[db_name] = Database(self, db_name)
                    if self.__listener:
                        try:
                            self.__listener.database_joined(self.__databases[db_name])
                        except AttributeError:
                            pass
                            

                if event_type == "NewProcess":
                    start_id = process_element.get("StartId")
                    self.__process_joined(Process.from_message(self.__databases[db_name],
                                                       process_element), start_id)
                else:
                    self.__process_left(Process.from_message(self.__databases[db_name],
                                                     process_element))

    def closed(self):
        """Called when the session is closed.
        
        Override from session.BaseListener.
        """
        if self.__listener:
            try:
                self.__listener.closed()
            except AttributeError:
                pass

    def __handle_status(self, message):
        """Handle initial domain status on domain connection.
        
        Note that this is ONLY for processing the initial status message. All
        further update messages are processed by message_received()."""
        root = ElementTree.fromstring(message)
        if root.tag != "Status":
            raise Exception("Expected status message; got " + root.tag)

        self.__domain_name = root.get("Domain")

        self.__entry_peer = Peer(self, self.__session.address, root.get("AgentId"),
                                (root.get("Role") == "Broker"), self.__session.port,
                                root.get("Hostname"), root.get("Version"))
        self.__peer_joined(self.__entry_peer)

        for child in list(root):
            if child.tag == "Broker":
                self.__peer_joined(Peer.from_message(self, child))

        for child in list(root):
            if child.tag == "Database":
                name = child.get("Name")
                if self.__listener:
                    try:
                        self.__listener.database_joined(self.__databases[name])
                    except AttributeError:
                        pass

                for process_element in list(child):
                    if process_element.tag == "Process":
                        if name not in self.__databases:
                            self.__databases[name] = Database(self, name)
                        self.__process_joined(Process.from_message(self.__databases[name], process_element), None)

    def __peer_joined(self, peer):
        """Called when a peer joins the domain."""
        self.__peers[peer.id] = peer
        if self.__listener:
            try:
                self.__listener.peer_joined(peer)
            except AttributeError:
                pass

    def __peer_left(self, peer):
        """Called when a peer leaves the domain."""
        del self.__peers[peer.id]
        if self.__listener:
            try:
                self.__listener.peer_left(peer)
            except AttributeError:
                pass

    def __process_joined(self, process, start_id):
        """Called when a process joins the domain."""
        process.database._add_process(process)
        process.peer._notify_start_id(start_id, process)
        if self.__listener:
            try:
                self.__listener.process_joined(process)
            except AttributeError:
                pass
    
    def __process_left(self, process):
        """Called when a process leaves the domain."""
        database = process.database
        database._remove_process(process)
        process.peer._remove_process(process)
        if self.__listener:
            try:
                self.__listener.process_left(process)
            except AttributeError:
                pass

        if len(database.processes) == 0:
            del self.__databases[database.name]
            if self.__listener:
                try:
                    self.__listener.database_left(database)
                except AttributeError:
                    pass

    def __process_failed(self, peer, start_id, reason):
        """Called when a process in the domain fails."""
        peer._notify_start_id(start_id, reason)
        if self.__listener:
            try:
                self.__listener.process_failed(peer, reason)
            except AttributeError:
                pass

    def __process_status_changed(self, process, status):
        """Called when a process in the domain changes status."""
        process._set_status(status)
        if self.__listener:
            try:
                self.__listener.process_status_changed(process, status)
            except AttributeError:
                pass


    def _send_management_message(self, message, peer, process):
        """Send a management message.
        
        Note that this is an initial verison only to support the shutdown 
        routine that doesn't need to watch for return messages ... right now 
        this module is only supporting the tests, which don't need the other 
        management routines at this point, so we'll flesh this out (as in the 
        Java implementation) in the second round when other utilites get 
        updated as well
        """
        root = ElementTree.fromstring("<ManagementRequest AgentId=\"%s\" ProcessId=\"%i\"/>" % (peer.id, process.pid))
        root.append(message)

        self.__session.send(ElementTree.tostring(root))
Esempio n. 8
0
class Domain(BaseListener):
    def __init__(self, brokerAddr, domainUser, domainPwd, listener=None):
        if not domainPwd:
            raise Exception("A password is required to join a domain")

        self.__session = Session(brokerAddr, service="Monitor")
        self.__session.authorize(domainUser, domainPwd)

        self.__user = domainUser
        self.__password = domainPwd
        self.__listener = listener
        self.__peers = dict()
        self.__databases = dict()

        self.__monitor = SessionMonitor(self.__session, self)

        try:
            self.__session.doConnect()
            self.__handleStatus(self.__session.recv())
        except Exception:
            self.__monitor.close()
            raise

        self.__monitor.start()

    def __str__(self):
        return self.getDomainName() + " [Entered through: " + self.getEntryPeer().getConnectStr() + "]"

    def disconnect(self):
        self.__monitor.close()

    def getUser(self):
        return self.__user

    def getPassword(self):
        return self.__password

    def getDomainName(self):
        return self.__domainName

    def getPeer(self, agentId):
        return self.__peers.get(agentId)

    def getPeers(self):
        return self.__peers.itervalues()

    def getEntryPeer(self):
        return self.__entryPeer

    def getDatabase(self, name):
        return self.__databases.get(name)

    def getDatabases(self):
        return self.__databases.itervalues()

    def getDatabaseCount(self):
        return len(self.__databases)

    def shutdown(self, graceful=True):
        for (dbName, db) in self.__databases.items():
            db.shutdown(graceful)

    def messageReceived(self, root):
        if root.tag == "Event":
            eventType = root.get("Type")
            if eventType == "NewBroker":
                self.__peerJoined(Peer.fromMessage(self, root.find("Broker")))
            elif eventType == "BrokerExit":
                self.__peerLeft(Peer.fromMessage(self, root.find("Broker")))
            elif eventType == "StatusChanged":
                status = root.get("Status")

                processElement = root.find("Process")
                db = self.__databases[processElement.get("Database")]
                process = Process.fromMessage(db, processElement)

                self.__processStatusChanged(process, status)
            elif eventType == "ProcessFailed":
                peer = Peer.fromMessage(self, root.find("Broker"))
                peer = self.getPeer(peer.getId())

                reason = root.get("Reason")
                startId = root.get("StartId")

                self.__processFailed(peer, startId, reason)
            elif eventType == "NewProcess" or eventType == "ProcessExit":
                processElement = root.find("Process")
                dbName = processElement.get("Database")

                if dbName not in self.__databases:
                    self.__databases[dbName] = Database(self, dbName)
                    if self.__listener:
                        try:
                            self.__listener.databaseJoined(self.__databases[dbName])
                        except:
                            pass

                if eventType == "NewProcess":
                    startId = processElement.get("StartId")
                    self.__processJoined(Process.fromMessage(self.__databases[dbName], processElement), startId)
                else:
                    self.__processLeft(Process.fromMessage(self.__databases[dbName], processElement))

    def closed(self):
        if self.__listener:
            try:
                self.__listener.closed()
            except:
                pass

    # NOTE: this is the status provided on initial broker-connection, and not
    # per-process status updates
    def __handleStatus(self, message):
        root = ElementTree.fromstring(message)
        if root.tag != "Status":
            raise Exception("Expected status message; got " + root.tag)

        self.__domainName = root.get("Domain")

        self.__entryPeer = Peer(
            self,
            self.__session.getAddress(),
            root.get("AgentId"),
            (root.get("Role") == "Broker"),
            self.__session.getPort(),
            root.get("Hostname"),
            root.get("Version"),
        )
        self.__peerJoined(self.__entryPeer)

        for child in list(root):
            if child.tag == "Broker":
                self.__peerJoined(Peer.fromMessage(self, child))

        for child in list(root):
            if child.tag == "Database":
                name = child.get("Name")
                if self.__listener:
                    try:
                        self.__listener.databaseJoined(self.__databases[name])
                    except:
                        pass

                for processElement in list(child):
                    if processElement.tag == "Process":
                        if name not in self.__databases:
                            self.__databases[name] = Database(self, name)
                        self.__processJoined(Process.fromMessage(self.__databases[name], processElement), None)

    def __peerJoined(self, peer):
        self.__peers[peer.getId()] = peer
        if self.__listener:
            try:
                self.__listener.peerJoined(peer)
            except:
                pass

    def __peerLeft(self, peer):
        del self.__peers[peer.getId()]
        if self.__listener:
            try:
                self.__listener.peerLeft(peer)
            except:
                pass

    def __processJoined(self, process, startId):
        process.getDatabase()._addProcess(process)
        process.getPeer()._notifyStartId(startId, process)
        if self.__listener:
            try:
                self.__listener.processJoined(process)
            except:
                pass

    def __processLeft(self, process):
        database = process.getDatabase()
        database._removeProcess(process)
        process.getPeer()._removeProcess(process)
        if self.__listener:
            try:
                self.__listener.processLeft(process)
            except:
                pass

        if database.getProcessCount() == 0:
            del self.__databases[database.getName()]
            if self.__listener:
                try:
                    self.__listener.databaseLeft(database)
                except:
                    pass

    def __processFailed(self, peer, startId, reason):
        peer._notifyStartId(startId, reason)
        if self.__listener:
            try:
                self.__listener.processFailed(peer, reason)
            except:
                pass

    def __processStatusChanged(self, process, status):
        process._setStatus(status)
        if self.__listener:
            try:
                self.__listener.processStatusChanged(process, status)
            except:
                pass

    # an initial verison only to support the shutdown routine that doesn't
    # need to watch for return messages ... right now this module is only
    # supporting the tests, which don't need the other management routines
    # at this point, so we'll flesh this out (as in the Java implementation)
    # in the second round when other utilites get updated as well
    def _sendManagementMessage(self, message, peer, process):
        root = ElementTree.fromstring(
            '<ManagementRequest AgentId="%s" ProcessId="%i"/>' % (peer.getId(), process.getPid())
        )
        root.append(message)

        self.__session.send(ElementTree.tostring(root))