Class: Roby::PlanObject

Inherits:
BasicObject
Includes:
DirectedRelationSupport, Distributed::RelationModificationHooks, Transactions::PlanObjectUpdates
Defined in:
lib/roby/plan-object.rb,
lib/roby.rb

Overview

Base class for all objects which are included in a plan.

Direct Known Subclasses

EventGenerator, Task

Defined Under Namespace

Classes: DRoby

Constant Summary

Constants included from Log::BasicObjectHooks

Log::BasicObjectHooks::HOOKS

Instance Attribute Summary collapse

Attributes inherited from BasicObject

#distribute

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Distributed::RelationModificationHooks

#added_child_object, #removed_child_object

Methods included from Transactions::PlanObjectUpdates

#adding_child_object

Methods included from DirectedRelationSupport

#add_parent_object, #check_is_relation, #related_objects, #relations, #remove_child_object, #remove_children, #remove_parent_object, #remove_parents, #remove_relations

Methods inherited from BasicObject

#add_sibling_for, #distribute?, distribute?, #has_sibling_on?, #initialize_copy, local_only, #remove_sibling_for, #self_owned?, #sibling_of, #sibling_on, #subscribe, #updated?, #updated_peers

Methods included from Log::BasicObjectHooks

#added_owner, #removed_owner

Instance Attribute Details

#executable=(value) ⇒ Object (writeonly)

A three-state flag with the following values:

nil

the object is executable if its plan is

true

the object is executable

false

the object is not executable



36
37
38
# File 'lib/roby/plan-object.rb', line 36

def executable=(value)
  @executable = value
end

#planObject

The plan this object belongs to



11
12
13
# File 'lib/roby/plan-object.rb', line 11

def plan
  @plan
end

#removed_atObject

The place where this object has been removed from its plan. Once an object is removed from its plan, it cannot be added back again.



15
16
17
# File 'lib/roby/plan-object.rb', line 15

def removed_at
  @removed_at
end

Class Method Details

.child_plan_object(attribute) ⇒ Object

This class method sets up the enclosing class as a child object, with the root object being returned by the given attribute. Task event generators are for instance defined by

class TaskEventGenerator < EventGenerator
    # The task this generator belongs to
    attr_reader :task

    child_plan_object :task
end


116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/roby/plan-object.rb', line 116

def self.child_plan_object(attribute)
    class_eval <<-EOD
    def root_object; #{attribute} end
    def root_object?; false end
    def owners; #{attribute}.owners end
    def distribute?; #{attribute}.distribute? end
    def plan; #{attribute}.plan end
    def executable?; #{attribute}.executable? end

    def subscribed?; #{attribute}.subscribed? end
    def updated?; #{attribute}.updated? end
    def updated_by?(peer); #{attribute}.updated_by?(peer) end
    def update_on?(peer); #{attribute}.update_on?(peer) end
    def updated_peers; #{attribute}.updated_peers end
    def remotely_useful?; #{attribute}.remotely_useful? end

    def forget_peer(peer)
	remove_sibling_for(peer)
    end
    def sibling_of(remote_object, peer)
	if !distribute?
	    raise ArgumentError, "#{self} is local only"
	end

	add_sibling_for(peer, remote_object)
    end

    private :plan=
    private :executable=
    EOD
end

Instance Method Details

#add_child_object(child, type, info = nil) ⇒ Object

Synchronizes the plan of this object from the one of its peer



91
92
93
94
95
96
97
# File 'lib/roby/plan-object.rb', line 91

def add_child_object(child, type, info = nil) # :nodoc:
    if child.plan != plan
	root_object.synchronize_plan(child.root_object)
    end

    super
end

#apply_relation_changes(object, changes) ⇒ Object

Transfers a set of relations from this plan object to object. changes is formatted as a sequence of relation, parents, children slices, where parents and children are sets of objects.

For each of these slices, the method removes the parent->self and self->child edges in the given relation, and then adds the corresponding parent->object and object->child edges.



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/roby/plan-object.rb', line 157

def apply_relation_changes(object, changes)
           # The operation is done in two parts to avoid problems with
           # creating cycles in the graph: first we remove the old edges, then
           # we add the new ones.
    changes.each_slice(3) do |rel, parents, children|
	parents.each_slice(2) do |parent, info|
	    parent.remove_child_object(self, rel)
	end
	children.each_slice(2) do |child, info|
	    remove_child_object(child, rel)
	end
    end

    changes.each_slice(3) do |rel, parents, children|
	parents.each_slice(2) do |parent, info|
	    parent.add_child_object(object, rel, info)
	end
	children.each_slice(2) do |child, info|
	    object.add_child_object(child, rel, info)
	end
    end
