Class: Roby::DRoby::Marshal
Overview
Handles marshalling and demarshalling objects for a given peer
Instance Attribute Summary collapse
-
#context_objects ⇒ Object
readonly
private
Objects that are temporarily referenced by IDs.
-
#object_manager ⇒ Object
readonly
The object that allows to match objects known locally with the objects transmitted by the peer.
-
#peer_id ⇒ PeerID
readonly
The ID of the peer that self handles.
Instance Method Summary collapse
-
#dump(object) ⇒ Object
Dump an object for transmition to the peer.
-
#dump_groups(*groups) ⇒ Object
Temporarily register sets of objects.
- #dump_model(object) ⇒ Object
-
#find_local_model(marshalled, name: marshalled.name) ⇒ Object
Find a known model matching the given name.
-
#find_local_object(marshalled) ⇒ (Boolean,Object)
Finds a local object that matches the object transmitted by our peer.
-
#find_model_by_name(name) ⇒ Object?
Attempts to resolve a registered model by its name.
-
#initialize(object_manager = ObjectManager.new(nil), peer_id = nil, auto_create_plans: false) ⇒ Marshal
constructor
A new instance of Marshal.
-
#known_siblings_for(object) ⇒ Hash
The set of IDs known for this object.
-
#load_groups(*groups) ⇒ Object
Load groups marshalled with #dump_groups.
- #local_model(marshalled, create: true) ⇒ Object
-
#local_object(marshalled, create: true) ⇒ Object
Resolves a marshalled object into a local object.
-
#local_plan(marshalled) ⇒ Object
Resolve an ID that is known to represent a plan.
-
#register_model(local_model, known_siblings = {}, name: local_model.name) ⇒ Object
Register a model by name and a list of known siblings for it.
-
#register_object(object, known_siblings = {}) ⇒ Object
Registers the mappings from object IDs to the corresponding local object.
- #with_object(id_to_object) ⇒ Object
Constructor Details
#initialize(object_manager = ObjectManager.new(nil), peer_id = nil, auto_create_plans: false) ⇒ Marshal
Returns a new instance of Marshal.
31 32 33 34 35 36 |
# File 'lib/roby/droby/marshal.rb', line 31 def initialize(object_manager = ObjectManager.new(nil), peer_id = nil, auto_create_plans: false) @object_manager = object_manager @peer_id = peer_id @context_objects = {} @auto_create_plans = auto_create_plans end |
Instance Attribute Details
#context_objects ⇒ Object (readonly)
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.
Objects that are temporarily referenced by IDs
This is used by #dump_groups and #load_groups
16 17 18 |
# File 'lib/roby/droby/marshal.rb', line 16 def context_objects @context_objects end |
#object_manager ⇒ Object (readonly)
The object that allows to match objects known locally with the objects transmitted by the peer
9 10 11 |
# File 'lib/roby/droby/marshal.rb', line 9 def object_manager @object_manager end |
#peer_id ⇒ PeerID (readonly)
The ID of the peer that self handles
21 22 23 |
# File 'lib/roby/droby/marshal.rb', line 21 def peer_id @peer_id end |
Instance Method Details
#dump(object) ⇒ Object
Dump an object for transmition to the peer
115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/roby/droby/marshal.rb', line 115 def dump(object) if droby_id = context_objects[object] droby_id elsif object.respond_to?(:droby_dump) if sibling = object_manager.registered_sibling_on(object, peer_id) RemoteDRobyID.new(peer_id, sibling) else object.droby_dump(self) end else object end end |
#dump_groups(*groups) ⇒ Object
Temporarily register sets of objects
Use this method to marshal sets of objects that could be referencing each other. Using this method ensures that the cross-references are marshalled using IDs instead of full objects
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/roby/droby/marshal.rb', line 55 def dump_groups(*groups) current_context = context_objects.dup mappings = groups.map do |collection| mapping = [] collection.each do |obj| context_objects[obj] = obj.droby_id mapping << [obj.droby_id, obj] end mapping end marshalled = mappings.map do |collection| collection.flat_map do |obj_id, obj| [obj_id, obj.droby_dump(self)] end end if block_given? yield(*marshalled) else marshalled end ensure context_objects.replace(current_context) end |
#dump_model(object) ⇒ Object
129 130 131 132 133 134 135 |
# File 'lib/roby/droby/marshal.rb', line 129 def dump_model(object) marshalled = dump(object) if !marshalled.kind_of?(RemoteDRobyID) && object.respond_to?(:droby_dump) register_model(object) end marshalled end |
#find_local_model(marshalled, name: marshalled.name) ⇒ Object
Find a known model matching the given name
It is first resolved among the models registered with #register_model and then resolved in the process constant hierarchy
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
# File 'lib/roby/droby/marshal.rb', line 213 def find_local_model(marshalled, name: marshalled.name) resolved, local_model = find_local_object(marshalled) if resolved return local_model elsif name && (local_model = object_manager.find_model_by_name(name)) return local_model elsif !name return end names = name.split("::") # Look locally for the constant listed in the name local_object = Object while subname = names.shift if subname =~ /^[A-Z]\w*$/ && local_object.const_defined_here?(subname) local_object = local_object.const_get(subname) else return end end local_object end |
#find_local_object(marshalled) ⇒ (Boolean,Object)
Finds a local object that matches the object transmitted by our peer
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/roby/droby/marshal.rb', line 142 def find_local_object(marshalled) if local_object = context_objects[marshalled] [true, local_object] elsif marshalled.kind_of?(DRobyID) [true, object_manager.fetch_by_id(peer_id, marshalled)] elsif marshalled.kind_of?(RemoteDRobyID) [true, object_manager.fetch_by_id(marshalled.peer_id, marshalled.droby_id)] elsif marshalled.respond_to?(:remote_siblings) marshalled.remote_siblings.each do |peer_id, droby_id| if local_object = object_manager.find_by_id(peer_id, droby_id) # In case the remote siblings got updated since # last time object_manager.register_siblings(local_object, marshalled.remote_siblings) if marshalled.respond_to?(:update) marshalled.update(self, local_object) end return true, local_object end end [false, nil] elsif !marshalled.respond_to?(:proxy) [true, marshalled] else [false, nil] end end |
#find_model_by_name(name) ⇒ Object?
Attempts to resolve a registered model by its name
In addition to ID-based resolution, models registered with #register_model can also be resolved by name.
This attempts a name-based resolution
244 245 246 |
# File 'lib/roby/droby/marshal.rb', line 244 def find_model_by_name(name) object_manager.find_model_by_name(name) end |
#known_siblings_for(object) ⇒ Hash
The set of IDs known for this object
This returns a mapping from peer IDs to the ID of the provided object on this peer. The list of siblings is maintained by #register_object and #deregister_object
259 260 261 |
# File 'lib/roby/droby/marshal.rb', line 259 def known_siblings_for(object) object_manager.known_siblings_for(object) end |
#load_groups(*groups) ⇒ Object
Load groups marshalled with #dump_groups
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/roby/droby/marshal.rb', line 82 def load_groups(*groups) current_context = context_objects.dup updates = [] local_objects = groups.map do |collection| collection.each_slice(2).map do |obj_id, marshalled_obj| proxy = local_object(marshalled_obj) context_objects[obj_id] = proxy if marshalled_obj.respond_to?(:remote_siblings) object_manager.register_object(proxy, marshalled_obj.remote_siblings) end if marshalled_obj.respond_to?(:update) updates << [marshalled_obj, proxy] end proxy end end updates.each do |marshalled, local| marshalled.update(self, local, fresh_proxy: true) end if block_given? yield(*local_objects) else local_objects end ensure context_objects.replace(current_context) end |
#local_model(marshalled, create: true) ⇒ Object
237 238 239 240 241 |
# File 'lib/roby/droby/marshal.rb', line 237 def local_model(marshalled, create: true) model = local_object(marshalled, create: create) object_manager.register_model(model) model end |
#local_object(marshalled, create: true) ⇒ Object
Resolves a marshalled object into a local object
Unlike #find_local_object, it raises if the object cannot be resolved
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/roby/droby/marshal.rb', line 173 def local_object(marshalled, create: true) resolved, local_object = find_local_object(marshalled) if resolved local_object elsif marshalled.respond_to?(:remote_siblings) unless create raise NoLocalObject, "#{marshalled} cannot be resolved into a local object and create is false" end local_object = marshalled.proxy(self) if local_object.respond_to?(:droby_id) object_manager.register_object(local_object, marshalled.remote_siblings) end if marshalled.respond_to?(:update) marshalled.update(self, local_object, fresh_proxy: true) end local_object elsif marshalled.respond_to?(:proxy) marshalled.proxy(self) else raise NoLocalObject, "#{marshalled} cannot be resolved into a local object" end end |
#local_plan(marshalled) ⇒ Object
Resolve an ID that is known to represent a plan
It calls #local_object by default, but can be overriden for e.g. environments where rebuilding a plan structure is not important (e.g. the shell)
202 203 204 205 206 |
# File 'lib/roby/droby/marshal.rb', line 202 def local_plan(marshalled) local_object(marshalled) rescue UnknownSibling Plan.new end |
#register_model(local_model, known_siblings = {}, name: local_model.name) ⇒ Object
Register a model by name and a list of known siblings for it
In addition to ID-based resolution, models can also be resolved by name through #find_model_by_name. This registers the name mapping and then calls #register_object
254 255 256 |
# File 'lib/roby/droby/marshal.rb', line 254 def register_model(local_model, known_siblings = {}, name: local_model.name) object_manager.register_model(local_model, known_siblings, name: name) end |
#register_object(object, known_siblings = {}) ⇒ Object
Registers the mappings from object IDs to the corresponding local object
This registers the mapping for the local process (local_id => local_object.droby_id), along with known siblings if provided
249 250 251 |
# File 'lib/roby/droby/marshal.rb', line 249 def register_object(object, known_siblings = {}) object_manager.register_object(object, known_siblings) end |
#with_object(id_to_object) ⇒ Object
38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/roby/droby/marshal.rb', line 38 def with_object(id_to_object) current_context = context_objects.dup id_to_object.each do |id, object| context_objects[id] = object context_objects[RemoteDRobyID.new(peer_id, id)] = object end yield ensure context_objects.replace(current_context) end |