Class: Roby::TaskEventGenerator

Inherits:
EventGenerator show all
Includes:
DRoby::V5::TaskEventGeneratorDumper, GUI::GraphvizTaskEventGenerator, GUI::RelationsCanvasTaskEventGenerator
Defined in:
lib/roby/task_event_generator.rb,
lib/roby/task_structure/error_handling.rb,
lib/roby/droby/enable.rb

Overview

Specialization of EventGenerator to represent task events

It gives access to the task-specific information (associated task, event name, …)

Instance Attribute Summary collapse

Attributes inherited from EventGenerator

#command, #event_model, #history, #unreachability_reason, #unreachable_handlers

Attributes inherited from PlanObject

#addition_time, #executable, #execution_engine, #finalization_handlers, #finalization_time, #model, #promise_executor, #removed_at

Attributes included from Roby::Transaction::Proxying::Cache

#transaction_forwarder_module, #transaction_proxy_module

Attributes included from Relations::DirectedRelationSupport

#relation_graphs

Attributes inherited from DistributedObject

#local_owner_id, #owners

Instance Method Summary collapse

Methods included from DRoby::V5::TaskEventGeneratorDumper

#droby_dump

Methods included from GUI::GraphvizTaskEventGenerator

#dot_label

Methods included from GUI::GraphvizPlanObject

#apply_layout, #dot_label, #to_dot

Methods included from GUI::RelationsCanvasTaskEventGenerator

#display, #display_name, #display_parent

Methods included from GUI::RelationsCanvasEventGenerator

#display, #display_create, #display_name, #display_time_end, #display_time_start, priorities, style, styles

Methods included from GUI::RelationsCanvasPlanObject

#display, #display_create, #display_events, #display_name, #display_parent

Methods inherited from EventGenerator

#&, #achieve_asynchronously, #add_child_object, #call, #call_handlers, #call_unreachable_handlers, #call_without_propagation, #calling, #cancel, #delay, #emit, #emit_without_propagation, #emitting, #filter, #finalized!, #forward, #forward_once, #forward_to, #forward_to_once, #garbage!, #happened?, #if_unreachable, #initialize_copy, #initialize_replacement, #last, #mark_unreachable!, match, #model, #name, #once, #precondition, #realize_with, #related_events, #replace_by, #signal, #signals, #signals_once, #to_event, #to_execution_exception, #to_execution_exception_matcher, #unreachable!, #unreachable_without_propagation, #until, #when_unreachable, #|

Methods included from DRoby::Identifiable

#droby_id, #initialize_copy

Methods included from DRoby::V5::DRobyConstant::Dump

#droby_dump

Methods included from DRoby::V5::EventGeneratorDumper

#droby_dump

Methods inherited from PlanObject

#add_child_object, #apply_relation_changes, #as_plan, #can_finalize?, #commit_transaction, #concrete_model, #connection_space, #each_finalization_handler, #each_in_neighbour_merged, #each_out_neighbour_merged, #each_plan_child, #engine, #executable?, #finalized!, #finalized?, #forget_peer, #fullfills?, #garbage!, #garbage?, #initialize_copy, #initialize_replacement, #merged_relations, #promise, #read_write?, #real_object, #remotely_useful?, #replace_by, #replace_subplan_by, #root_object, #root_object?, #subscribed?, #transaction_proxy?, #transaction_stack, #update_on?, #updated_by?, #when_finalized

Methods included from Models::PlanObject

#child_plan_object, #finalization_handler, #when_finalized

Methods included from Relations::DirectedRelationSupport

#[], #[]=, #add_child_object, #add_parent_object, #child_object?, #child_objects, #clear_vertex, #each_child_object, #each_in_neighbour, #each_out_neighbour, #each_parent_object, #each_relation, #each_relation_graph, #each_relation_sorted, #each_root_relation_graph, #enum_child_objects, #enum_parent_objects, #enum_relations, #leaf?, #parent_object?, #parent_objects, #related_object?, #related_objects, #relation_graph_for, #relations, #remove_child_object, #remove_children, #remove_parent_object, #remove_parents, #remove_relations, #root?, #sorted_relations

Methods inherited from DistributedObject

#add_owner, #clear_owners, #initialize_copy, #owned_by?, #remove_owner

Constructor Details

#initialize(task, model) ⇒ TaskEventGenerator

Returns a new instance of TaskEventGenerator.



16
17
18
19
20
# File 'lib/roby/task_event_generator.rb', line 16

def initialize(task, model)
    super(model.respond_to?(:call), plan: task.plan)
    @task, @event_model = task, model
    @symbol = model.symbol
end

Instance Attribute Details

#planObject

The event plan. It is the same as task.plan and is actually updated by task.plan=. It is redefined here for performance reasons.



