示例#1
0
    def __init__(self,
                 servers=None,
                 paths=None,
                 orb=None,
                 filter=[],
                 dynamic=False,
                 *args,
                 **kwargs):
        '''Constructor.

        @param servers A list of servers to parse into the tree.
        @param paths A list of paths from which to get servers to parse
                     into the tree.
        @param orb If not None, the specified ORB will be used. If None,
                   the tree object will create its own ORB.
        @param filter A list of paths (each a list of strings).
                      If not empty, then only objects in the paths will
                      be parsed, to increase speed. If the tail of a
                      path is a directory, that entire directory will be
                      parsed. Directories that are not the tail will
                      only have the next entry in the path parsed.
        @param dynamic Use observers to keep the tree up-to-date. For example,
                       when a component changes state, an observer can notify
                       RTCTree so that the corresponding object in the tree can
                       be updated. Currently this only affects components.
        @raises NonRootPathError

        '''
        super(RTCTree, self).__init__()
        self._root = TreeNode('/', None, dynamic=dynamic)
        self._create_orb(orb)
        self._dynamic = dynamic
        if servers:
            self._parse_name_servers(servers, filter=filter, dynamic=dynamic)
        if paths:
            if type(paths[0]) == str:
                if paths[0][0] != '/':
                    raise exceptions.NonRootPathError(paths[0])
                if len(paths) > 1:
                    self.add_name_server(paths[1],
                                         filter=filter,
                                         dynamic=dynamic)
            else:
                for p in paths:
                    if p[0] != '/':
                        raise exceptions.NonRootPathError(p)
                    if len(p) > 1:
                        self.add_name_server(p[1],
                                             filter=filter,
                                             dynamic=dynamic)
            self.load_servers_from_env(filter=filter, dynamic=dynamic)
        if not servers and not paths:
            self.load_servers_from_env(filter=filter, dynamic=dynamic)
示例#2
0
文件: tree.py 项目: chikuta/rtctree
    def __init__(self, servers=None, paths=None, orb=None, filter=[],
            dynamic=False, *args, **kwargs):
        '''Constructor.

        @param servers A list of servers to parse into the tree.
        @param paths A list of paths from which to get servers to parse
                     into the tree.
        @param orb If not None, the specified ORB will be used. If None,
                   the tree object will create its own ORB.
        @param filter A list of paths (each a list of strings).
                      If not empty, then only objects in the paths will
                      be parsed, to increase speed. If the tail of a
                      path is a directory, that entire directory will be
                      parsed. Directories that are not the tail will
                      only have the next entry in the path parsed.
        @param dynamic Use observers to keep the tree up-to-date. For example,
                       when a component changes state, an observer can notify
                       RTCTree so that the corresponding object in the tree can
                       be updated. Currently this only affects components.
        @raises NonRootPathError

        '''
        super(RTCTree, self).__init__()
        self._root = TreeNode('/', None, dynamic=dynamic)
        self._create_orb(orb)
        self._dynamic = dynamic
        if servers:
            self._parse_name_servers(servers, filter=filter, dynamic=dynamic)
        if paths:
            if type(paths[0]) == str:
                if paths[0][0] != '/':
                    raise exceptions.NonRootPathError(paths[0])
                if len(paths) > 1:
                    self.add_name_server(paths[1], filter=filter,
                            dynamic=dynamic)
            else:
                for p in paths:
                    if p[0] != '/':
                        raise exceptions.NonRootPathError(p)
                    if len(p) > 1:
                        self.add_name_server(p[1], filter=filter,
                                dynamic=dynamic)
            self.load_servers_from_env(filter=filter, dynamic=dynamic)
        if not servers and not paths:
            self.load_servers_from_env(filter=filter, dynamic=dynamic)
