interactive_interface.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 #
00003 # License: BSD
00004 #   https://raw.github.com/robotics-in-concert/rocon_multimaster/master/rocon_gateway/LICENSE
00005 #
00006 
00007 ##############################################################################
00008 # Imports
00009 ##############################################################################
00010 
00011 import roslib
00012 roslib.load_manifest('rocon_gateway')
00013 import threading
00014 from gateway_msgs.msg import RemoteRule
00015 import re
00016 import copy
00017 
00018 # Local imports
00019 import utils
00020 
00021 ##############################################################################
00022 # Classes
00023 ##############################################################################
00024 
00025 
00026 class InteractiveInterface(object):
00027     '''
00028       Parent interface for flip and pull interfaces.
00029     '''
00030     def __init__(self, default_rule_blacklist, default_rules, all_targets):
00031         '''
00032           @param default_rule_blacklist : used when in flip/pull all mode
00033           @type dictionary of gateway
00034           @param default_rules : static rules to flip/pull on startup
00035           @type gateway_msgs.msg.RemoteRule[]
00036           @param all_targets : static flip/pull all targets to flip/pull to on startup
00037           @type string[]
00038         '''
00039         # Rules that are active, ie have been flipped or pulled from remote gateways
00040         # keys are connection_types, elements are lists of RemoteRule objects
00041         # This gets aliased to self.flipped or self.pulled as necessary in
00042         # the subclasses
00043         self.active = utils.createEmptyConnectionTypeDictionary()
00044 
00045         # Default rules used in the xxxAll modes
00046         self._default_blacklist = default_rule_blacklist  # dictionary of gateway-gateway_msgs.msg.Rule lists, not RemoteRules!
00047 
00048         # keys are connection_types, elements are lists of gateway_msgs.msg.RemoteRule objects
00049         self.watchlist = utils.createEmptyConnectionTypeDictionary()    # Specific rules used to determine what local rules to flip  
00050 
00051         # keys are connection_types, elements are lists of utils.Registration objects
00052         self.registrations = utils.createEmptyConnectionTypeDictionary()  # Flips from remote gateways that have been locally registered
00053 
00054         # Blacklists when doing flip all - different for each gateway, each value is one of our usual rule type dictionaries
00055         self._blacklist = {}
00056 
00057         self._lock = threading.Lock()
00058 
00059         # Load up static rules.
00060         for rule in default_rules:
00061             self.add_rule(rule)
00062         for gateway in all_targets:
00063             self.add_all(gateway,[])  # don't add the complexity of extra blacklists yet, maybe later
00064 
00065     ##########################################################################
00066     # Rules
00067     ##########################################################################
00068 
00069     def add_rule(self, remote_rule):
00070         '''
00071           Add a remote rule to the watchlist for monitoring.
00072 
00073           @param remote_rule : the remote rule to add to the watchlist
00074           @type gateway_msgs.msg.RemoteRule
00075 
00076           @return the remote rule, or None if the rule already exists.
00077           @rtype gateway_msgs.msg.RemoteRule || None
00078         '''
00079         result = None
00080         self._lock.acquire()
00081         rule_already_exists = False
00082         # Could be a bit smarter here - given regex expressions an added
00083         # rule may be redundant. It doesn't break the eventual behaviour though
00084         for watched_rule in self.watchlist[remote_rule.rule.type]:
00085             if watched_rule.gateway   == remote_rule.gateway and \
00086                watched_rule.rule.name == remote_rule.rule.name and \
00087                watched_rule.rule.node == remote_rule.rule.node:
00088                 rule_already_exists = True
00089                 break
00090         if not rule_already_exists:
00091             self.watchlist[remote_rule.rule.type].append(remote_rule)
00092             result = remote_rule
00093         self._lock.release()
00094         return result
00095 
00096     def remove_rule(self, remote_rule):
00097         '''
00098           Remove a rule. Be a bit careful looking for a rule to remove, depending
00099           on the node name, which can be set (exact rule/node name match) or
00100           None in which case all nodes of that kind of flip will match.
00101 
00102           Handle the remapping appropriately.
00103 
00104           @param remote_rule : the remote rule to remove from the watchlist.
00105           @type gateway_msgs.msg.RemoteRule
00106          
00107           @return Rules remaining in the watchlist
00108           @rtype RemoteRule[]
00109         '''
00110         if remote_rule.rule.node:
00111             # This looks for *exact* matches.
00112             try:
00113                 self._lock.acquire()
00114                 self.watchlist[remote_rule.rule.type].remove(remote_rule)
00115                 self._lock.release()
00116                 return [remote_rule]
00117             except ValueError:
00118                 self._lock.release()
00119                 return []
00120         else:
00121             # This looks for any flip rules which match except for the node name
00122             existing_rules = []
00123             self._lock.acquire()
00124             for existing_rule in self.watchlist[remote_rule.rule.type]:
00125                 if (existing_rule.gateway == remote_rule.gateway) and \
00126                    (existing_rule.rule.name == remote_rule.rule.name):
00127                     existing_rules.append(existing_rule)
00128             for rule in existing_rules:
00129                 self.watchlist[remote_rule.rule.type].remove(rule)  # not terribly optimal
00130             self._lock.release()
00131             return existing_rules
00132 
00133     def add_all(self, gateway, blacklist):
00134         '''
00135           Instead of watching/acting on specific rules, take action
00136           on everything except for rules in a blacklist.
00137 
00138           @param gateway : target remote gateway string id
00139           @type str
00140 
00141           @param blacklist : do not act on rules matching these patterns
00142           @type gateway_msgs.msg.Rule[]
00143 
00144           @return success or failure depending on if it ahs already been set or not
00145           @rtype Bool
00146         '''
00147         self._lock.acquire()
00148         # Blacklist
00149         if gateway in self._blacklist:
00150             self._lock.release()
00151             return False
00152         self._blacklist[gateway] = self._default_blacklist
00153         for rule in blacklist:
00154             self._blacklist[gateway][rule.type].append(rule)
00155         # Flips
00156         for connection_type in utils.connection_types:
00157             remote_rule = RemoteRule()
00158             remote_rule.gateway = gateway
00159             remote_rule.rule.name = '.*'
00160             remote_rule.rule.node = None
00161             remote_rule.rule.type = connection_type
00162             # Remove all other rules for that gateway
00163             self.watchlist[connection_type][:] = [rule for rule in self.watchlist[connection_type] if rule.gateway != gateway]
00164             # basically self.add_rule() - do it manually here so we don't deadlock locks
00165             self.watchlist[connection_type].append(remote_rule)
00166         self._lock.release()
00167         return True
00168 
00169     def remove_all(self, gateway):
00170         '''
00171           Remove the add all rule for the specified gateway.
00172 
00173           @param gateway : target remote gateway string id
00174           @type str
00175         '''
00176         self._lock.acquire()
00177         if gateway in self._blacklist:
00178             del self._blacklist[gateway]
00179         for connection_type in utils.connection_types:
00180             for rule in self.watchlist[connection_type]:
00181                 if rule.gateway == gateway:
00182                     # basically self.remove_rule() - do it manually here so we don't deadlock locks
00183                     try:
00184                         self.watchlist[connection_type].remove(rule)
00185                     except ValueError:
00186                         pass  # should never get here
00187         self._lock.release()
00188 
00189     ##########################################################################
00190     # Accessors for Gateway Info
00191     ##########################################################################
00192 
00193     def is_matched(self, rule, rule_name, name, node):
00194         matched = False
00195         name_match_result = re.match(rule_name, name)
00196         if name_match_result and name_match_result.group() == name:
00197             if utils.isAllPattern(rule_name):
00198                 if self._isInBlacklist(rule.gateway, type, name, node):
00199                     return False
00200             if rule.rule.node:
00201                 node_match_result = re.match(rule.rule.node, node)
00202                 if node_match_result and node_match_result.group() == node:
00203                     matched = True
00204             else:
00205                 matched = True
00206         return matched
00207 
00208     def getLocalRegistrations(self):
00209         '''
00210           Gets the local registrations for GatewayInfo consumption (flipped ins/pulls).
00211 
00212           We don't need to show the service and node uri's here.
00213 
00214           Basic operation : convert Registration -> RemoteRule for each registration
00215 
00216           @return the list of registrations corresponding to remote interactions
00217           @rtype RemoteRule[]
00218         '''
00219         local_registrations = []
00220         for connection_type in utils.connection_types:
00221             for registration in self.registrations[connection_type]:
00222                 remote_rule = RemoteRule()
00223                 remote_rule.gateway = registration.remote_gateway
00224                 remote_rule.rule.name = registration.connection.rule.name
00225                 remote_rule.rule.node = registration.connection.rule.node
00226                 remote_rule.rule.type = connection_type
00227                 local_registrations.append(remote_rule)
00228         return local_registrations
00229 
00230     def getWatchlist(self):
00231         '''
00232           Gets the watchlist for GatewayInfo consumption.
00233 
00234           @return the list of flip rules that are being watched
00235           @rtype gateway_msgs.msg.RemoteRule[]
00236         '''
00237         watchlist = []
00238         for connection_type in utils.connection_types:
00239             watchlist.extend(copy.deepcopy(self.watchlist[connection_type]))
00240         # ros messages must have string output
00241         for remote in watchlist:
00242             if not remote.rule.node:
00243                 remote.rule.node = 'None'
00244         return watchlist
00245 
00246     ##########################################################################
00247     # Utilities
00248     ##########################################################################
00249 
00250     def findRegistrationMatch(self, remote_gateway, remote_name, remote_node, connection_type):
00251         '''
00252           Check to see if a registration exists. Note that it doesn't use the
00253           local node name in the check. We will get things like unflip requests that
00254           don't have this variable set (that gets autogenerated when registering
00255           the flip), but we need to find the matching registration.
00256 
00257           We then return the registration that matches.
00258 
00259           @param remote_gateway : string remote gateway id
00260           @type string
00261           @param remote_name, remote_node, connection_type : remote connection details
00262           @type string
00263 
00264           @return matching registration or none
00265           @rtype utils.Registration
00266         '''
00267 
00268         matched_registration = None
00269         self._lock.acquire()
00270         for registration in self.registrations[connection_type]:
00271             if (registration.remote_gateway == remote_gateway) and \
00272                (registration.connection.rule.name == remote_name) and \
00273                (registration.connection.rule.node == remote_node) and \
00274                (registration.connection.rule.type == connection_type):
00275                 matched_registration = registration
00276                 break
00277             else:
00278                 continue
00279         self._lock.release()
00280         return matched_registration
00281 
00282     def _isInBlacklist(self, gateway, type, name, node):
00283         '''
00284           Check if a particular connection is in the blacklist. Use this to
00285           filter connections from the flip_all command.
00286 
00287           @todo move to utils - should be shared with the public interface.
00288         '''
00289         for blacklist_rule in self._blacklist[gateway][type]:
00290             name_match_result = re.match(blacklist_rule.name, name)
00291             if name_match_result and name_match_result.group() == name:
00292                 if blacklist_rule.node:
00293                     node_match_result = re.match(blacklist_rule.node, node)
00294                     if node_match_result and node_match_result.group() == node:
00295                         return True
00296                 else:  # rule.connection.node is None so we don't care about matching the node
00297                     return True
00298         return False
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends


rocon_gateway
Author(s): Daniel Stonier, Jihoon Lee,
autogenerated on Tue Jan 15 2013 17:43:24