00001
00002
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 Object representing a manager node in the tree.
00017
00018 '''
00019
00020
00021 from omniORB import CORBA, TRANSIENT_ConnectFailed, UNKNOWN_UserException
00022 import os.path
00023 import sys
00024
00025 from rtctree.component import Component
00026 from rtctree.exceptions import FailedToLoadModuleError, \
00027 FailedToCreateComponentError, \
00028 FailedToDeleteComponentError, \
00029 FailedToSetConfigurationError, \
00030 FailedToAddMasterManagerError, \
00031 FailedToRemoveMasterManagerError, \
00032 FailedToAddSlaveManagerError, \
00033 FailedToRemoveSlaveManagerError
00034 from rtctree.node import TreeNode
00035 from rtctree.utils import nvlist_to_dict
00036 import RTC
00037
00038
00039
00040
00041
00042 class Manager(TreeNode):
00043 '''Node representing a manager on a name server.
00044
00045 Manager nodes can occur below name server and directory nodes. They may
00046 store child components and child managers. They can be used to add and
00047 remove new components and managers to the tree at run time.
00048
00049 '''
00050 def __init__(self, name=None, parent=None, obj=None, *args, **kwargs):
00051 '''Constructor. Calls the TreeNode constructor.'''
00052 super(Manager, self).__init__(name=name, parent=parent, *args,
00053 **kwargs)
00054 self._obj = obj
00055 self._parse()
00056
00057
00058
00059
00060 def create_component(self, module_name):
00061 '''Create a component out of a loaded module.
00062
00063 Turns a previously-loaded shared module into a component in the
00064 manager. This will invalidate any objects that are children of this
00065 node.
00066
00067 The @ref module_name argument can contain options that set various
00068 properties of the new component. These must be appended to the module
00069 name, prefixed by a question mark for each property, in key=value
00070 format. For example, to change the instance name of the new component,
00071 append '?instance_name=new_name' to the module name.
00072
00073 @param module_name Name of the module to turn into a component.
00074 @raises FailedToCreateComponentError
00075
00076 '''
00077 with self._mutex:
00078 if not self._obj.create_component(module_name):
00079 raise FailedToCreateComponentError(module_name)
00080
00081
00082 self._parse_component_children()
00083
00084 def delete_component(self, instance_name):
00085 '''Delete a component.
00086
00087 Deletes the component specified by @ref instance_name from the manager.
00088 This will invalidate any objects that are children of this node.
00089
00090 @param instance_name The instance name of the component to delete.
00091 @raises FailedToDeleteComponentError
00092
00093 '''
00094 with self._mutex:
00095 if self._obj.delete_component(instance_name) != RTC.RTC_OK:
00096 raise FailedToDeleteComponentError(instance_name)
00097
00098
00099 self._parse_component_children()
00100
00101 def load_module(self, path, init_func):
00102 '''Load a shared library.
00103
00104 Call this function to load a shared library (DLL file under Windows,
00105 shared object under UNIX) into the manager.
00106
00107 @param path The path to the shared library.
00108 @param init_func The name entry function in the library.
00109 @raises FailedToLoadModuleError
00110
00111 '''
00112 try:
00113 with self._mutex:
00114 if self._obj.load_module(path, init_func) != RTC.RTC_OK:
00115 raise FailedToLoadModuleError(path)
00116 except CORBA.UNKNOWN, e:
00117 if e.args[0] == UNKNOWN_UserException:
00118 raise FailedToLoadModuleError(path, 'CORBA User Exception')
00119 else:
00120 raise
00121
00122 def unload_module(self, path):
00123 '''Unload a loaded shared library.
00124
00125 Call this function to remove a shared library (e.g. a component) that
00126 was previously loaded.
00127
00128 @param path The path to the shared library.
00129 @raises FailedToUnloadModuleError
00130
00131 '''
00132 with self._mutex:
00133 if self._obj.unload_module(path) != RTC.RTC_OK:
00134 raise FailedToUnloadModuleError(path)
00135
00136 @property
00137 def components(self):
00138 '''The list of components in this manager, if any.
00139
00140 This information can also be found by listing the children of this node
00141 that are of type @ref Component. That method is more useful as it returns
00142 the tree entries for the components.
00143
00144 '''
00145 with self._mutex:
00146 if not self._components:
00147 self._components = [c for c in self.children if c.is_component]
00148 return self._components
00149
00150 @property
00151 def factory_profiles(self):
00152 '''The factory profiles of all loaded modules.'''
00153 with self._mutex:
00154 if not self._factory_profiles:
00155 self._factory_profiles = []
00156 for fp in self._obj.get_factory_profiles():
00157 self._factory_profiles.append(nvlist_to_dict(fp.properties))
00158 return self._factory_profiles
00159
00160
00161
00162
00163 def set_config_parameter(self, param, value):
00164 '''Set a configuration parameter of the manager.
00165
00166 @param The parameter to set.
00167 @value The new value for the parameter.
00168 @raises FailedToSetConfigurationError
00169
00170 '''
00171 with self._mutex:
00172 if self._obj.set_configuration(param, value) != RTC.RTC_OK:
00173 raise FailedToSetConfigurationError(param, value)
00174
00175 self._configuration = None
00176
00177 @property
00178 def configuration(self):
00179 '''The configuration dictionary of the manager.'''
00180 with self._mutex:
00181 if not self._configuration:
00182 self._configuration = nvlist_to_dict(self._obj.get_configuration())
00183 return self._configuration
00184
00185 @property
00186 def profile(self):
00187 '''The manager's profile.'''
00188 with self._mutex:
00189 if not self._profile:
00190 profile = self._obj.get_profile()
00191 self._profile = nvlist_to_dict(profile.properties)
00192 return self._profile
00193
00194
00195
00196
00197 def fork(self):
00198 '''Fork the manager.'''
00199 with self._mutex:
00200 self._obj.fork()
00201
00202 def shutdown(self):
00203 '''Shut down the manager.'''
00204 with self._mutex:
00205 self._obj.shutdown()
00206
00207 def restart(self):
00208 '''Restart the manager.'''
00209 with self._mutex:
00210 self._obj.restart()
00211
00212
00213
00214
00215 @property
00216 def is_directory(self):
00217 '''Is this node a directory?'''
00218 return True
00219
00220 @property
00221 def is_manager(self):
00222 '''Is this node a manager?'''
00223 return True
00224
00225
00226 @property
00227 def object(self):
00228 '''The RTM::Manager object that this node contains.'''
00229 with self._mutex:
00230 return self._obj
00231
00232 @property
00233 def is_master(self):
00234 '''Is this manager node a master manager?
00235
00236 Master managers have a direct presence on the name server. Slave
00237 managers are only present as children of other managers.
00238
00239 '''
00240 with self._mutex:
00241 return self._obj.is_master()
00242
00243 @property
00244 def loadable_modules(self):
00245 '''The list of loadable module profile dictionaries.'''
00246 with self._mutex:
00247 if not self._loadable_modules:
00248 self._loadable_modules = []
00249 for mp in self._obj.get_loadable_modules():
00250 self._loadable_modules.append(nvlist_to_dict(mp.properties))
00251 return self._loadable_modules
00252
00253 @property
00254 def loaded_modules(self):
00255 '''The list of loaded module profile dictionaries.'''
00256 with self._mutex:
00257 if not self._loaded_modules:
00258 self._loaded_modules = []
00259 for mp in self._obj.get_loaded_modules():
00260 self._loaded_modules.append(nvlist_to_dict(mp.properties))
00261 return self._loaded_modules
00262
00263 @property
00264 def masters(self):
00265 '''The list of master managers of this manager, if any.
00266
00267 If this manager is a master, this list will be empty.
00268
00269 '''
00270 with self._mutex:
00271 if not self._masters:
00272 raise NotImplementedError
00273 return self._masters
00274
00275 @property
00276 def slaves(self):
00277 '''The list of slave managers of this manager, if any.
00278
00279 This information can also be found by listing the children of this node
00280 that are of type @ref Manager.
00281
00282 '''
00283 with self._mutex:
00284 if not self._slaves:
00285 self._slaves = [c for c in self.children if c.is_manager]
00286 return self._slaves
00287
00288
00289
00290
00291 def _add_master(self, new_master):
00292
00293
00294 with self._mutex:
00295 if self._obj.add_master_manager(new_master.object) != RTC.RTC_OK:
00296 raise FailedToAddMasterManagerError
00297
00298 def _add_slave(self, new_slave):
00299
00300
00301
00302
00303 with self._mutex:
00304 if self._obj.add_save_manager(new_slave.object) != RTC.RTC_OK:
00305 raise FailedToAddSlaveManagerError(self.name, new_slave.name)
00306
00307 def _parse(self):
00308
00309 with self._mutex:
00310 self._components = None
00311 self._configuration = None
00312 self._profile = None
00313 self._factory_profiles = None
00314 self._loadable_modules = None
00315 self._loaded_modules = None
00316 self._masters = None
00317 self._slaves = None
00318 self._parse_children()
00319
00320 def _parse_children(self):
00321
00322 with self._mutex:
00323 self._parse_component_children()
00324 self._parse_manager_children()
00325
00326 def _parse_component_children(self):
00327
00328 with self._mutex:
00329 try:
00330 comps = self._obj.get_components()
00331 except CORBA.BAD_PARAM, e:
00332 print >>sys.stderr, '{0}: {1}'.format(
00333 os.path.basename(sys.argv[0]), e)
00334 return
00335 for c in comps:
00336
00337 profile = c.get_component_profile()
00338 instance_name = profile.instance_name
00339
00340 leaf = Component(instance_name + '.rtc', self, c)
00341 self._add_child(leaf)
00342
00343 def _parse_manager_children(self):
00344
00345 with self._mutex:
00346 try:
00347 mgrs = self._obj.get_slave_managers()
00348 except CORBA.BAD_OPERATION:
00349
00350 return
00351 index = 0
00352 for m in mgrs:
00353
00354 try:
00355 props = nvlist_to_dict(m.get_profile().properties)
00356 except CORBA.TRANSIENT, e:
00357 if e.args[0] == TRANSIENT_ConnectFailed:
00358 print >>sys.stderr, '{0}: Warning: zombie slave of '\
00359 'manager {1} found'.format(sys.argv[0],
00360 self.name)
00361 continue
00362 else:
00363 raise
00364 if 'name' in props:
00365 name = props['name']
00366 else:
00367 name = 'slave{0}'.format(index)
00368 index += 1
00369 leaf = Manager(name, self, m)
00370 self._add_child(leaf)
00371
00372 def _remove_master(self, master):
00373
00374
00375 with self._mutex:
00376 if self._obj.remove_master_manager(master.object) != RTC.RTC_OK:
00377 raise FailedToRemoveMasterManagerError
00378
00379 def _remove_slave(self, slave):
00380
00381
00382
00383 with self._mutex:
00384 if self._obj.remove_slave_manager(slave.object) != RTC.RTC_OK:
00385 raise FailedToRemoveSlaveManagerError(self.name, slave.name)
00386
00387 def _set_parent(self, new_parent):
00388
00389
00390
00391
00392 with self._mutex:
00393 if self.parent:
00394 if self.parent.is_manager:
00395 self.parent._remove_slave(self)
00396 self._remove_master(self.parent)
00397 self._add_master(new_parent)
00398 new_parent._add_slave(self)
00399 self.parent = new_parent
00400
00401
00402
00403