39
40
41
# File 'lib/roby/task_event_generator.rb', line 39

def plan
  @plan
end

#symbolObject (readonly)

The event symbol (its name as a Symbol object)



10
11
12
# File 'lib/roby/task_event_generator.rb', line 10

def symbol
  @symbol
end

#taskObject (readonly)

The task we are part of



8
9
10
# File 'lib/roby/task_event_generator.rb', line 8

def task
  @task
end

#terminal_flagObject

Returns the value for #terminal_flag, updating it if needed



131
132
133
134
135
136
# File 'lib/roby/task_event_generator.rb', line 131

def terminal_flag # :nodoc:
    if task.invalidated_terminal_flag?
        task.update_terminal_flag
    end
    return @terminal_flag
end

Instance Method Details

#achieve_with(obj) ⇒ Object

See EventGenerator#achieve_with



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/roby/task_event_generator.rb', line 197

def achieve_with(obj) # :nodoc:
    child_task, child_event = case obj
                              when Roby::Task then [obj, obj.event(:success)]
                              when Roby::TaskEventGenerator then [obj.task, obj]
                              end

    if child_task
        unless task.depends_on?(child_task)
            task.depends_on child_task, 
                success: [child_event.symbol],
                remove_when_done: true
        end
        super(child_event)
    else
        super(obj)
    end
end

#added_forwarding(child, info) ⇒ Object

Invalidates the task’s terminal flag when the Forwarding and/or the Signal relation gets modified.



164
165
166
167
# File 'lib/roby/task_event_generator.rb', line 164

def added_forwarding(child, info) # :nodoc:
    super
    invalidate_task_terminal_flag_if_needed(child)
end

#added_signal(child, info) ⇒ Object

Invalidates the task’s terminal flag when the Forwarding and/or the Signal relation gets modified.



157
158
159
160
# File 'lib/roby/task_event_generator.rb', line 157

def added_signal(child, info) # :nodoc:
    super
    invalidate_task_terminal_flag_if_needed(child)
end

#called(context) ⇒ Object



74
75
76
77
78
79
# File 'lib/roby/task_event_generator.rb', line 74

def called(context)
    super
    if terminal? && pending?
        task.finishing = true
    end
end

#check_call_validityObject

Checks that the event can be called. Raises various exception when it is not the case.



226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/roby/task_event_generator.rb', line 226

def check_call_validity # :nodoc:
    if error = super
        if !error.kind_of?(UnreachableEvent)
            return refine_call_exception(error)
        end
    end

    if task.failed_to_start?
        CommandRejected.new(self).
            exception("#{symbol}! called by #{execution_engine.propagation_sources.to_a} but the task has failed to start: #{task.failure_reason}")
    elsif task.event(:stop).emitted?
        CommandRejected.new(self).
            exception("#{symbol}! called by #{execution_engine.propagation_sources.to_a} but the task has finished. Task has been terminated by #{task.event(:stop).history.first.sources.to_a}.")
    elsif task.finished? && !terminal?
        CommandRejected.new(self).
            exception("#{symbol}! called by #{execution_engine.propagation_sources.to_a} but the task has finished. Task has been terminated by #{task.event(:stop).history.first.sources.to_a}.")
    elsif task.pending? && symbol != :start
        CommandRejected.new(self).
            exception("#{symbol}! called by #{execution_engine.propagation_sources.to_a} but the task has never been started")
    elsif task.running? && symbol == :start
        CommandRejected.new(self).
            exception("#{symbol}! called by #{execution_engine.propagation_sources.to_a} but the task is already running. Task has been started by #{task.event(:start).history.first.sources.to_a}.")
    else error
    end
end

#check_call_validity_after_callingObject



252
253
254
255
256
# File 'lib/roby/task_event_generator.rb', line 252

def check_call_validity_after_calling
    if error = super
        refine_call_exception(error)
    end
end

#check_emission_validityObject

Checks that the event can be emitted. Raises various exception when it is not the case.



260
261
262
263
264
265
266
# File 'lib/roby/task_event_generator.rb', line 260

def check_emission_validity # :nodoc:
    if error = super
        refine_emit_exception(error)
    else
        task.check_emission_validity(self)
    end
end

#clear_pendingObject



63
64
65
66
67
68
69
70
71
72
# File 'lib/roby/task_event_generator.rb', line 63

def clear_pending
    if @pending && symbol == :start
        if !emitted? && !task.failed_to_start?
            plan.task_index.set_state(task, :pending?) if plan && !plan.template?
            task.pending = true
            task.starting = false
        end
    end
    super
end

#command=(block) ⇒ Object



28
29
30
31
32
# File 'lib/roby/task_event_generator.rb', line 28

def command=(block)
    event_model.singleton_class.class_eval do
        define_method(:call, &block)
    end
end

