tree.py
Go to the documentation of this file.
00001 # -*- Python -*-
00002 # -*- coding: utf-8 -*-
00003 
00004 '''rtctree
00005 
00006 Copyright (C) 2009-2014
00007     Geoffrey Biggs
00008     RT-Synthesis Research Group
00009     Intelligent Systems Research Institute,
00010     National Institute of Advanced Industrial Science and Technology (AIST),
00011     Japan
00012     All rights reserved.
00013 Licensed under the Eclipse Public License -v 1.0 (EPL)
00014 http://www.opensource.org/licenses/eclipse-1.0.txt
00015 
00016 Objects and functions used to build and store a tree representing a hierarchy
00017 of name servers, directories, managers and components.
00018 
00019 '''
00020 
00021 from copy import deepcopy
00022 from omniORB import CORBA
00023 import os
00024 import sys
00025 
00026 from rtctree import NAMESERVERS_ENV_VAR, ORB_ARGS_ENV_VAR
00027 from rtctree.exceptions import *
00028 from rtctree.path import BadPathError
00029 from rtctree.node import TreeNode
00030 from rtctree.directory import Directory
00031 from rtctree.nameserver import NameServer
00032 from rtctree.manager import Manager
00033 from rtctree.component import Component
00034 from rtctree.utils import filtered, trim_filter
00035 
00036 
00037 ##############################################################################
00038 ## Tree object
00039 
00040 class RTCTree(object):
00041     '''Represents a tree of name servers, directories, managers and components.
00042 
00043     This stores the root node. All other nodes branch off from that.
00044 
00045     When creating a tree, you may pass no arguments, or a list of name servers
00046     to load, or a path or list of paths (as returned by
00047     rtctree.path.parse_path). If no arguments are given, the tree will load
00048     name servers from the environment variable specified in
00049     NAMESERVERS_ENV_VAR. If a list of servers are given, only those servers
00050     will be loaded.
00051 
00052     If paths are given, and the path is just '/', behaviour is as if no path
00053     argument were given. If a path starts with '/' and contains an element
00054     after it, that element will be treated as a name server. Otherwise the path
00055     is considered to be bad.
00056 
00057     '''
00058     def __init__(self, servers=None, paths=None, orb=None, filter=[],
00059             dynamic=False, *args, **kwargs):
00060         '''Constructor.
00061 
00062         @param servers A list of servers to parse into the tree.
00063         @param paths A list of paths from which to get servers to parse
00064                      into the tree.
00065         @param orb If not None, the specified ORB will be used. If None,
00066                    the tree object will create its own ORB.
00067         @param filter A list of paths (each a list of strings).
00068                       If not empty, then only objects in the paths will
00069                       be parsed, to increase speed. If the tail of a
00070                       path is a directory, that entire directory will be
00071                       parsed. Directories that are not the tail will
00072                       only have the next entry in the path parsed.
00073         @param dynamic Use observers to keep the tree up-to-date. For example,
00074                        when a component changes state, an observer can notify
00075                        RTCTree so that the corresponding object in the tree can
00076                        be updated. Currently this only affects components.
00077         @raises NonRootPathError
00078 
00079         '''
00080         super(RTCTree, self).__init__()
00081         self._root = TreeNode('/', None, dynamic=dynamic)
00082         self._create_orb(orb)
00083         self._dynamic = dynamic
00084         if servers:
00085             self._parse_name_servers(servers, filter=filter, dynamic=dynamic)
00086         if paths:
00087             if type(paths[0]) == str:
00088                 if paths[0][0] != '/':
00089                     raise NonRootPathError(paths[0])
00090                 if len(paths) > 1:
00091                     self.add_name_server(paths[1], filter=filter,
00092                             dynamic=dynamic)
00093             else:
00094                 for p in paths:
00095                     if p[0] != '/':
00096                         raise NonRootPathError(p)
00097                     if len(p) > 1:
00098                         self.add_name_server(p[1], filter=filter,
00099                                 dynamic=dynamic)
00100             self.load_servers_from_env(filter=filter, dynamic=dynamic)
00101         if not servers and not paths:
00102             self.load_servers_from_env(filter=filter, dynamic=dynamic)
00103 
00104     def __del__(self):
00105         # Destructor to ensure the ORB shuts down correctly.
00106         if self._orb_is_mine:
00107             self._orb.shutdown(wait_for_completion=CORBA.FALSE)
00108             self._orb.destroy()
00109 
00110     def __str__(self):
00111         # Get a (potentially very large) string describing the tree.
00112         return str(self._root)
00113 
00114     def add_name_server(self, server, filter=[], dynamic=None):
00115         '''Parse a name server, adding its contents to the tree.
00116 
00117         @param server The address of the name server, in standard
00118                       address format. e.g. 'localhost',
00119                       'localhost:2809', '59.7.0.1'.
00120         @param filter Restrict the parsed objects to only those in this
00121                       path. For example, setting filter to [['/',
00122                       'localhost', 'host.cxt', 'comp1.rtc']] will
00123                       prevent 'comp2.rtc' in the same naming context
00124                       from being parsed.
00125         @param dynamic Override the tree-wide dynamic setting. If not provided,
00126                        the value given when the tree was created will be used.
00127 
00128         '''
00129         if dynamic == None:
00130             dynamic = self._dynamic
00131         self._parse_name_server(server, filter, dynamic=dynamic)
00132 
00133     def get_node(self, path):
00134         '''Get a node by path.
00135 
00136         @param path A list of path elements pointing to a node in the tree.
00137                     For example, ['/', 'localhost', 'dir.host']. The first
00138                     element in this path should be the root node's name.
00139 
00140         '''
00141         return self._root.get_node(path)
00142 
00143     def has_path(self, path):
00144         '''Check if the tree has a path.
00145 
00146         @param path A list of path elements pointing to a node in the tree.
00147                     For example, ['/', 'localhost', 'dir.host']. The first
00148                     element in this path should be the root node's name.
00149 
00150         '''
00151         return self._root.has_path(path)
00152 
00153     def is_component(self, path):
00154         '''Is the node pointed to by @ref path a component?'''
00155         node = self.get_node(path)
00156         return node.is_component
00157 
00158     def is_directory(self, path):
00159         '''Is the node pointed to by @ref path a directory (name servers and
00160         naming contexts)?
00161 
00162         '''
00163         node = self.get_node(path)
00164         return node.is_directory
00165 
00166     def is_manager(self, path):
00167         '''Is the node pointed to by @ref path a manager?'''
00168         node = self.get_node(path)
00169         return node.is_manager
00170 
00171     def is_nameserver(self, path):
00172         '''Is the node pointed to by @ref path a name server (specialisation
00173         of directory nodes)?
00174 
00175         '''
00176         node = self.get_node(path)
00177         return node.is_nameserver
00178 
00179     def is_unknown(self, path):
00180         '''Is the node pointed to by @ref path an unknown object?'''
00181         node = self.get_node(path)
00182         return node.is_unknown
00183 
00184     def is_zombie(self, path):
00185         '''Is the node pointed to by @ref path a zombie object?'''
00186         node = self.get_node(path)
00187         return node.is_zombie
00188 
00189     def iterate(self, func, args=None, filter=[]):
00190         '''Call a function on the root node, and recursively all its children.
00191 
00192         This is a depth-first iteration.
00193 
00194         @param func The function to call. Its declaration must be
00195                     'def blag(node, args)', where 'node' is the current node
00196                     in the iteration and args is the value of @ref args.
00197         @param args Extra arguments to pass to the function at each iteration.
00198                     Pass multiple arguments in as a tuple.
00199         @param filter A list of filters to apply before calling func for each
00200                       node in the iteration. If the filter is not True,
00201                       @ref func will not be called for that node. Each filter
00202                       entry should be a string, representing on of the is_*
00203                       properties (is_component, etc), or a function object.
00204         @return The results of the calls to @ref func in a list.
00205 
00206         '''
00207         return self._root.iterate(func, args, filter)
00208 
00209     def load_servers_from_env(self, filter=[], dynamic=None):
00210         '''Load the name servers environment variable and parse each server in
00211         the list.
00212 
00213         @param filter Restrict the parsed objects to only those in this
00214                       path. For example, setting filter to [['/',
00215                       'localhost', 'host.cxt', 'comp1.rtc']] will
00216                       prevent 'comp2.rtc' in the same naming context
00217                       from being parsed.
00218         @param dynamic Override the tree-wide dynamic setting. If not provided,
00219                        the value given when the tree was created will be used.
00220 
00221         '''
00222         if dynamic == None:
00223             dynamic = self._dynamic
00224         if NAMESERVERS_ENV_VAR in os.environ:
00225             servers = [s for s in os.environ[NAMESERVERS_ENV_VAR].split(';') \
00226                          if s]
00227             self._parse_name_servers(servers, filter, dynamic)
00228 
00229     def give_away_orb(self):
00230         '''Releases ownership of an ORB created by the tree.
00231 
00232         This will prevent the ORB being destroyed when the tree is.
00233 
00234         '''
00235         self._orb_is_mine = False
00236 
00237     def own_orb(self):
00238         '''Claims ownership of an ORB created elsewhere.
00239 
00240         This will cause the ORB to be destroyed when the tree is.
00241 
00242         '''
00243         self._orb_is_mine = True
00244 
00245     @property
00246     def orb(self):
00247         '''The reference to the ORB held by this tree.'''
00248         return self._orb
00249 
00250     def _create_orb(self, orb=None):
00251         # Create the ORB, optionally checking the environment variable for
00252         # arguments to pass to the ORB.
00253         if orb:
00254             self._orb = orb
00255             self._orb_is_mine = False
00256         else:
00257             if ORB_ARGS_ENV_VAR in os.environ:
00258                 orb_args = os.environ[ORB_ARGS_ENV_VAR].split(';')
00259             else:
00260                 orb_args = []
00261             self._orb = CORBA.ORB_init(orb_args)
00262             self._orb_is_mine = True
00263         # Run the POA manager
00264         self._poa = self._orb.resolve_initial_references('RootPOA')
00265         self._poa._get_the_POAManager().activate()
00266 
00267     def _parse_name_servers(self, servers, filter=[], dynamic=False):
00268         # Parse a list of name servers.
00269         if type(servers) is str:
00270             # Don't parse any servers already parsed
00271             if servers in self._root.children_names:
00272                 return
00273             self._parse_name_server(servers, filter, dynamic=dynamic)
00274         else:
00275             for server in servers:
00276                 # Don't parse any servers already parsed
00277                 if server in self._root.children_names:
00278                     return
00279                 self._parse_name_server(server, filter, dynamic=dynamic)
00280 
00281     def _parse_name_server(self, address, filter=[], dynamic=False):
00282         # Parse a single name server and add it to the root node.
00283         if not filtered(['/', address], filter):
00284             new_ns_node = NameServer(self._orb, address, self._root,
00285                     trim_filter(deepcopy(filter), 2), dynamic=dynamic)
00286             self._root._add_child(new_ns_node)
00287 
00288 
00289 # vim: tw=79
00290 


rtctree
Author(s): Geoffrey Biggs
autogenerated on Wed Aug 26 2015 16:13:08