actions.py
Go to the documentation of this file.
00001 # -*- Python -*-
00002 # -*- coding: utf-8 -*-
00003 
00004 '''rtshell
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 Function objects for actions that can be performed using rtctree.
00017 
00018 '''
00019 
00020 
00021 import sys
00022 
00023 import rtctree.exceptions
00024 import rtctree.path
00025 
00026 import option_store
00027 import rts_exceptions
00028 
00029 
00030 ###############################################################################
00031 ## Base action function object
00032 
00033 class Action(object):
00034     '''Base class for all action function objects.
00035 
00036     Action objects should implement the _execute method. This will receive one
00037     argument (a reference to the RTCTree object) and should implement the
00038     action. It must return True for success or False for failure, and a very
00039     brief error message.
00040 
00041     All actions must be provided with one or more result callback objects.
00042     These will be called in the order they are set after performing the action
00043     and passed the result of the action's _execute method. Its job is to take
00044     appropriate measures based on the outcome of the action. Typically, the
00045     first should perform a verification that the result meets necessary
00046     criteria, such as a required action succeeding. If no callbacks are
00047     provided, a default (@ref BaseCallback) will be inserted.
00048 
00049     Action objects must implement the __str__ method. They should print out a
00050     description of what they will do. This description should include details
00051     specific to that instance of the action (for example, "Will activate
00052     component 'ConsoleIn0.rtc'").
00053 
00054     '''
00055 
00056     def __init__(self, callbacks=[]):
00057         super(Action, self).__init__()
00058         self._callbacks = callbacks
00059 
00060     def __call__(self, rtctree=None):
00061         result, err = self._execute(rtctree)
00062         if not self._callbacks:
00063             c = BaseCallback()
00064             c(result, err)
00065         else:
00066             for c in self._callbacks:
00067                 c(result, err)
00068 
00069     def __str__(self):
00070         return 'Base action'
00071 
00072     def add_callback(self, callback):
00073         self._callbacks.append(callback)
00074 
00075     @property
00076     def optional(self):
00077         '''Is this action optional?'''
00078         for cb in self._callbacks:
00079             if cb.__class__ == RequiredActionCB:
00080                 return False
00081         return True
00082 
00083     def _action_string(self, action_desc):
00084         if self._callbacks:
00085             action_desc += ' ({0}'.format(self._callbacks[0])
00086             for c in self._callbacks[1:]:
00087                 action_desc += ', {0}'.format(c)
00088             action_desc += ')'
00089         return action_desc
00090 
00091     def _execute(self, rtctree):
00092         '''Base for action execution method.
00093 
00094         Return (True, '') or (False, 'Why I failed.') when implementing this
00095         method.
00096 
00097         '''
00098         raise NotImplementedError
00099 
00100 
00101 ###############################################################################
00102 ## Base callback
00103 
00104 class BaseCallback(object):
00105     '''Base class for callback objects.
00106 
00107     Callback objects must implement the __call__ method, and receive two
00108     values:
00109     - A boolean indicating success or failure of the action.
00110     - An error message to optionally be printed on failure. None if no message.
00111 
00112     '''
00113     def __init__(self, *args, **kwargs):
00114         super(BaseCallback, self).__init__()
00115 
00116     def __call__(self, result, err_msg):
00117         if err_msg:
00118             if not result:
00119                 print >>sys.stderr, 'Action failed: ' + err_msg
00120         else:
00121             if not result:
00122                 print >>sys.stderr, 'Action failed.'
00123 
00124     def __str__(self):
00125         return ''
00126 
00127 
00128 ###############################################################################
00129 ## Required action callback
00130 
00131 class RequiredActionCB(BaseCallback):
00132     '''Callback for a required action.
00133 
00134     Checks the action result and raises @ref RequiredActionFailedError if the
00135     action failed.
00136 
00137     '''
00138     def __init__(self, *args, **kwargs):
00139         super(RequiredActionCB, self).__init__(*args, **kwargs)
00140 
00141     def __call__(self, result, err_msg):
00142         if not result:
00143             raise rts_exceptions.RequiredActionFailedError(err_msg)
00144 
00145     def __str__(self):
00146         return 'Required'
00147 
00148 
00149 ###############################################################################
00150 ## Check if a required component is present
00151 
00152 class CheckForRequiredCompAct(Action):
00153     '''Check for a required component in the RTC Tree.
00154 
00155     This action checks the rtctree to see if a component is present at a
00156     particular path. If it finds a component at that path, it will check that
00157     the component's ID and instance name to ensure it is the desired component.
00158     If the component is not present or is the wrong component, this action will
00159     fail. Otherwise, it will succeed.
00160 
00161     '''
00162     def __init__(self, path_str, id, instance_name, callbacks=[]):
00163         super(CheckForRequiredCompAct, self).__init__(callbacks=callbacks)
00164         self._path_str = path_str
00165         self._path = rtctree.path.parse_path(path_str)[0]
00166         self._id = id
00167         self._instance_name = instance_name
00168 
00169     def __str__(self):
00170         return self._action_string('Check for required component \
00171 "{0}", "{1}" at path {2}'.format(self._id, self._instance_name,
00172                 self._path_str))
00173 
00174     def _execute(self, rtctree):
00175         if option_store.OptionStore().verbose:
00176             print >>sys.stderr, 'Checking for required component {0} with ID \
00177 "{1}" and instance name "{2}"'.format(self._path_str, self._id,
00178                     self._instance_name)
00179         # Check there is a component at the specified path
00180         comp = rtctree.get_node(self._path)
00181         if not comp or not comp.is_component:
00182             return False, \
00183                     'Required component missing: {0}'.format(self._path_str)
00184         # Check the instance names match
00185         if comp.instance_name != self._instance_name:
00186             return False, 'Component instance names mismatched: {0} != \
00187 {1}'.format(comp.instance_name, self._instance_name)
00188         # Check the IDs match - in rtctree, the ID is formed from like so:
00189         # 'RTC:'<vendor>:<category>:<type_name>:<version>
00190         id = 'RTC:{0}:{1}:{2}:{3}'.format(comp.vendor, comp.category,
00191                                           comp.type_name, comp.version)
00192         if id != self._id:
00193             return False, 'Component IDs mismatched: {0} != {1}'.format(id,
00194                     self._id)
00195         # All good
00196         return True, None
00197 
00198 
00199 ###############################################################################
00200 ## Check if a port exists on a component
00201 
00202 class CheckForPortAct(Action):
00203     '''Check for a port on a component in the RTC Tree.
00204 
00205     This action checks the rtctree to see if a component is present at a
00206     particular path. If it finds a component at that path, it will check that
00207     the component has the desired port. If the port is not present on the
00208     component, it will fail. Otherwise, it will succeed. No check is performed
00209     to ensure that the correct component is at that path; for that, use the
00210     @ref CheckForRequiredCompAct action.
00211 
00212     This action will not fail if the specified component does not exist or is
00213     incorrect. To cause an abort in these situations, use @ref
00214     CheckForRequiredCompAct.
00215 
00216     '''
00217     def __init__(self, path_str, port_name, callbacks=[]):
00218         super(CheckForPortAct, self).__init__(callbacks=callbacks)
00219         self._path_str = path_str
00220         self._path = rtctree.path.parse_path(path_str)[0]
00221         self._port_name = port_name
00222 
00223     def __str__(self):
00224         return self._action_string('Check for required port "{0}" on \
00225 component at path {1}'.format(self._port_name, self._path_str))
00226 
00227     def _execute(self, rtctree):
00228         if option_store.OptionStore().verbose:
00229             print >>sys.stderr, 'Checking for required port {0} on component \
00230 {1}'.format(self._port_name, self._path_str)
00231         # Get the component at the specified path
00232         comp = rtctree.get_node(self._path)
00233         if not comp or not comp.is_component:
00234             return True, None
00235         # Check for the port
00236         if not comp.has_port_by_name(self._port_name):
00237             return False, \
00238                     'Required port not found: {0}'.format(self._port_name)
00239         # All good
00240         return True, None
00241 
00242 
00243 ###############################################################################
00244 ## Check the active configuration set of a component.
00245 
00246 class CheckActiveConfigSetAct(Action):
00247     '''Checks if a configuration set is active in a component.
00248 
00249     This action checks if the active configuration set of a component is as
00250     expected. It will check if the set exists first; if no such set exists,
00251     the action will fail.
00252 
00253     This action will not fail if the specified component does not exist or is
00254     incorrect. To cause an abort in these situations, use @ref
00255     CheckForRequiredCompAct.
00256 
00257     '''
00258     def __init__(self, path_str, set, callbacks=[]):
00259         super(CheckActiveConfigSetAct, self).__init__(callbacks=callbacks)
00260         self._path_str = path_str
00261         self._path = rtctree.path.parse_path(path_str)[0]
00262         self._set = str(set) # Cannot send unicode strings to CORBA
00263 
00264     def __str__(self):
00265         return self._action_string('Check configuration set "{0}" is active '\
00266                 'on component {1}'.format(self._set, self._path_str))
00267 
00268     def _execute(self, rtctree):
00269         if option_store.OptionStore().verbose:
00270             print >>sys.stderr, 'Checking configuration set "{0}" is active '\
00271                     'on component {1}'.format(self._set, self._path_str)
00272         comp = rtctree.get_node(self._path)
00273         if not comp or not comp.is_component:
00274             return False, 'Component missing: {0}'.format(self._path_str)
00275         if comp.active_conf_set_name != self._set:
00276             return False, 'Wrong configuration set is active on {0} '\
00277                     '(Active set: {1})'.format(self._path_str,
00278                             comp.active_conf_set_name)
00279         return True, None
00280 
00281 
00282 ###############################################################################
00283 ## Set the active configuration set of a component
00284 
00285 class SetActiveConfigSetAct(Action):
00286     '''Set the active configuration set of a component.
00287 
00288     This action sets the active configuration set of a component to the
00289     specified configuration set. It will check if the set exists first; if no
00290     such set exists, the action will fail.
00291 
00292     This action will not fail if the specified component does not exist or is
00293     incorrect. To cause an abort in these situations, use @ref
00294     CheckForRequiredCompAct.
00295 
00296     '''
00297     def __init__(self, path_str, set, callbacks=[]):
00298         super(SetActiveConfigSetAct, self).__init__(callbacks=callbacks)
00299         self._path_str = path_str
00300         self._path = rtctree.path.parse_path(path_str)[0]
00301         self._set = str(set) # Cannot send unicode strings to CORBA
00302 
00303     def __str__(self):
00304         return self._action_string('Set configuration set "{0}" active on \
00305 component at path {1}'.format(self._set, self._path_str))
00306 
00307     def _execute(self, rtctree):
00308         if option_store.OptionStore().verbose:
00309             print >>sys.stderr, 'Setting configuration set "{0}" active on \
00310 component {1}'.format(self._set, self._path_str)
00311         comp = rtctree.get_node(self._path)
00312         if not comp or not comp.is_component:
00313             return False, 'Component missing: {0}'.format(self._path_str)
00314         try:
00315             comp.activate_conf_set(self._set)
00316         except rts_exceptions.NoConfSetError:
00317             return False, 'Invalid configuration set: {0}'.format(self._set)
00318         return True, None
00319 
00320 
00321 ###############################################################################
00322 ## Set a configuration parameter in a configuration set
00323 
00324 class CheckConfigParamAct(Action):
00325     '''Check the value of a configuration parameter.
00326 
00327     This action checks that the value of a configuration parameter is correct.
00328     It will fail if the set or the parameter does not exist.
00329 
00330     This action will not fail if the specified component does not exist or is
00331     incorrect. To cause an abort in these situations, use @ref
00332     CheckForRequiredCompAct.
00333 
00334     '''
00335     def __init__(self, path_str, set, param, value, callbacks=[]):
00336         super(CheckConfigParamAct, self).__init__(callbacks=callbacks)
00337         self._path_str = path_str
00338         self._path = rtctree.path.parse_path(path_str)[0]
00339         self._set = str(set) # Cannot send unicode strings to CORBA
00340         self._param = str(param)
00341         self._value = str(value)
00342 
00343     def __str__(self):
00344         return self._action_string('Check parameter "{0}" in set "{1}" on '\
00345                 'component at path "{2}" is "{3}"'.format(self._param,
00346                     self._set, self._path_str, self._value))
00347 
00348     def _execute(self, rtctree):
00349         if option_store.OptionStore().verbose:
00350             print >>sys.stderr, 'Checking parameter "{0}" in set "{1}" on '\
00351                     'component "{2}" is "{3}"'.format(self._param, self._set,
00352                             self._path_str, self._value)
00353         comp = rtctree.get_node(self._path)
00354         if not comp or not comp.is_component:
00355             return False, 'Component missing: {0}'.format(self._path_str)
00356         if not self._set in comp.conf_sets:
00357             return False, 'Invalid configuration set: {0}'.format(self._set)
00358         if not comp.conf_sets[self._set].has_param(self._param):
00359             return False, 'Invalid configuration parameter: '\
00360                     '{0}'.format(self._param)
00361         if comp.conf_sets[self._set].data[self._param] != self._value:
00362             return False, 'Configuration parameter {0} in set {1} on '\
00363                     'component {2} is incorrect (value: {3})'.format(
00364                             self._param, self._set, self._path_str,
00365                             comp.conf_sets[self._set].data[self._param])
00366         return True, None
00367 
00368 
00369 ###############################################################################
00370 ## Set a configuration parameter in a configuration set
00371 
00372 class SetConfigParamValueAct(Action):
00373     '''Change the value of a configuration parameter in a set.
00374 
00375     This action sets the value of the given configuration parameter in the
00376     given configuration set. It will fail if the set does not exist, or the
00377     parameter does not exist in that set.
00378 
00379     This action will not fail if the specified component does not exist or is
00380     incorrect. To cause an abort in these situations, use @ref
00381     CheckForRequiredCompAct.
00382 
00383     '''
00384     def __init__(self, path_str, set, parameter, new_value, callbacks=[]):
00385         super(SetConfigParamValueAct, self).__init__(callbacks=callbacks)
00386         self._path_str = path_str
00387         self._path = rtctree.path.parse_path(path_str)[0]
00388         self._set = str(set) # Cannot send unicode strings to CORBA
00389         self._param = str(parameter)
00390         self._new_value = str(new_value)
00391 
00392     def __str__(self):
00393         return self._action_string('Set parameter "{0}" in set "{1}" on \
00394 component at path {2} to "{3}"'.format(self._param, self._set,
00395                 self._path_str, self._new_value))
00396 
00397     def _execute(self, rtctree):
00398         if option_store.OptionStore().verbose:
00399             print >>sys.stderr, 'Setting parameter "{0}" in set "{1}" on \
00400 component at path {2} to "{3}"'.format(self._param, self._set,
00401                     self._path_str, self._new_value)
00402         comp = rtctree.get_node(self._path)
00403         if not comp or not comp.is_component:
00404             return False, 'Component missing: {0}'.format(self._path_str)
00405         try:
00406             comp.set_conf_set_value(self._set, self._param, self._new_value)
00407         except rts_exceptions.NoConfSetError:
00408             return False, 'Invalid configuration set: {0}'.format(self._set)
00409         except rts_exceptions.NoSuchConfParamError:
00410             return False, 'Invalid configuration parameter: {0}'.format(self._param)
00411         comp.reparse_conf_sets()
00412         if self._set == comp.active_conf_set_name:
00413             comp.activate_conf_set(self._set)
00414         return True, None
00415 
00416 
00417 ###############################################################################
00418 ## Check if a connection between two components exists and is correct
00419 
00420 class CheckForConnAct(Action):
00421     '''Check for a correct connection between two components.
00422 
00423     This action checks if there is a connection between the specified source
00424     and destination ports. If there is, it will check that any given properties
00425     are also correct.
00426 
00427     No check is performed to ensure that the correct component is at that path;
00428     for that, use the @ref CheckForRequiredCompAct action.
00429 
00430     This action will not fail if the specified component does not exist or is
00431     incorrect. To cause an abort in these situations, use @ref
00432     CheckForRequiredCompAct.
00433 
00434     '''
00435     def __init__(self, source, dest, id, props={}, callbacks=[]):
00436         super(CheckForConnAct, self).__init__(callbacks=callbacks)
00437         self._source = source
00438         self._s_path = rtctree.path.parse_path(self._source[0])[0]
00439         self._dest = dest
00440         self._d_path = rtctree.path.parse_path(self._dest[0])[0]
00441         self._id = id
00442         self._props = props
00443 
00444     def __str__(self):
00445         return self._action_string('Check for connection from {0}:{1} to ' \
00446                 '{2}:{3} with properties {4}'.format(self._source[0],
00447                     self._source[1], self._dest[0], self._dest[1],
00448                     self._props))
00449 
00450     def _execute(self, rtctree):
00451         if option_store.OptionStore().verbose:
00452             print 'Checking for connection between {0}:{1} and ' \
00453                     '{2}:{3}'.format(self._source[0], self._source[1],
00454                             self._dest[0], self._dest[1])
00455         # Get the source component
00456         s_comp = rtctree.get_node(self._s_path)
00457         if not s_comp or not s_comp.is_component:
00458             return False, 'Source component missing: {0}'.format(\
00459                     self._source[0])
00460         s_port = s_comp.get_port_by_name(self._source[1])
00461         if not s_port:
00462             return False, 'Source port missing: {0}:{1}'.format(\
00463                     self._source[0], self._source[1])
00464         # Get the destination component
00465         d_comp = rtctree.get_node(self._d_path)
00466         if not d_comp or not d_comp.is_component:
00467             return False, 'Destination component missing: {0}'.format(\
00468                     self._dest[0])
00469         d_port = d_comp.get_port_by_name(self._dest[1])
00470         if not d_port:
00471             return False, 'Destination port missing: {0}:{1}'.format(\
00472                     self._dest[0], self._dest[1])
00473 
00474         conn = s_port.get_connection_by_id(self._id)
00475         if not conn:
00476             # No connection: fail
00477             return False, 'No connection between {0}:{1} and {2}:{3}'.format(
00478                     self._source[0], self._source[1], self._dest[0],
00479                     self._dest[1])
00480         conn = d_port.get_connection_by_id(self._id)
00481         if not conn:
00482             # No connection: fail
00483             return False, 'No connection between {0}:{1} and {2}:{3}'.format(
00484                     self._source[0], self._source[1], self._dest[0],
00485                     self._dest[1])
00486         # Check the properties
00487         for k in self._props:
00488             if self._props[k] != conn.properties[k]:
00489                 return False, 'Property {0} of connection from {1}:{2} to '\
00490                         '{3}:{4} is incorrect.'.format(k, self._source[0],
00491                                 self._source[1], self._dest[0], self._dest[1])
00492 
00493         # All good
00494         return True, None
00495 
00496 
00497 ###############################################################################
00498 ## Connect two ports
00499 
00500 class ConnectPortsAct(Action):
00501     '''Connect two ports together.
00502 
00503     This action connects two ports together using the provided connection
00504     profile. It will fail if either the components or the ports ports are not
00505     present. No check is made to ensure the components at the specified paths
00506     are the correct components.
00507 
00508     '''
00509     def __init__(self, source_path, source_port, dest_path, dest_port,
00510                  name, id, properties, callbacks=[]):
00511         super(ConnectPortsAct, self).__init__(callbacks=callbacks)
00512         self._source_path_str = source_path
00513         self._source_path = rtctree.path.parse_path(source_path)[0]
00514         self._source_port = source_port
00515         self._dest_path_str = dest_path
00516         self._dest_path = rtctree.path.parse_path(dest_path)[0]
00517         self._dest_port = dest_port
00518         self._name = name
00519         self._id = id
00520         self._properties = properties.copy()
00521 
00522     def __str__(self):
00523         return self._action_string('Connect {0}:{1} to {2}:{3} with \
00524 ID {4} and properties {5}'.format(self._source_path_str, self._source_port,
00525                 self._dest_path_str, self._dest_port, self._id,
00526                 self._properties))
00527 
00528     def _execute(self, rtctree):
00529         if option_store.OptionStore().verbose:
00530             print >>sys.stderr, 'Connect {0}:{1} to {2}:{3} with \
00531 ID {4} and properties {5}'.format(self._source_path_str, self._source_port,
00532                     self._dest_path_str, self._dest_port, self._id,
00533                     self._properties)
00534         source_comp = rtctree.get_node(self._source_path)
00535         if not source_comp or not source_comp.is_component:
00536             return False, 'Source component missing: {0}'.format(\
00537                     self._source_path_str)
00538         s_port = source_comp.get_port_by_name(self._source_port)
00539         if not s_port:
00540             return False, 'Source port missing: {0}:{1}'.format(\
00541                     self._source_path_str, self._source_port)
00542         dest_comp = rtctree.get_node(self._dest_path)
00543         if not dest_comp or not dest_comp.is_component:
00544             return False, 'Destination component missing: {0}'.format(\
00545                     self._dest_path_str)
00546         d_port = dest_comp.get_port_by_name(self._dest_port)
00547         if not d_port:
00548             return False, 'Destination port missing: {0}:{1}'.format(\
00549                     self._dest_path_str, self._dest_port)
00550 
00551         conn = s_port.get_connection_by_id(self._id)
00552         if not conn:
00553             if d_port.get_connection_by_id(self._id) is None:
00554                 # No existing connection
00555                 s_port.connect([d_port], name=self._name, id=self._id,
00556                                         props=self._properties)
00557                 return True, None
00558             else:
00559                 # The destination port has a connection with that ID but
00560                 # different ports.
00561                 return False, \
00562                     'Destination port has existing connection with ID {0}'.format(
00563                             self._id)
00564         else:
00565             if len(conn.ports) != 2 or not conn.has_port(d_port):
00566                 # The source port has a connection with that ID but different
00567                 # ports.
00568                 return False, \
00569                     'Source port has existing connection with ID {0}'.format(
00570                             self._id)
00571             else:
00572                 # The connection already exists - check the properties match
00573                 for k in self._properties:
00574                     if self._properties[k] != conn.properties[k]:
00575                         return False, \
00576                                 'Property {0} of existing connection from '\
00577                                 '{1}:{2} to {3}:{4} with ID {5} does not '\
00578                                 'match'.format(k, self._source_path_str,
00579                                         self._source_port, self._dest_path_str,
00580                                         self._dest_port, self._id)
00581                 if option_store.OptionStore().verbose:
00582                     print >>sys.stderr, \
00583                             'Skipped existing connection with ID {0}'.format(
00584                                     self._id)
00585                 return True, None
00586 
00587 
00588 ###############################################################################
00589 ## Disconnect two data ports
00590 
00591 class DisconnectPortsAct(Action):
00592     '''Disconnect two ports.
00593 
00594     This action disconnects two ports. It will fail if either the components or
00595     the ports ports are not present. No check is made to ensure the components
00596     at the specified paths are the correct components.
00597 
00598     '''
00599     def __init__(self, source_path, source_port, dest_path, dest_port, id,
00600                  callbacks=[]):
00601         super(DisconnectPortsAct, self).__init__(callbacks=callbacks)
00602         self._source_path_str = source_path
00603         self._source_path = rtctree.path.parse_path(source_path)[0]
00604         self._source_port = source_port
00605         self._dest_path_str = dest_path
00606         self._dest_path = rtctree.path.parse_path(dest_path)[0]
00607         self._dest_port = dest_port
00608         self._id = id
00609 
00610     def __str__(self):
00611         return self._action_string('Disconnect {0}:{1} from {2}:{3} with ID {4}'.format(\
00612                 self._source_path_str, self._source_port, self._dest_path_str,
00613                 self._dest_port, self._id))
00614 
00615     def _execute(self, rtctree):
00616         if option_store.OptionStore().verbose:
00617             print >>sys.stderr, \
00618                     'Disconnecting {0}:{1} from {2}:{3} with ID {4}'.format(\
00619                     self._source_path_str, self._source_port,
00620                     self._dest_path_str, self._dest_port, self._id)
00621         source_comp = rtctree.get_node(self._source_path)
00622         if not source_comp or not source_comp.is_component:
00623             return False, 'Source component missing: {0}'.format(\
00624                     self._source_path_str)
00625         source_port_obj = source_comp.get_port_by_name(self._source_port)
00626         if not source_port_obj:
00627             return False, 'Source port missing: {0}:{1}'.format(\
00628                     self._source_path_str, self._source_port)
00629         dest_comp = rtctree.get_node(self._dest_path)
00630         if not dest_comp or not dest_comp.is_component:
00631             return False, 'Destination component missing: {0}'.format(\
00632                     self._dest_path_str)
00633         dest_port_obj = dest_comp.get_port_by_name(self._dest_port)
00634         if not dest_port_obj:
00635             return False, 'Destination port missing: {0}:{1}'.format(\
00636                     self._dest_path_str, self._dest_port)
00637 
00638         s_conn = source_port_obj.get_connection_by_id(self._id)
00639         if not s_conn:
00640             return False, 'No connection from {0}:{1} with ID {2}'.format(
00641                     self._source_path_str, self._source_port, self._id)
00642         d_conn = dest_port_obj.get_connection_by_id(self._id)
00643         if not d_conn:
00644             return False, 'No connection to {0}:{1} with ID {2}'.format(
00645                     self._dest_path_str, self._dest_port, self._id)
00646         s_conn.disconnect()
00647         return True, None
00648 
00649 
00650 ###############################################################################
00651 ## State change base action
00652 
00653 class StateChangeAct(Action):
00654     '''Base action for actions that change a component's state.
00655 
00656     Actions that inherit from this should provide three members:
00657     - self._action_str: A string describing the action for use in str(). e.g.
00658       "Activate".
00659     - self._verbose_str: A similar string for use in the verbose output. e.g.
00660       "Activating".
00661     - self._action_impl: A function to be called by self._execute to perform
00662       the action. It will be passed two arguments; the first is the component
00663       node from rtctree, the second is the index of the execution context
00664       involved. This should return (True, None) or False and an error string.
00665 
00666     '''
00667     def __init__(self, path_str, comp_id, instance_name, ec_id, callbacks=[]):
00668         super(StateChangeAct, self).__init__(callbacks=callbacks)
00669         self._path_str = path_str
00670         self._comp_id = comp_id
00671         self._instance_name = instance_name
00672         self._path = rtctree.path.parse_path(path_str)[0]
00673         self._ec_id = ec_id
00674 
00675     def __str__(self):
00676         return self._action_string('{0} {1} in execution context {2}'.format(\
00677                 self._action_str, self._path_str, self._ec_id))
00678 
00679     @property
00680     def comp_id(self):
00681         '''Identification string of the component.'''
00682         return self._comp_id
00683 
00684     @property
00685     def ec_id(self):
00686         '''Target execution context ID.'''
00687         return self._ec_id
00688 
00689     @property
00690     def instance_name(self):
00691         '''Instance name of the target component.'''
00692         return self._instance_name
00693 
00694     @property
00695     def path(self):
00696         '''Full path of the target component.'''
00697         return self._path_str
00698 
00699     def _execute(self, rtctree):
00700         if option_store.OptionStore().verbose:
00701             print >>sys.stderr, '{0} {1} in {2}'.format(self._verbose_str,
00702                     self._path_str, self._ec_id)
00703         comp = rtctree.get_node(self._path)
00704         if not comp or not comp.is_component:
00705             return False, 'Component missing: {0}'.format(self._path_str)
00706         ec_index = comp.get_ec_index(int(self._ec_id))
00707         if ec_index < 0:
00708             return False, 'Invalid execution context: {0}'.format(self._ec_id)
00709         return self._action_impl(comp, ec_index)
00710 
00711 
00712 ###############################################################################
00713 ## Check component state
00714 
00715 class CheckCompStateAct(StateChangeAct):
00716     '''Check component state in an execution context.
00717 
00718     This action checks that the state of an execution context is as expected.
00719 
00720     '''
00721     def __init__(self, path_str, comp_id, instance_name, ec_id, expected,
00722             callbacks=[]):
00723         super(CheckCompStateAct, self).__init__(path_str, comp_id,
00724                 instance_name, ec_id, callbacks=callbacks)
00725         self._expected = expected
00726         self._action_str = 'Check state is {0} for'.format(self._expected)
00727         self._verbose_str = 'Checking state is {0} for'.format(self._expected)
00728 
00729     def _action_impl(self, comp, ec_index):
00730         if (self._expected.lower() == 'active' and \
00731                 comp.state_in_ec(ec_index) == comp.ACTIVE) or \
00732             (self._expected.lower() == 'inactive' and \
00733                 comp.state_in_ec(ec_index) == comp.INACTIVE) or \
00734             (self._expected.lower() == 'error' and \
00735                 comp.state_in_ec(ec_index) == comp.ERROR) or \
00736             (self._expected.lower() == 'created' and \
00737                 comp.state_in_ec(ec_index) == comp.CREATED) or \
00738             (self._expected.lower() == 'unknown' and \
00739                 comp.state_in_ec(ec_index) == comp.UNKNOWN):
00740             return True, None
00741         return False, 'Component {0} is in incorrect state {1}'.format(
00742                 self._path_str,
00743                 comp.get_state_in_ec_string(ec_index, add_colour=False))
00744 
00745 
00746 ###############################################################################
00747 ## Activate a component
00748 
00749 class ActivateCompAct(StateChangeAct):
00750     '''Activate a component.
00751 
00752     This action changes the status of a component to active.
00753 
00754     '''
00755     def __init__(self, path_str, comp_id, instance_name, ec_id, callbacks=[]):
00756         super(ActivateCompAct, self).__init__(path_str, comp_id, instance_name,
00757                 ec_id, callbacks=callbacks)
00758         self._action_str = 'Activate'
00759         self._verbose_str = 'Activating'
00760 
00761     def _action_impl(self, comp, ec_index):
00762         comp.activate_in_ec(ec_index)
00763         return True, None
00764 
00765 
00766 ###############################################################################
00767 ## Deactivate a component
00768 
00769 class DeactivateCompAct(StateChangeAct):
00770     '''Deactivate a component.
00771 
00772     This action changes the status of a component to inactive.
00773 
00774     '''
00775     def __init__(self, path_str, comp_id, instance_name, ec_id, callbacks=[]):
00776         super(DeactivateCompAct, self).__init__(path_str, comp_id,
00777                 instance_name, ec_id, callbacks=callbacks)
00778         self._action_str = 'Deactivate'
00779         self._verbose_str = 'Deactivating'
00780 
00781     def _action_impl(self, comp, ec_index):
00782         comp.deactivate_in_ec(ec_index)
00783         return True, None
00784 
00785 
00786 ###############################################################################
00787 ## Reset a component
00788 
00789 class ResetCompAct(StateChangeAct):
00790     '''Reset a component.
00791 
00792     This action changes the status of a component to inactive from error.
00793 
00794     '''
00795     def __init__(self, path_str, comp_id, instance_name, ec_id, callbacks=[]):
00796         super(ResetCompAct, self).__init__(path_str, comp_id, instance_name,
00797                 ec_id, callbacks=callbacks)
00798         self._action_str = 'Reset'
00799         self._verbose_str = 'Resetting'
00800 
00801     def _action_impl(self, comp, ec_index):
00802         comp.reset_in_ec(ec_index)
00803         return True, None
00804 
00805 
00806 # vim: tw=79
00807 


rtshell
Author(s): Geoffrey Biggs
autogenerated on Fri Aug 28 2015 12:55:12