#controlable?Boolean

See EventGenerator#controlable?

Returns:

  • (Boolean)


123
124
125
# File 'lib/roby/task_event_generator.rb', line 123

def controlable? # :nodoc:
    event_model.controlable?
end

#create_transaction_proxy(transaction) ⇒ Object



328
329
330
331
# File 'lib/roby/task_event_generator.rb', line 328

def create_transaction_proxy(transaction)
    # Ensure that the task is proxied already
    transaction.wrap_task(task).event(symbol)
end

#default_command(context) ⇒ Object

The default command if the event is created with controlable: true. It emits the event on the task.



24
25
26
# File 'lib/roby/task_event_generator.rb', line 24

def default_command(context)
    event_model.call(task, context)
end

#default_on_replaceObject



318
319
320
321
322
# File 'lib/roby/task_event_generator.rb', line 318

def default_on_replace
    if task.abstract? then :copy
    else :drop
    end
end

#each_handlerObject

See EventGenerator#each_handler



108
109
110
111
112
113
114
# File 'lib/roby/task_event_generator.rb', line 108

def each_handler # :nodoc:
    if self_owned?
        task.model.each_handler(event_model.symbol) { |o| yield(o) }
    end

    super
end

#each_preconditionObject

See EventGenerator#each_precondition



117
118
119
120
# File 'lib/roby/task_event_generator.rb', line 117

def each_precondition # :nodoc:
    task.model.each_precondition(event_model.symbol) { |o| yield(o) }
    super
end

#emit_failed(error = nil, message = nil) ⇒ Object



215
216
217
218
219
220
221
222
# File 'lib/roby/task_event_generator.rb', line 215

def emit_failed(error = nil, message = nil)
    exception = super
    if symbol == :start
        if !task.failed_to_start?
            task.failed_to_start!(exception)
        end
    end
end

#failure?Boolean

True if this event is either forwarded to or signals the task’s :failed event

Returns:

  • (Boolean)


143
# File 'lib/roby/task_event_generator.rb', line 143

def failure?; terminal_flag == :failure end

#fire(event) ⇒ Object



81
82
83
84
85
86
87
88
89
90
# File 'lib/roby/task_event_generator.rb', line 81

def fire(event)
    super
    if symbol == :start
        task.do_poll(plan)
    elsif symbol == :stop
        task.each_event do |ev|
            ev.unreachable!(task.terminal_event)
        end
    end
end

#fired(event) ⇒ Object

Actually emits the event. This should not be used directly.

It forwards the call to Task#fire



95
96
97
98
# File 'lib/roby/task_event_generator.rb', line 95

def fired(event) # :nodoc:
    super
    task.fired_event(event)
end

#handle_with(repairing_task, remove_when_done: true) ⇒ Object

Mark this event as being handled by the task task



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/roby/task_structure/error_handling.rb', line 4

def handle_with(repairing_task, remove_when_done: true)
    if repairing_task.respond_to?(:as_plan)
        repairing_task = repairing_task.as_plan
    end

    if !task.child_object?(repairing_task, ErrorHandling)
        task.add_error_handler repairing_task, Set.new
    end

    if remove_when_done
        repairing_task.stop_event.on do |event|
            repairing_task = event.task
            if task.plan && task.child_object?(repairing_task, ErrorHandling)
                task.remove_error_handler(repairing_task)
            end
        end
    end

    task[repairing_task, ErrorHandling] << Roby::Queries::ExecutionExceptionMatcher.new.with_origin(task.model.find_event(symbol))
    repairing_task
end

#inspectObject

:nodoc:



189
190
191
# File 'lib/roby/task_event_generator.rb', line 189

def inspect # :nodoc:
    "#{task.inspect}/#{symbol}: #{history.to_s}"
end

#invalidate_task_terminal_flag_if_needed(child) ⇒ 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 the signal and forward relation hooks that invalidates the events terminal flags when the event structure is changed



149
150
151
152
153
# File 'lib/roby/task_event_generator.rb', line 149

def invalidate_task_terminal_flag_if_needed(child)
    if child.respond_to?(:task) && child.task == task
        task.invalidate_terminal_flag
    end
end

#matchObject



333
334
335
# File 'lib/roby/task_event_generator.rb', line 333

def match
    Queries::TaskEventGeneratorMatcher.new(task, symbol)
end

#new(context, propagation_id = nil, time = nil) ⇒ Object

See EventGenerator#new



182
183
184
# File 'lib/roby/task_event_generator.rb', line 182

def new(context, propagation_id = nil, time = nil) # :nodoc:
    event_model.new(task, self, propagation_id || execution_engine.propagation_id, context, time || Time.now)
end

#on(on_replace: default_on_replace, once: false, &block) ⇒ Object