示例#3
0
文件: tree.py 项目: zoetrope/rtctree
class RTCTree(object):
    """Represents a tree of name servers, directories, managers and components.

    This stores the root node. All other nodes branch off from that.

    When creating a tree, you may pass no arguments, or a list of name servers
    to load, or a path or list of paths (as returned by
    rtctree.path.parse_path). If no arguments are given, the tree will load
    name servers from the environment variable specified in
    NAMESERVERS_ENV_VAR. If a list of servers are given, only those servers
    will be loaded.

    If paths are given, and the path is just '/', behaviour is as if no path
    argument were given. If a path starts with '/' and contains an element
    after it, that element will be treated as a name server. Otherwise the path
    is considered to be bad.

    """

    def __init__(self, servers=None, paths=None, orb=None, filter=[], dynamic=False, *args, **kwargs):
        """Constructor.

        @param servers A list of servers to parse into the tree.
        @param paths A list of paths from which to get servers to parse
                     into the tree.
        @param orb If not None, the specified ORB will be used. If None,
                   the tree object will create its own ORB.
        @param filter A list of paths (each a list of strings).
                      If not empty, then only objects in the paths will
                      be parsed, to increase speed. If the tail of a
                      path is a directory, that entire directory will be
                      parsed. Directories that are not the tail will
                      only have the next entry in the path parsed.
        @param dynamic Use observers to keep the tree up-to-date. For example,
                       when a component changes state, an observer can notify
                       RTCTree so that the corresponding object in the tree can
                       be updated. Currently this only affects components.
        @raises NonRootPathError

        """
        super(RTCTree, self).__init__()
        self._root = TreeNode("/", None, dynamic=dynamic)
        self._create_orb(orb)
        self._dynamic = dynamic
        if servers:
            self._parse_name_servers(servers, filter=filter, dynamic=dynamic)
        if paths:
            if type(paths[0]) == str:
                if paths[0][0] != "/":
                    raise NonRootPathError(paths[0])
                if len(paths) > 1:
                    self.add_name_server(paths[1], filter=filter, dynamic=dynamic)
            else:
                for p in paths:
                    if p[0] != "/":
                        raise NonRootPathError(p)
                    if len(p) > 1:
                        self.add_name_server(p[1], filter=filter, dynamic=dynamic)
            self.load_servers_from_env(filter=filter, dynamic=dynamic)
        if not servers and not paths:
            self.load_servers_from_env(filter=filter, dynamic=dynamic)

    def __del__(self):
        # Destructor to ensure the ORB shuts down correctly.
        if self._orb_is_mine:
            self._orb.shutdown(wait_for_completion=CORBA.FALSE)
            self._orb.destroy()

    def __str__(self):
        # Get a (potentially very large) string describing the tree.
        return str(self._root)

    def add_name_server(self, server, filter=[], dynamic=None):
        """Parse a name server, adding its contents to the tree.

        @param server The address of the name server, in standard
                      address format. e.g. 'localhost',
                      'localhost:2809', '59.7.0.1'.
        @param filter Restrict the parsed objects to only those in this
                      path. For example, setting filter to [['/',
                      'localhost', 'host.cxt', 'comp1.rtc']] will
                      prevent 'comp2.rtc' in the same naming context
                      from being parsed.
        @param dynamic Override the tree-wide dynamic setting. If not provided,
                       the value given when the tree was created will be used.

        """
        if dynamic == None:
            dynamic = self._dynamic
        self._parse_name_server(server, filter, dynamic=dynamic)

    def get_node(self, path):
        """Get a node by path.

        @param path A list of path elements pointing to a node in the tree.
                    For example, ['/', 'localhost', 'dir.host']. The first
                    element in this path should be the root node's name.

        """
        return self._root.get_node(path)

    def has_path(self, path):
        """Check if the tree has a path.

        @param path A list of path elements pointing to a node in the tree.
                    For example, ['/', 'localhost', 'dir.host']. The first
                    element in this path should be the root node's name.

        """
        return self._root.has_path(path)

    def is_component(self, path):
        """Is the node pointed to by @ref path a component?"""
        node = self.get_node(path)
        return node.is_component

    def is_directory(self, path):
        """Is the node pointed to by @ref path a directory (name servers and
        naming contexts)?

        """
        node = self.get_node(path)
        return node.is_directory

    def is_manager(self, path):
        """Is the node pointed to by @ref path a manager?"""
        node = self.get_node(path)
        return node.is_manager

    def is_nameserver(self, path):
        """Is the node pointed to by @ref path a name server (specialisation
        of directory nodes)?

        """
        node = self.get_node(path)
        return node.is_nameserver

    def is_unknown(self, path):
        """Is the node pointed to by @ref path an unknown object?"""
        node = self.get_node(path)
        return node.is_unknown

    def is_zombie(self, path):
        """Is the node pointed to by @ref path a zombie object?"""
        node = self.get_node(path)
        return node.is_zombie

    def iterate(self, func, args=None, filter=[]):
        """Call a function on the root node, and recursively all its children.

        This is a depth-first iteration.

        @param func The function to call. Its declaration must be
                    'def blag(node, args)', where 'node' is the current node
                    in the iteration and args is the value of @ref args.
        @param args Extra arguments to pass to the function at each iteration.
                    Pass multiple arguments in as a tuple.
        @param filter A list of filters to apply before calling func for each
                      node in the iteration. If the filter is not True,
                      @ref func will not be called for that node. Each filter
                      entry should be a string, representing on of the is_*
                      properties (is_component, etc), or a function object.
        @return The results of the calls to @ref func in a list.

        """
        return self._root.iterate(func, args, filter)

    def load_servers_from_env(self, filter=[], dynamic=None):
        """Load the name servers environment variable and parse each server in
        the list.

        @param filter Restrict the parsed objects to only those in this
                      path. For example, setting filter to [['/',
                      'localhost', 'host.cxt', 'comp1.rtc']] will
                      prevent 'comp2.rtc' in the same naming context
                      from being parsed.
        @param dynamic Override the tree-wide dynamic setting. If not provided,
                       the value given when the tree was created will be used.

        """
        if dynamic == None:
            dynamic = self._dynamic
        if NAMESERVERS_ENV_VAR in os.environ:
            servers = [s for s in os.environ[NAMESERVERS_ENV_VAR].split(";") if s]
            self._parse_name_servers(servers, filter, dynamic)

    def give_away_orb(self):
        """Releases ownership of an ORB created by the tree.

        This will prevent the ORB being destroyed when the tree is.

        """
        self._orb_is_mine = False

    def own_orb(self):
        """Claims ownership of an ORB created elsewhere.

        This will cause the ORB to be destroyed when the tree is.

        """
        self._orb_is_mine = True

    @property
    def orb(self):
        """The reference to the ORB held by this tree."""
        return self._orb

    def _create_orb(self, orb=None):
        # Create the ORB, optionally checking the environment variable for
        # arguments to pass to the ORB.
        if orb:
            self._orb = orb
            self._orb_is_mine = False
        else:
            if ORB_ARGS_ENV_VAR in os.environ:
                orb_args = os.environ[ORB_ARGS_ENV_VAR].split(";")
            else:
                orb_args = []
            self._orb = CORBA.ORB_init(orb_args)
            self._orb_is_mine = True
        # Run the POA manager
        self._poa = self._orb.resolve_initial_references("RootPOA")
        self._poa._get_the_POAManager().activate()

    def _parse_name_servers(self, servers, filter=[], dynamic=False):
        # Parse a list of name servers.
        if type(servers) is str:
            # Don't parse any servers already parsed
            if servers in self._root.children_names:
                return
            self._parse_name_server(servers, filter, dynamic=dynamic)
        else:
            for server in servers:
                # Don't parse any servers already parsed
                if server in self._root.children_names:
                    return
                self._parse_name_server(server, filter, dynamic=dynamic)

    def _parse_name_server(self, address, filter=[], dynamic=False):
        # Parse a single name server and add it to the root node.
        if not filtered(["/", address], filter):
            new_ns_node = NameServer(self._orb, address, self._root, trim_filter(deepcopy(filter), 2), dynamic=dynamic)
            self._root._add_child(new_ns_node)
