Class: Syskit::Composition
Overview
Compositions, i.e. grouping of components and/or other compositions that perform a given function.
Compositions are used to regroup components and/or other compositions in functional groups.
See the Models::Composition for class-level methods
Defined Under Namespace
Classes: CompositionChildInstance
Constant Summary
Constants included from Models::Component
Models::Component::PROVIDES_ARGUMENTS
Instance Attribute Summary collapse
-
#child_selection ⇒ Object
readonly
A name => SelectedChild mapping of the selection result during #instanciate.
Attributes included from Models::Component
Attributes inherited from Component
#dynamics, #required_host, #requirements
Instance Method Summary collapse
-
#added_sink(child, mappings) ⇒ Object
Called when a new child is added to this composition.
-
#conf(names) ⇒ Object
Returns the configuration definition for the given configuration(s).
-
#dataflow_change_handler(ignore_missing_child, child, mappings) ⇒ Object
private
Helper for #added_child_object and #removing_child_object.
-
#executable? ⇒ Boolean
Overriden from Roby::Task.
-
#find_required_composition_child_from_role(role, from_model = self.model) ⇒ Component, ...
Returns a child from its role, as the composition model tells we should see it.
-
#initialize(options = Hash.new) ⇒ Composition
constructor
A new instance of Composition.
-
#port_by_name(name) ⇒ Syskit::Port
Finds the corresponding syskit port.
-
#removing_child(child) ⇒ Object
Hook called when one of the compositions' child has been removed.
-
#removing_sink(child) ⇒ Object
Called when a child is removed from this composition.
-
#required_composition_child_from_role(role) ⇒ Component, ...
Returns a child from its role, as the composition model tells we should see it.
- #resolve_port(port_name) ⇒ Object
-
#self_port_to_actual_port(exported_port) ⇒ Object
attribute is guaranteed to be an instance of TaskContext.
-
#self_port_to_orocos_port(exported_port) ⇒ Orocos::Port
Maps a port exported on this composition to the actual orocos port that it represents.
-
#to_instance_requirements ⇒ Syskit::InstanceRequirements
Generates the InstanceRequirements object that represents
self
best. - #update_requirements(new_requirements, name: nil, keep_abstract: false) ⇒ Object
- #updated_sink(child, mappings) ⇒ Object
Methods included from Models::Composition
add, add_child, add_main, add_main_task, add_optional, add_specialization_constraint, all_child, all_child_constraint, all_configuration, all_explicit_connection, all_exported_input, all_exported_output, applied_specializations, child, child_constraints, child_port?, children, children_names, clear_model, compute_child_dependency_options, configuration, configurations, connect, connections, constraints_for, create_dynamic_instantiation_context, create_private_specialization, dependency_injection_names, each_child, each_child_constraint, each_configuration, each_explicit_connection, each_exported_input, each_exported_output, each_input_port, each_output_port, explicit_connection, export, exported_input, exported_inputs, exported_output, exported_outputs, exported_port?, extract_grandchild_selections_by_child_name, find_applicable_specialization_from_selection, find_child, find_child_constraint, find_child_model_and_task, find_children_models_and_tasks, find_configuration, find_exported_input, find_exported_output, find_input_port, find_output_port, find_through_method_missing, fullfills?, has_child?, has_child_constraint?, has_configuration?, has_dynamic_input_port?, has_dynamic_output_port?, has_exported_input?, has_exported_output?, has_through_method_missing?, inherited, instanciate, instanciate_child, instanciate_connections, is_specialization?, main_task, merge, narrow, new_specialized_submodel, overload, parent_model_of?, prefer_specializations, pretty_print, promote_child, promote_explicit_connection, promote_exported_input, promote_exported_output, promote_exported_port, root_model, setup_submodel, specializations, specialize, specialized_children, specialized_on?, to_dot, try_resolve_child_references_in_use_flags, use
Methods included from Models::Component
#all_data_service, #all_dynamic_service, #all_stub_module, #apply_missing_dynamic_services_from, #as, #as_plan, #bind, #can_merge?, #clear_model, #component_model?, #compute_port_mappings, #concrete_model?, #connected?, #create_dynamic_instantiation_context, #create_private_specialization, #create_proxy_task, #create_proxy_task_model, #data_service, #data_services, #deregister_placeholder_model, #deregister_submodels, #driver_for, #dynamic_service, #dynamic_services, #each_com_bus_driver_service, #each_data_service, #each_dynamic_service, #each_input_port, #each_master_driver_service, #each_output_port, #each_port, #each_required_dynamic_service, #each_required_model, #each_root_data_service, #each_slave_data_service, #each_stub_module, #ensure_model_is_specialized, #find_all_data_services_from_type, #find_data_service_from_type, #find_directional_port_mapping, #find_input_port, #find_matching_service, #find_output_port, #find_placeholder_model, #find_port, #find_through_method_missing, #fullfills?, #has_through_method_missing?, #if_already_present, #implicit_fullfilled_model, #instanciate, #instanciate_dynamic_input_port, #instanciate_dynamic_output_port, #merge, #merge_service_model, #method_missing, #needs_stub?, #placeholder?, #port_mappings_for, #port_mappings_for_task, #prefer_deployed_tasks, #prepare_stub, #private_specialization=, #private_specialization?, #promote_data_service, #promote_dynamic_service, #provides, #provides_dynamic, #proxy_task_model, #register_placeholder_model, #require_dynamic_service, #resolve, #selected_for, #self_port?, #self_port_to_component_port, #specialization_counter, #specialize, #stub, #stub_module, #supermodel, #to_component_model, #try_bind, #try_resolve, #use_conf, #use_deployments, #with_arguments, #with_conf, #with_dynamic_service
Methods included from DataService
Methods included from Models::Base
#dependency_injection_names, #pretty_print, #short_name, #to_s
Methods included from Models::PortAccess
#each_input_port, #each_output_port, #each_port, #find_input_port, #find_output_port, #find_port, #find_through_method_missing, #has_dynamic_input_port?, #has_dynamic_output_port?, #has_input_port?, #has_output_port?, #has_port?, #has_through_method_missing?
Methods included from PortAccess
#each_input_port, #each_output_port, #each_port, #find_input_port, #find_output_port, #find_port, #find_through_method_missing, #has_input_port?, #has_output_port?, #has_port?, #has_through_method_missing?
Methods inherited from Component
#added_dynamic_service, #added_input_port_connection, #added_output_port_connection, #adding_input_port_connection, #adding_output_port_connection, #as, #bind, #can_be_deployed_by?, #can_finalize?, #can_merge?, #concrete_model, #configure, #connect_to, #create_fresh_copy, #data_accessor, #data_reader, #data_writer, #dependency_context, #deployment_hints, #duplicate_missing_services_from, #each_data_service, #each_dynamic_service, #each_fullfilled_model, #each_required_dynamic_service, #find_data_service, #find_data_service_from_type, #find_through_method_missing, #has_data_service?, #has_through_method_missing?, #initialize_copy, #meets_configurationg_precedence_constraints?, #merge, #perform_setup, #placeholder?, #ready_for_setup?, #removed_input_port_connection, #removed_output_port_connection, #removing_input_port_connection, #removing_output_port_connection, #require_dynamic_service, #self_port_to_component_port, #setting_up!, #setting_up?, #setup, #setup=, #setup?, #setup_failed!, #setup_successful!, #should_configure_after, #specialize, #specialized_model?, #start_only_when_connected?, #will_never_setup?
Constructor Details
#initialize(options = Hash.new) ⇒ Composition
Returns a new instance of Composition
20 21 22 23 |
# File 'lib/syskit/composition.rb', line 20 def initialize( = Hash.new) @child_selection = Hash.new super end |
Instance Attribute Details
#child_selection ⇒ Object (readonly)
A name => SelectedChild mapping of the selection result during #instanciate
27 28 29 |
# File 'lib/syskit/composition.rb', line 27 def child_selection @child_selection end |
Instance Method Details
#added_sink(child, mappings) ⇒ Object
Called when a new child is added to this composition.
It updates Flows::DataFlow#modified_tasks so that the engine can update the underlying task's connections
258 259 260 261 |
# File 'lib/syskit/composition.rb', line 258 def added_sink(child, mappings) # :nodoc: super dataflow_change_handler(false, child, mappings) end |
#conf(names) ⇒ Object
Returns the configuration definition for the given configuration(s)
Note that unlike ConfigurationManager, only one configuration can be selected (they cannot be overlaid on top of each other)
The returned value is a mapping from child names to the configurations that should be applied to them, i.e. for the 'narrow' configuration used as an example in Composition.conf,
conf(['narrow'])
would return
'monitoring' => ['default', 'narrow_window'],
'sonar' => ['default', 'narrow_window']
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/syskit/composition.rb', line 45 def conf(names) if names.size != 1 raise ArgumentError, "unlike with ConfigurationManager, only one configuration can be selected on compositions" end result = Hash.new found_something = false model.each_configuration(names.first.to_s, false) do |values| found_something = true result = values.merge(result) end if !found_something if names == ['default'] ConfigurationManager.info "required default configuration on composition #{task}, but #{task.model.short_name} has no registered default configurations" return result else raise ArgumentError, "#{self} has no declared configuration called #{names.join(", ")}" end end result end |
#dataflow_change_handler(ignore_missing_child, child, mappings) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Helper for #added_child_object and #removing_child_object
It adds the task to Flows::DataFlow#modified_tasks whenever the DataFlow relations is changed in a way that could require changing the underlying Orocos components connections.
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
# File 'lib/syskit/composition.rb', line 207 def dataflow_change_handler(ignore_missing_child, child, mappings) # :nodoc: # The case where 'child' is already a task context is already # taken care of by mappings.each_key do |source_port, sink_port| component = begin find_port(source_port).to_actual_port.component rescue Roby::NoSuchChild raise if !ignore_missing_child end if component relation_graph_for(Flows::DataFlow).modified_tasks << component end end end |
#executable? ⇒ Boolean
Overriden from Roby::Task
will return false if any of the children is not executable.
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
# File 'lib/syskit/composition.rb', line 179 def executable? # :nodoc: if !super return false elsif @executable return true end each_child do |child_task, _| if child_task.kind_of?(TaskContext) if !child_task.orocos_task return false end elsif child_task.kind_of?(Component) && child_task.start_event.root? if !child_task.executable? return false end end end return true end |
#find_required_composition_child_from_role(role, from_model = self.model) ⇒ Component, ...
Returns a child from its role, as the composition model tells we should see it
Generally speaking, if the composition model requires a data service, this service is going to be returned instead of the whole task
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/syskit/composition.rb', line 134 def find_required_composition_child_from_role(role, from_model = self.model) selected = child_selection[role] return if !selected # Check what the child is made of ... We might not have to # return a service task = find_child_from_role(role) return if !task target_child_model = from_model.find_child(role) if target_srv = target_child_model.service service_selections = [selected.service_selection] child_model = self.model.find_child(role) while !from_model.fullfills?(child_model.composition_model) service_selections.unshift child_model.overload_info.service_selection child_model = child_model.parent_model end selected_service_m = service_selections.inject(target_srv) do |srv, selections| if selected_srv = selections[srv.model] if task.model <= selected_srv.component_model selected_srv else selected_srv.as_real_model end else break srv end end return selected_service_m.bind(task).as(target_srv.model) else return task end end |
#port_by_name(name) ⇒ Syskit::Port
Finds the corresponding syskit port
119 120 121 122 123 124 |
# File 'lib/syskit/composition.rb', line 119 def port_by_name(name) if p = find_input_port(name) || find_output_port(name) p else raise ArgumentError, "#{self} has no port called #{name}, known ports are: #{each_port.map(&:name).sort.join(", ")}" end end |
#removing_child(child) ⇒ Object
Hook called when one of the compositions' child has been removed
If self has exported ports, this broke some connections (the exported ports are not “internally connected” anymore) and as such the corresponding tasks should be added to modified_tasks
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 |
# File 'lib/syskit/composition.rb', line 228 def removing_child(child) super dataflow_graph = relation_graph_for(Flows::DataFlow) if dataflow_graph.has_edge?(child, self) # output ports, we only need to make sure that the dataflow # handlers are called dataflow_graph.remove_relation(child, self) end if dataflow_graph.has_edge?(self, child) # This one is harder, we need to explicitely add the sources # because none of the other triggers will work # # Note that merging and dependency injection can cause a child # to have a non-forwarding connection to the composition. We # can't assume that the edges from self to child are all forwarding # (input-to-input) dataflow_graph.edge_info(self, child).each_key do |self_port_name, child_port_name| if (self_port = find_input_port(self_port_name)) self_port.each_concrete_connection do |source_port| dataflow_graph.modified_tasks << source_port.component end end end end end |
#removing_sink(child) ⇒ Object
Called when a child is removed from this composition.
It updates Flows::DataFlow#modified_tasks so that the engine can update the underlying task's connections
272 273 274 275 |
# File 'lib/syskit/composition.rb', line 272 def removing_sink(child) # :nodoc: super dataflow_change_handler(true, child, self[child, Flows::DataFlow]) end |
#required_composition_child_from_role(role) ⇒ Component, ...
Returns a child from its role, as the composition model tells we should see it
Generally speaking, if the composition model requires a data service, this service is going to be returned instead of the whole task
168 169 170 171 172 173 174 |
# File 'lib/syskit/composition.rb', line 168 def required_composition_child_from_role(role) selected = find_required_composition_child_from_role(role) if !selected raise ArgumentError, "#{role} does not seem to be a proper child of this composition" end selected end |
#resolve_port(port_name) ⇒ Object
67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/syskit/composition.rb', line 67 def resolve_port(port_name) export = model.find_exported_input(port_name) || model.find_exported_output(port_name) child_name = export.component_model.child_name if child = find_child_from_role(child_name) actual_port_name = child_selection[child_name].port_mappings[export.name] if child.respond_to?(:resolve_port) child.resolve_port(actual_port_name) else child.find_port(actual_port_name) end end end |
#self_port_to_actual_port(exported_port) ⇒ Object
attribute is guaranteed to be an instance of TaskContext
86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/syskit/composition.rb', line 86 def self_port_to_actual_port(exported_port) port_name = exported_port.name export = model.find_exported_input(port_name) || model.find_exported_output(port_name) child_name = export.component_model.child_name child = child_from_role(child_name) actual_port_name = child_selection[child_name].port_mappings[export.name] child.find_port(actual_port_name).to_actual_port end |
#self_port_to_orocos_port(exported_port) ⇒ Orocos::Port
Maps a port exported on this composition to the actual orocos port that it represents
103 104 105 |
# File 'lib/syskit/composition.rb', line 103 def self_port_to_orocos_port(exported_port) self_port_to_actual_port(exported_port).to_orocos_port end |
#to_instance_requirements ⇒ Syskit::InstanceRequirements
Generates the InstanceRequirements object that represents self
best
281 282 283 284 285 286 287 288 289 |
# File 'lib/syskit/composition.rb', line 281 def to_instance_requirements req = super use_flags = Hash.new model.each_child do |child_name, _| use_flags[child_name] = required_composition_child_from_role(child_name).to_instance_requirements end req.use(use_flags) req end |
#update_requirements(new_requirements, name: nil, keep_abstract: false) ⇒ Object
107 108 109 110 111 112 113 |
# File 'lib/syskit/composition.rb', line 107 def update_requirements(new_requirements, name: nil, keep_abstract: false) super new_requirements.dynamics.ports.each do |port_name, info| find_port(port_name).to_actual_port.component. requirements.dynamics.add_port_info(port_name, info) end end |
#updated_sink(child, mappings) ⇒ Object
263 264 265 266 |
# File 'lib/syskit/composition.rb', line 263 def updated_sink(child, mappings) super dataflow_change_handler(false, child, mappings) end |