Package rospy :: Package impl :: Module paramserver

Source Code for Module rospy.impl.paramserver

  1  # Software License Agreement (BSD License) 
  2  # 
  3  # Copyright (c) 2009, Willow Garage, Inc. 
  4  # All rights reserved. 
  5  # 
  6  # Redistribution and use in source and binary forms, with or without 
  7  # modification, are permitted provided that the following conditions 
  8  # are met: 
  9  # 
 10  #  * Redistributions of source code must retain the above copyright 
 11  #    notice, this list of conditions and the following disclaimer. 
 12  #  * Redistributions in binary form must reproduce the above 
 13  #    copyright notice, this list of conditions and the following 
 14  #    disclaimer in the documentation and/or other materials provided 
 15  #    with the distribution. 
 16  #  * Neither the name of Willow Garage, Inc. nor the names of its 
 17  #    contributors may be used to endorse or promote products derived 
 18  #    from this software without specific prior written permission. 
 19  # 
 20  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 21  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 22  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 23  # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 24  # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 25  # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 26  # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 27  # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 28  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 29  # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
 30  # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 31  # POSSIBILITY OF SUCH DAMAGE. 
 32   
 33  """Parameter Server Cache""" 
 34   
 35   
 36  import threading 
 37  from rosgraph.names import GLOBALNS, SEP 
 38   
39 -class ParamServerCache(object):
40 """ 41 Cache of values on the parameter server. Implementation 42 is just a thread-safe dictionary. 43 """ 44
45 - def __init__(self):
46 self.lock = threading.Lock() 47 self.d = None 48 self.notifier = None
49 50 ## Delete parameter from cache
51 - def delete(self, key):
52 with self.lock: 53 # partially borrowed from rosmaster/paramserver.py 54 if key == GLOBALNS: 55 raise KeyError("cannot delete root of parameter tree") 56 elif self.d is None: 57 raise KeyError(key) 58 else: 59 # key is global, so first split is empty 60 namespaces = [x for x in key.split(SEP) if x] 61 # - last namespace is the actual key we're deleting 62 value_key = namespaces[-1] 63 namespaces = namespaces[:-1] 64 d = self.d 65 # - descend tree to the node we're setting 66 for ns in namespaces: 67 if type(d) != dict or ns not in d: 68 raise KeyError(key) 69 else: 70 d = d[ns] 71 72 if value_key not in d: 73 raise KeyError(key) 74 else: 75 del d[value_key]
76
77 - def set_notifier(self, notifier):
78 """ 79 Notifier implements any parameter subscription logic. The 80 notifier should be a function that takes in a key and value 81 that represents a parameter update. Notifier is called under 82 lock and thus must not implement any lengthy computation. 83 """ 84 self.notifier = notifier
85
86 - def update(self, key, value):
87 """ 88 Update the value of the parameter in the cache 89 @param key: parameter key 90 @type key: str 91 @param value: parameter value 92 @type value: str 93 @raise: KeyError if key is not already in the cache. 94 """ 95 with self.lock: 96 # partially borrowed from rosmaster/paramserver.py 97 namespaces = [x for x in key.split(SEP) if x] 98 # - last namespace is the actual key we're storing in 99 d = self.d 100 if d is None: 101 raise KeyError(key) 102 value_key = namespaces[-1] 103 namespaces = namespaces[:-1] 104 # - descend tree to the node we're setting 105 for ns in namespaces: 106 if ns not in d: 107 raise KeyError(key) 108 else: 109 d = d[ns] 110 111 if value_key not in d: 112 raise KeyError(key) 113 114 d[value_key] = value 115 if self.notifier is not None: 116 self.notifier(key, value)
117
118 - def set(self, key, value):
119 """ 120 Set the value of the parameter in the cache. This is a 121 prerequisite of calling update(). 122 @param key: parameter key 123 @type key: str 124 @param value: parameter value 125 @type value: str 126 """ 127 with self.lock: 128 # partially borrowed from rosmaster/paramserver.py 129 if key == GLOBALNS: 130 if type(value) != dict: 131 raise TypeError("cannot set root of parameter tree to " 132 "non-dictionary") 133 self.d = value 134 else: 135 namespaces = [x for x in key.split(SEP) if x] 136 # - last namespace is the actual key we're storing in 137 value_key = namespaces[-1] 138 namespaces = namespaces[:-1] 139 if self.d is None: 140 self.d = {} 141 d = self.d 142 # - descend tree to the node we're setting 143 for ns in namespaces: 144 if ns not in d: 145 new_d = {} 146 d[ns] = new_d 147 d = new_d 148 else: 149 val = d[ns] 150 # implicit type conversion of value to namespace 151 if type(val) != dict: 152 d[ns] = val = {} 153 d = val 154 155 d[value_key] = value
156
157 - def get(self, key):
158 """ 159 @param key: parameter key 160 @type key: str 161 @return: Current value for parameter 162 @raise: KeyError 163 """ 164 with self.lock: 165 # borrowed from rosmaster/paramserver.py 166 if self.d is None: 167 raise KeyError(key) 168 val = self.d 169 if key != GLOBALNS: 170 # split by the namespace separator, ignoring empty splits 171 namespaces = [x for x in key.split(SEP) if x] 172 for ns in namespaces: 173 if not type(val) == dict: 174 raise KeyError(val) 175 val = val[ns] 176 if isinstance(val, dict) and not val: 177 raise KeyError(key) 178 return val
179 180 _param_server_cache = None
181 -def get_param_server_cache():
182 """ 183 Get a handle on the client-wide parameter server cache 184 """ 185 global _param_server_cache 186 if _param_server_cache is None: 187 _param_server_cache = ParamServerCache() 188 return _param_server_cache
189