示例#4
0
class RTCTree(object):
    '''Represents a tree of name servers, directories, managers and components.

    This stores the root node. All other nodes branch off from that.

    When creating a tree, you may pass no arguments, or a list of name servers
    to load, or a path or list of paths (as returned by
    rtctree.path.parse_path). If no arguments are given, the tree will load
    name servers from the environment variable specified in
    NAMESERVERS_ENV_VAR. If a list of servers are given, only those servers
    will be loaded.

    If paths are given, and the path is just '/', behaviour is as if no path
    argument were given. If a path starts with '/' and contains an element
    after it, that element will be treated as a name server. Otherwise the path
    is considered to be bad.

    To explain the usage, we first launch manager and component:
    >>> import subprocess, shlex, time
    >>> p = []
    >>> p.append(subprocess.Popen(shlex.split('rtcd_python -d -f test/rtc.conf')))
    >>> p.append(subprocess.Popen(shlex.split('./test/c1_comp.py -f test/rtc.conf')))

    Initialize RTCTree and wait for the manager and the component:
    >>> t = RTCTree(servers=['localhost'])
    >>> while t.is_manager(['/', 'localhost', 'local.host_cxt', 'manager.mgr']) == False:
    ...     time.sleep(0.1)
    ...     t.get_node(['/', 'localhost']).reparse()
    >>> while t.is_component(['/', 'localhost', 'local.host_cxt', 'C10.rtc']) == False:
    ...     time.sleep(0.1)
    ...     t.get_node(['/', 'localhost']).reparse()

    Basic RTCTree operations:
    >>> t.is_nameserver(['/', 'localhost'])
    True
    >>> t.is_directory(['/', 'localhost', 'local.host_cxt'])
    True
    >>> n = t.get_node(['/', 'localhost', 'local.host_cxt', 'manager.mgr'])
    >>> type(n)
    <class 'rtctree.manager.Manager'>
    >>> n = t.get_node(['/', 'localhost', 'local.host_cxt', 'C10.rtc'])
    >>> type(n)
    <class 'rtctree.component.Component'>

    >>> n.full_path
    ['/', 'localhost', 'local.host_cxt', 'C10.rtc']
    >>> n.full_path_str
    '/localhost/local.host_cxt/C10.rtc'
    >>> n.parent == t.get_node(['/', 'localhost', 'local.host_cxt'])
    True
    >>> n.parent_name
    'local.host_cxt'
    >>> n.nameserver == t.get_node(['/', 'localhost'])
    True
    >>> n.root == t.get_node(['/'])
    True

    >>> p[0].terminate()
    >>> p[0].wait()
    -15
    >>> p[1].terminate()
    >>> p[1].wait()
    -15
    '''
    def __init__(self,
                 servers=None,
                 paths=None,
                 orb=None,
                 filter=[],
                 dynamic=False,
                 *args,
                 **kwargs):
        '''Constructor.

        @param servers A list of servers to parse into the tree.
        @param paths A list of paths from which to get servers to parse
                     into the tree.
        @param orb If not None, the specified ORB will be used. If None,
                   the tree object will create its own ORB.
        @param filter A list of paths (each a list of strings).
                      If not empty, then only objects in the paths will
                      be parsed, to increase speed. If the tail of a
                      path is a directory, that entire directory will be
                      parsed. Directories that are not the tail will
                      only have the next entry in the path parsed.
        @param dynamic Use observers to keep the tree up-to-date. For example,
                       when a component changes state, an observer can notify
                       RTCTree so that the corresponding object in the tree can
                       be updated. Currently this only affects components.
        @raises NonRootPathError

        '''
        super(RTCTree, self).__init__()
        self._root = TreeNode('/', None, dynamic=dynamic)
        self._create_orb(orb)
        self._dynamic = dynamic
        if servers:
            self._parse_name_servers(servers, filter=filter, dynamic=dynamic)
        if paths:
            if type(paths[0]) == str:
                if paths[0][0] != '/':
                    raise exceptions.NonRootPathError(paths[0])
                if len(paths) > 1:
                    self.add_name_server(paths[1],
                                         filter=filter,
                                         dynamic=dynamic)
            else:
                for p in paths:
                    if p[0] != '/':
                        raise exceptions.NonRootPathError(p)
                    if len(p) > 1:
                        self.add_name_server(p[1],
                                             filter=filter,
                                             dynamic=dynamic)
            self.load_servers_from_env(filter=filter, dynamic=dynamic)
        if not servers and not paths:
            self.load_servers_from_env(filter=filter, dynamic=dynamic)

    def __del__(self):
        # Destructor to ensure the ORB shuts down correctly.
        if self._orb_is_mine:
            self._orb.shutdown(wait_for_completion=CORBA.FALSE)
            self._orb.destroy()

    def __str__(self):
        # Get a (potentially very large) string describing the tree.
        return str(self._root)

    def add_name_server(self, server, filter=[], dynamic=None):
        '''Parse a name server, adding its contents to the tree.

        @param server The address of the name server, in standard
                      address format. e.g. 'localhost',
                      'localhost:2809', '59.7.0.1'.
        @param filter Restrict the parsed objects to only those in this
                      path. For example, setting filter to [['/',
                      'localhost', 'host.cxt', 'comp1.rtc']] will
                      prevent 'comp2.rtc' in the same naming context
                      from being parsed.
        @param dynamic Override the tree-wide dynamic setting. If not provided,
                       the value given when the tree was created will be used.

        '''
        if dynamic == None:
            dynamic = self._dynamic
        self._parse_name_server(server, filter, dynamic=dynamic)

    def get_node(self, path):
        '''Get a node by path.

        @param path A list of path elements pointing to a node in the tree.
                    For example, ['/', 'localhost', 'dir.host']. The first
                    element in this path should be the root node's name.

        '''
        return self._root.get_node(path)

    def has_path(self, path):
        '''Check if the tree has a path.

        @param path A list of path elements pointing to a node in the tree.
                    For example, ['/', 'localhost', 'dir.host']. The first
                    element in this path should be the root node's name.

        '''
        return self._root.has_path(path)

    def is_component(self, path):
        '''Is the node pointed to by @ref path a component?'''
        node = self.get_node(path)
        if not node:
            return False
        return node.is_component

    def is_directory(self, path):
        '''Is the node pointed to by @ref path a directory (name servers and
        naming contexts)?

        '''
        node = self.get_node(path)
        if not node:
            return False
        return node.is_directory

    def is_manager(self, path):
        '''Is the node pointed to by @ref path a manager?'''
        node = self.get_node(path)
        if not node:
            return False
        return node.is_manager

    def is_nameserver(self, path):
        '''Is the node pointed to by @ref path a name server (specialisation
        of directory nodes)?

        '''
        node = self.get_node(path)
        if not node:
            return False
        return node.is_nameserver

    def is_unknown(self, path):
        '''Is the node pointed to by @ref path an unknown object?'''
        node = self.get_node(path)
        if not node:
            return True
        return node.is_unknown

    def is_zombie(self, path):
        '''Is the node pointed to by @ref path a zombie object?'''
        node = self.get_node(path)
        if not node:
            return False
        return node.is_zombie

    def iterate(self, func, args=None, filter=[]):
        '''Call a function on the root node, and recursively all its children.

        This is a depth-first iteration.

        @param func The function to call. Its declaration must be
                    'def blag(node, args)', where 'node' is the current node
                    in the iteration and args is the value of @ref args.
        @param args Extra arguments to pass to the function at each iteration.
                    Pass multiple arguments in as a tuple.
        @param filter A list of filters to apply before calling func for each
                      node in the iteration. If the filter is not True,
                      @ref func will not be called for that node. Each filter
                      entry should be a string, representing on of the is_*
                      properties (is_component, etc), or a function object.
        @return The results of the calls to @ref func in a list.

        '''
        return self._root.iterate(func, args, filter)

    def load_servers_from_env(self, filter=[], dynamic=None):
        '''Load the name servers environment variable and parse each server in
        the list.

        @param filter Restrict the parsed objects to only those in this
                      path. For example, setting filter to [['/',
                      'localhost', 'host.cxt', 'comp1.rtc']] will
                      prevent 'comp2.rtc' in the same naming context
                      from being parsed.
        @param dynamic Override the tree-wide dynamic setting. If not provided,
                       the value given when the tree was created will be used.

        '''
        if dynamic == None:
            dynamic = self._dynamic
        if NAMESERVERS_ENV_VAR in os.environ:
            servers = [s for s in os.environ[NAMESERVERS_ENV_VAR].split(';') \
                         if s]
            self._parse_name_servers(servers, filter, dynamic)

    def give_away_orb(self):
        '''Releases ownership of an ORB created by the tree.

        This will prevent the ORB being destroyed when the tree is.

        '''
        self._orb_is_mine = False

    def own_orb(self):
        '''Claims ownership of an ORB created elsewhere.

        This will cause the ORB to be destroyed when the tree is.

        '''
        self._orb_is_mine = True

    @property
    def orb(self):
        '''The reference to the ORB held by this tree.'''
        return self._orb

    def _create_orb(self, orb=None):
        # Create the ORB, optionally checking the environment variable for
        # arguments to pass to the ORB.
        if orb:
            self._orb = orb
            self._orb_is_mine = False
        else:
            if ORB_ARGS_ENV_VAR in os.environ:
                orb_args = os.environ[ORB_ARGS_ENV_VAR].split(';')
            else:
                orb_args = []
            self._orb = CORBA.ORB_init(orb_args)
            self._orb_is_mine = True
        # Run the POA manager
        self._poa = self._orb.resolve_initial_references('RootPOA')
        self._poa._get_the_POAManager().activate()

    def _parse_name_servers(self, servers, filter=[], dynamic=False):
        # Parse a list of name servers.
        if type(servers) is str:
            # Don't parse any servers already parsed
            if servers in self._root.children_names:
                return
            self._parse_name_server(servers, filter, dynamic=dynamic)
        else:
            for server in servers:
                # Don't parse any servers already parsed
                if server in self._root.children_names:
                    return
                self._parse_name_server(server, filter, dynamic=dynamic)

    def _parse_name_server(self, address, filter=[], dynamic=False):
        # Parse a single name server and add it to the root node.
        if not utils.filtered(['/', address], filter):
            new_ns_node = NameServer(self._orb,
                                     address,
                                     self._root,
                                     utils.trim_filter(copy.deepcopy(filter),
                                                       2),
                                     dynamic=dynamic)
            self._root._add_child(new_ns_node)