324
325
326
# File 'lib/roby/task_event_generator.rb', line 324

def on(on_replace: default_on_replace, once: false, &block)
    super(on_replace: on_replace, once: once, &block)
end

#override_model(model) ⇒ Object

Changes the underlying model



12
13
14
# File 'lib/roby/task_event_generator.rb', line 12

def override_model(model)
    @event_model = model
end

#pending(sources) ⇒ Object



53
54
55
56
57
58
59
60
61
# File 'lib/roby/task_event_generator.rb', line 53

def pending(sources)
    super
    if symbol == :start
        task.freeze_delayed_arguments
        plan.task_index.set_state(task, :starting?) if plan && !plan.template?
        task.pending  = false
        task.starting = true
    end
end

#pretty_print(pp) ⇒ Object

:nodoc:



192
193
194
# File 'lib/roby/task_event_generator.rb', line 192

def pretty_print(pp) # :nodoc:
    pp.text "#{symbol} event of #{task.class}:0x#{task.address.to_s(16)}"
end

#refine_call_exception(e) ⇒ Object

When an emissio and/or call exception is raised by the base EventGenerator methods, this method is used to transform it to the relevant task-related error.



271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# File 'lib/roby/task_event_generator.rb', line 271

def refine_call_exception (e) # :nodoc:
    if task.partially_instanciated?
        TaskEventNotExecutable.new(self).
            exception("#{symbol}_event.call on #{task} which is partially instanciated\n" + 
                "The following arguments were not set:\n" +
                task.list_unset_arguments.map {|n| "  #{n}"}.join("\n"))
    elsif !plan
        TaskEventNotExecutable.new(self).
            exception("#{symbol}_event.call on #{task} but the task has been removed from its plan")
    elsif !plan.executable?
        TaskEventNotExecutable.new(self).
            exception("#{symbol}_event.call on #{task} but its plan is not executable")
    elsif task.abstract?
        TaskEventNotExecutable.new(self).
            exception("#{symbol}_event.call on #{task} but the task is abstract")
    elsif e.kind_of?(EventNotExecutable)
        TaskEventNotExecutable.new(self).
            exception("#{symbol}_event.call on #{task} which is not executable")
    else e
    end
end

#refine_emit_exception(e) ⇒ Object

When an emissio and/or call exception is raised by the base EventGenerator methods, this method is used to transform it to the relevant task-related error.



296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
# File 'lib/roby/task_event_generator.rb', line 296

def refine_emit_exception (e) # :nodoc:
    if task.partially_instanciated?
        TaskEventNotExecutable.new(self).
            exception("#{symbol}_event.emit on #{task} which is partially instanciated\n" + 
                "The following arguments were not set:\n" +
                task.list_unset_arguments.map {|n| "  #{n}"}.join("\n"))
    elsif !plan
        TaskEventNotExecutable.new(self).
            exception("#{symbol}_event.emit on #{task} but the task has been removed from its plan")
    elsif !plan.executable?
        TaskEventNotExecutable.new(self).
            exception("#{symbol}_event.emit on #{task} but its plan is not executable")
    elsif task.abstract?
        TaskEventNotExecutable.new(self).
            exception("#{symbol}_event.emit on #{task} but the task is abstract")
    elsif e.kind_of?(EventNotExecutable)
        TaskEventNotExecutable.new(self).
            exception("#{symbol}_event.emit on #{task} which is not executable")
    else e
    end
end

See EventGenerator#related_tasks



101
102
103
104
105
# File 'lib/roby/task_event_generator.rb', line 101

def related_tasks(result = nil) # :nodoc:
    tasks = super
    tasks.delete(task)
    tasks
end

#removed_forwarding(child) ⇒ Object



176
177
178
179
# File 'lib/roby/task_event_generator.rb', line 176

def removed_forwarding(child)
    super
    invalidate_task_terminal_flag_if_needed(child)
end

#removed_signal(child) ⇒ Object

Invalidates the task’s terminal flag when the Forwarding and/or the Signal relation gets modified.



171
172
173
174
# File 'lib/roby/task_event_generator.rb', line 171

def removed_signal(child)
    super
    invalidate_task_terminal_flag_if_needed(child)
end

#success?Boolean

True if this event is either forwarded to or signals the task’s :success event

Returns:

  • (Boolean)


141
# File 'lib/roby/task_event_generator.rb', line 141

def success?; terminal_flag == :success end

#terminal?Boolean

True if this event is either forwarded to or signals the task’s :stop event

Returns:

  • (Boolean)


139
# File 'lib/roby/task_event_generator.rb', line 139

def terminal?; !!terminal_flag end

#to_sObject

:nodoc:



186
187
188
# File 'lib/roby/task_event_generator.rb', line 186

def to_s # :nodoc:
    "#{task}/#{symbol}"
end