class Syskit::Models::BoundDataService

Representation of a data service as provided by a component model

Instances of this class are usually created by {Models::Component#provides}. Note that bound dynamic services are instances of {BoundDynamicDataService} instead.

At the component instance level, each {Models::BoundDataService} is represented by a corresponding {Syskit::BoundDataService}, whose {Syskit::BoundDataService#model} method returns this object. This instance-level object is created with {#bind}

Bound data services are promoted from one component model to its submodels, which means that when one does

bound_m = task_m.test_srv
sub_m = task_m.mew_submodel
sub_bound_m = bound_m.test_srv

Then sub_bound_m != bound_m as sub_bound_m is bound to sub_m and bound_m is bound to task_m. Use {#same_service?} to check whether two services are different promoted version of the same original service

Constants

DRoby

Attributes

component_model[R]

The task model which provides this service

demoted[R]

The original service from which self has been promoted

See {BoundDataService} for more details on promotion

full_name[R]

The service's full name, i.e. the name with which it is referred to in the task model

master[R]

The master service (if there is one)

model[R]

The service model

name[R]

The service name

port_mappings[R]

The mappings needed between the ports in the service interface and the actual ports on the component

Public Class Methods

new(name, component_model, master, model, port_mappings) click to toggle source
# File lib/syskit/models/bound_data_service.rb, line 74
def initialize(name, component_model, master, model, port_mappings)
    @name, @component_model, @master, @model, @port_mappings =
        name, component_model, master, model, port_mappings

    @full_name =
        if master
            "#{master.name}.#{name}"
        else
            name
        end

    @demoted = self
end

Public Instance Methods

==(other) click to toggle source
# File lib/syskit/models/bound_data_service.rb, line 63
def ==(other)
    eql?(other)
end
as(service_model) click to toggle source

Returns a view of this service as a provider of service_model

It allows to transparently apply port mappings as if self was a service of type service_model

The original state of self (before as was called) can be retrieved by calling {as_real_model} on the returned value

@return [BoundDataService]

# File lib/syskit/models/bound_data_service.rb, line 184
def as(service_model)
    result = dup
    result.instance_variable_set(:@model, service_model)

    mappings = port_mappings.dup
    mappings.delete_if do |srv, _|
        !service_model.fullfills?(srv)
    end
    result.instance_variable_set(:@port_mappings, mappings)
    result.ports.clear
    result
end
as_real_model() click to toggle source

Returns the actual bound data service when the receiver is the return value of {as}

@return [BoundDataService]

# File lib/syskit/models/bound_data_service.rb, line 201
def as_real_model
    component_model.find_data_service(full_name)
end
attach(new_component_model, verify: true) click to toggle source

Returns the bound data service object that represents self being attached to a new component model

# File lib/syskit/models/bound_data_service.rb, line 134
def attach(new_component_model, verify: true)
    if new_component_model == self
        return self
    elsif verify && !new_component_model.fullfills?(component_model)
        raise ArgumentError, "cannot attach #{self} on #{new_component_model}: does not fullfill #{component_model}"
    end

    # NOTE: do NOT use #find_data_service here ! find_data_service
    # NOTE: might require some promotion from parent models, which
    # NOTE: is done using #attach !
    result = dup
    result.instance_variable_set :@component_model, new_component_model
    result
end
bind(task) click to toggle source

Returns the BoundDataService object that binds this provided service to an actual task

@param [Component,Syskit::BoundDataService] task the component

that we should bind to. It can itself be a data service

@return [Syskit::BoundDataService]

# File lib/syskit/models/bound_data_service.rb, line 285
def bind(task)
    if task.model == self
        # !!! task is a BoundDataService
        return task
    elsif task.model <= component_model # This is stronger than #fullfills?
        Syskit::BoundDataService.new(task, self)
    elsif task.fullfills?(component_model)
        # Fullfills, but does not inherit ? component_model may be
        # a data service proxies
        if component_model.placeholder_task?
            base_model = component_model.superclass
            if base_model_srv = base_model.find_data_service(name)
                # The data service is from a concrete task model
                Syskit::BoundDataService.new(task, base_model_srv)
            else
                task.find_data_service_from_type(model)
            end
        # Or maybe we're dealing with dynamic service instanciation
        else
            resolved = task.find_data_service(name)
            if resolved && resolved.model.same_service?(self)
                return resolved
            else
                raise InternalError, "#{component_model} is fullfilled by #{task}, but is not inherited by its model #{task.model}. I didn't manage to resolve this, either as a task-to-placeholder mapping, or as a dynamic service"
            end
        end
    else
        raise ArgumentError, "cannot bind #{self} on #{task}: does not fullfill #{component_model}"
    end
end
connect_to(other, policy = Hash.new) click to toggle source
# File lib/syskit/models/bound_data_service.rb, line 149
def connect_to(other, policy = Hash.new)
    Syskit.connect(self, other, policy)
end
dependency_injection_names() click to toggle source
# File lib/syskit/models/bound_data_service.rb, line 54
def dependency_injection_names; Array.new end
droby_dump(peer) click to toggle source
# File lib/syskit/models/bound_data_service.rb, line 418
def droby_dump(peer)
    DRoby.new(name, peer.dump(component_model), peer.dump(master), peer.dump(model))
end
dynamic?() click to toggle source

True if this is a dynamic service

# File lib/syskit/models/bound_data_service.rb, line 50
def dynamic?; false end
each_data_service(&block) click to toggle source
# File lib/syskit/models/bound_data_service.rb, line 261
def each_data_service(&block)
    self
end
each_fullfilled_model(&block) click to toggle source
# File lib/syskit/models/bound_data_service.rb, line 270
def each_fullfilled_model(&block)
    model.each_fullfilled_model(&block)
end
each_input_port() { |find_input_port(name)| ... } click to toggle source
# File lib/syskit/models/bound_data_service.rb, line 125
def each_input_port
    return enum_for(:each_input_port) if !block_given?
    orogen_model.each_input_port do |p|
        yield(find_input_port(p.name))
    end
end
each_output_port() { |find_output_port(name)| ... } click to toggle source
# File lib/syskit/models/bound_data_service.rb, line 118
def each_output_port
    return enum_for(:each_output_port) if !block_given?
    orogen_model.each_output_port do |p|
        yield(find_output_port(p.name))
    end
end
each_required_model() { |model| ... } click to toggle source
# File lib/syskit/models/bound_data_service.rb, line 342
def each_required_model
    return enum_for(:each_required_model) if !block_given?
    yield(model)
end
each_slave_data_service(&block) click to toggle source

Enumerates the data services that are slave of this one

# File lib/syskit/models/bound_data_service.rb, line 266
def each_slave_data_service(&block)
    component_model.each_slave_data_service(self, &block)
end
eql?(other) click to toggle source
# File lib/syskit/models/bound_data_service.rb, line 56
def eql?(other)
    other.kind_of?(self.class) &&
        other.full_name == full_name &&
        other.model == model &&
        other.component_model == component_model
end
find_data_service(name) click to toggle source
# File lib/syskit/models/bound_data_service.rb, line 356
def find_data_service(name)
    component_model.each_slave_data_service(self) do |slave_m|
        if slave_m.name == name
            return slave_m
        end
    end
    nil
end
find_input_port(name) click to toggle source
# File lib/syskit/models/bound_data_service.rb, line 111
def find_input_port(name)
    name = name.to_str
    if (mapped = port_mappings_for_task[name]) && (port = component_model.find_input_port(mapped))
        ports[name] ||= InputPort.new(self, port.orogen_model, name)
    end
end
find_output_port(name) click to toggle source
# File lib/syskit/models/bound_data_service.rb, line 104
def find_output_port(name)
    name = name.to_str
    if (mapped = port_mappings_for_task[name]) && (port = component_model.find_output_port(mapped))
        ports[name] ||= OutputPort.new(self, port.orogen_model, name)
    end
end
find_port_for_task_port(task_port) click to toggle source

Returns the service port that maps to a task port

@return [nil,Port]

# File lib/syskit/models/bound_data_service.rb, line 225
def find_port_for_task_port(task_port)
    task_port_name = task_port.name
    port_mappings_for_task.each do |service_port_name, port_name|
        if port_name == task_port_name
            return find_port(service_port_name)
        end
    end
    nil
end
find_through_method_missing(m, args) click to toggle source
# File lib/syskit/models/bound_data_service.rb, line 369
def find_through_method_missing(m, args)
    MetaRuby::DSLs.find_through_method_missing(
        self, m, args,
        '_srv'.freeze => :find_data_service) || super
end
fullfilled_model() click to toggle source
# File lib/syskit/models/bound_data_service.rb, line 205
def fullfilled_model
    [model]
end
fullfills?(models) click to toggle source

Returns true if self provides all models in models

# File lib/syskit/models/bound_data_service.rb, line 210
def fullfills?(models)
    if !models.respond_to?(:each)
        models = [models]
    end
    models.each do |required_m|
        required_m.each_fullfilled_model do |m|
            return false if !self.model.fullfills?(m)
        end
    end
    true
end
has_data_service?(name) click to toggle source
# File lib/syskit/models/bound_data_service.rb, line 349
def has_data_service?(name)
    component_model.each_slave_data_service(self) do |slave_m|
        return true if slave_m.name == name
    end
    false
end
has_through_method_missing?(m) click to toggle source
# File lib/syskit/models/bound_data_service.rb, line 365
def has_through_method_missing?(m)
    MetaRuby::DSLs.has_through_method_missing?(
        self, m, '_srv'.freeze => :has_data_service?) || super
end
hash() click to toggle source
# File lib/syskit/models/bound_data_service.rb, line 67
def hash; [self.class, full_name, component_model].hash end
initialize_copy(original) click to toggle source
Calls superclass method
# File lib/syskit/models/bound_data_service.rb, line 88
def initialize_copy(original)
    super
    @ports = Hash.new
end
inspect() click to toggle source
# File lib/syskit/models/bound_data_service.rb, line 161
def inspect; to_s end
instanciate(plan, context = DependencyInjectionContext.new, options = Hash.new) click to toggle source

Creates, in the given plan, a new task matching this service in the given context, and returns the instanciated data service

@return [Syskit::BoundDataService]

# File lib/syskit/models/bound_data_service.rb, line 320
def instanciate(plan, context = DependencyInjectionContext.new, options = Hash.new)
    bind(component_model.instanciate(plan, context, options))
end
master?() click to toggle source

True if this service is not a slave service

# File lib/syskit/models/bound_data_service.rb, line 47
def master?; !@master end
merge(other_model) click to toggle source
# File lib/syskit/models/bound_data_service.rb, line 274
def merge(other_model)
    m = other_model.merge(component_model)
    attach(m)
end
orogen_model() click to toggle source
Orocos::Spec::TaskContext

the oroGen model for this service's

interface

# File lib/syskit/models/bound_data_service.rb, line 100
def orogen_model
    model.orogen_model
end
port_mappings_for(service_model) click to toggle source

Returns the port mappings that should be applied from one of the service models provided by {#model} to {#component_model}

@param [Model<DataService>] service_model the model of a service

provided by {#model}

@return [Hash<String,String>] mapping from the name of a port of

service_model to the name of a port on {#component_model}

@see #port_mappings_for_task

# File lib/syskit/models/bound_data_service.rb, line 254
def port_mappings_for(service_model)
    if !(result = port_mappings[service_model])
        raise ArgumentError, "#{service_model} is not provided by #{model.short_name}"
    end
    result
end
port_mappings_for_task() click to toggle source

Returns the port mappings that should be applied to convert a port from this service to {#component_model}

@return [Hash<String,String>] mapping from the name of a port of

self to the name of a port on {#component_model}

@see #port_mappings_for

# File lib/syskit/models/bound_data_service.rb, line 242
def port_mappings_for_task
    port_mappings_for(model)
end
pretty_print(pp) click to toggle source
# File lib/syskit/models/bound_data_service.rb, line 167
def pretty_print(pp)
    pp.text "service #{name}(#{model.name}) of"
    pp.nest(2) do
        pp.breakable
        component_model.pretty_print(pp)
    end
end
resolve(task) click to toggle source

Returns the BoundDataService object that binds this provided service to an actual task

@return [Syskit::BoundDataService]

# File lib/syskit/models/bound_data_service.rb, line 328
def resolve(task)
    bind(component_model.resolve(task))
end
same_service?(other) click to toggle source

Whether two services are the same service bound to two different interfaces

When subclassing, the services are promoted to the new component interface that is being accessed, so in effect when one does

bound_m = task_m.test_srv
sub_m = task_m.mew_submodel
sub_bound_m = bound_m.test_srv

Then sub_bound_m != bound_m as sub_bound_m is bound to sub_m and bound_m is bound to task_m. This is important, as we sometimes want to compare services including which interface they're bound to.

However, in some cases, we want to know whether two services are actually issues from the same service definition, i.e. have been promoted from the same service. This method performs that comparison

@param [BoundDataService] other @return [Boolean]

# File lib/syskit/models/bound_data_service.rb, line 394
def same_service?(other)
    other.demoted == self.demoted
end
selected_for(requirements) click to toggle source

The selection object that represents self being selected for requirements

@param [#to_instance_requirements] requirements the requirements

for which self is being selected

@return [InstanceSelection]

# File lib/syskit/models/bound_data_service.rb, line 404
def selected_for(requirements)
    InstanceSelection.new(nil, self.to_instance_requirements, requirements.to_instance_requirements)
end
self_port_to_component_port(port) click to toggle source

(see Syskit::Models::Component#self_port_to_component_port)

# File lib/syskit/models/bound_data_service.rb, line 94
def self_port_to_component_port(port)
    return component_model.find_port(port_mappings_for_task[port.name])
end
short_name() click to toggle source
# File lib/syskit/models/bound_data_service.rb, line 163
def short_name
    "#{component_model.short_name}:#{full_name}"
end
to_component_model() click to toggle source
# File lib/syskit/models/bound_data_service.rb, line 52
def to_component_model; component_model.to_component_model end
to_instance_requirements() click to toggle source

Generates the InstanceRequirements object that represents self best

@return [Syskit::InstanceRequirements]

# File lib/syskit/models/bound_data_service.rb, line 336
def to_instance_requirements
    req = component_model.to_instance_requirements
    req.select_service(self)
    req
end
to_s() click to toggle source
# File lib/syskit/models/bound_data_service.rb, line 157
def to_s
    "#{component_model.short_name}.#{full_name}"
end