end

#each_plan_childObject

Iterates on all the children of this root object



104
# File 'lib/roby/plan-object.rb', line 104

def each_plan_child; self end

#executable?Boolean

If this object is executable

Returns:

  • (Boolean)


39
40
41
# File 'lib/roby/plan-object.rb', line 39

def executable?
    @executable || (@executable.nil? && plan && plan.executable?)
end

#finalized?Boolean

True if this object has been included in a plan, but has been removed from it since

Returns:

  • (Boolean)


19
# File 'lib/roby/plan-object.rb', line 19

def finalized?; !!removed_at end

#forget_peer(peer) ⇒ Object

Called when all links to peer should be removed.



79
80
81
82
83
84
85
86
87
88
# File 'lib/roby/plan-object.rb', line 79

def forget_peer(peer)
    if !root_object?
	raise ArgumentError, "#{self} is not root"
    end

    each_plan_child do |child|
	child.forget_peer(peer)
    end
    super
end

#read_write?Boolean

True if this object can be modified by the local plan manager

Returns:

  • (Boolean)


225
226
227
228
229
230
231
232
233
234
# File 'lib/roby/plan-object.rb', line 225

def read_write?
    if (owners.include?(Distributed) || Distributed.updating?(root_object) || !plan)
	true
    elsif plan.owners.include?(Distributed)
	for peer in owners
	    return false unless plan.owners.include?(peer)
	end
	true
    end
end

#remotely_useful?Boolean

True if this object is useful for one of our peers

Returns:

  • (Boolean)


59
# File 'lib/roby/plan-object.rb', line 59

def remotely_useful?; (plan && plan.remotely_useful?) || super end

#removing_child_object(child, type) ⇒ Object

Checks if we have the right to remove a relation. Raises OwnershipError if it is not the case



238
239
240
241
242
243
244
# File 'lib/roby/plan-object.rb', line 238

def removing_child_object(child, type)
    super if defined? super

    unless read_write? || child.read_write?
	raise OwnershipError, "cannot remove a relation between two objects we don't own"
    end
end

#replace_by(object) ⇒ Object

Replaces self by object in all graphs self is part of. Unlike BGL::Vertex#replace_by, this calls the various add/remove hooks defined in DirectedRelationSupport



203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/roby/plan-object.rb', line 203

def replace_by(object)
    changes = []
    each_relation do |rel|
	parents = []
	each_parent_object(rel) do |parent|
	    unless parent.root_object == root_object
		parents << parent << parent[self, rel]
	    end
	end
	children = []
	each_child_object(rel) do |child|
	    unless child.root_object == root_object
		children << child << self[child, rel]
	    end
	end
	changes << rel << parents << children
    end

    apply_relation_changes(object, changes)
end

#replace_subplan_by(object) ⇒ Object

Replaces, in the plan, the subplan generated by this plan object by the one generated by object. In practice, it means that we transfer all parent edges whose target is self from the receiver to object. It calls the various add/remove hooks defined in DirectedRelationSupport.



185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/roby/plan-object.rb', line 185

def replace_subplan_by(object)
    changes = []
    each_relation do |rel|
	parents = []
	each_parent_object(rel) do |parent|
	    unless parent.root_object == root_object
		parents << parent << parent[self, rel]
	    end
	end
	changes << rel << parents << []
    end

    apply_relation_changes(object, changes)
end

#root_objectObject

Return the root plan object for this object.



100
# File 'lib/roby/plan-object.rb', line 100

def root_object; self end

#root_object?Boolean

True if this object is a root object in the plan.

Returns:

  • (Boolean)


102
# File 'lib/roby/plan-object.rb', line 102

def root_object?; root_object == self end

#subscribed?Boolean

True if we are explicitely subscribed to this object

Returns:

  • (Boolean)


44
45
46
47
48
49
50
51
52
# File 'lib/roby/plan-object.rb', line 44

def subscribed?
    if root_object?
	(plan && plan.subscribed?) ||
	    (!self_owned? && owners.any? { |peer| peer.subscribed_plan? }) ||
	    super
    else
	root_object.subscribed?
    end
end

#update_on?(peer) ⇒ Boolean

True if we should send updates about this object to peer

Returns:

  • (Boolean)


55
# File 'lib/roby/plan-object.rb', line 55

def update_on?(peer); (plan && plan.update_on?(peer)) || super end

#updated_by?(peer) ⇒ Boolean

True if we receive updates for this object from peer

Returns:

  • (Boolean)


57
# File 'lib/roby/plan-object.rb', line 57

def updated_by?(peer); (plan && plan.updated_by?(peer)) || super end