/interpreter/tags/at2dist030708/src/edu/vub/at/actors/natives/NATActorMirror.java
Java | 389 lines | 206 code | 35 blank | 148 comment | 6 complexity | e87166938d8aac84775d81964f34c5a1 MD5 | raw file
1/** 2 * AmbientTalk/2 Project 3 * NATActorMirror.java created on Oct 16, 2006 at 1:55:05 PM 4 * (c) Programming Technology Lab, 2006 - 2007 5 * Authors: Tom Van Cutsem & Stijn Mostinckx 6 * 7 * Permission is hereby granted, free of charge, to any person 8 * obtaining a copy of this software and associated documentation 9 * files (the "Software"), to deal in the Software without 10 * restriction, including without limitation the rights to use, 11 * copy, modify, merge, publish, distribute, sublicense, and/or 12 * sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following 14 * conditions: 15 * 16 * The above copyright notice and this permission notice shall be 17 * included in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 21 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 23 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 * OTHER DEALINGS IN THE SOFTWARE. 27 */ 28package edu.vub.at.actors.natives; 29 30import edu.vub.at.actors.ATActorMirror; 31import edu.vub.at.actors.ATAsyncMessage; 32import edu.vub.at.actors.ATLetter; 33import edu.vub.at.actors.natives.DiscoveryManager.Publication; 34import edu.vub.at.actors.natives.DiscoveryManager.Subscription; 35import edu.vub.at.eval.Evaluator; 36import edu.vub.at.exceptions.InterpreterException; 37import edu.vub.at.exceptions.XArityMismatch; 38import edu.vub.at.exceptions.XIllegalOperation; 39import edu.vub.at.exceptions.XTypeMismatch; 40import edu.vub.at.objects.ATBoolean; 41import edu.vub.at.objects.ATClosure; 42import edu.vub.at.objects.ATObject; 43import edu.vub.at.objects.ATTable; 44import edu.vub.at.objects.ATTypeTag; 45import edu.vub.at.objects.coercion.NativeTypeTags; 46import edu.vub.at.objects.grammar.ATSymbol; 47import edu.vub.at.objects.mirrors.NATIntrospectiveMirror; 48import edu.vub.at.objects.mirrors.NativeClosure; 49import edu.vub.at.objects.natives.NATByRef; 50import edu.vub.at.objects.natives.NATNumber; 51import edu.vub.at.objects.natives.NATObject; 52import edu.vub.at.objects.natives.NATTable; 53import edu.vub.at.objects.natives.NATText; 54import edu.vub.at.objects.natives.OBJLexicalRoot; 55import edu.vub.at.objects.natives.grammar.AGSymbol; 56 57import java.util.LinkedList; 58 59/** 60 * The NATActorMirror class implements the concurrency model of ambienttalk. It continually 61 * consumes meta-events which are written to a synchronized queue. This way the actor 62 * is notified of incoming messages, discovered and lost services, etc. When no meta- 63 * messages are available, the actor consumes base-level messages as they are stored 64 * in its inbox. These messages have a receiver object internal to the actor and they 65 * will be invoked on this receiver by the actor's thread. 66 * 67 * @author smostinc 68 */ 69public class NATActorMirror extends NATByRef implements ATActorMirror { 70 71 // INSTANCE VARIABLES 72 73 private final ELDiscoveryActor discoveryActor_; 74 75 /** 76 * When initializing a new actor, do not forget that this constructor is still executed by the 77 * creating actor, not by the created actor. To make the created actor perform something, it is 78 * necessary to use meta_receive to send itself messages for later execution. 79 */ 80 public NATActorMirror(ELVirtualMachine host) { 81 discoveryActor_ = host.discoveryActor_; 82 } 83 84 /* ------------------------------------------ 85 * -- Language Construct to Actor Protocol -- 86 * ------------------------------------------ */ 87 88 public ATAsyncMessage base_createMessage(ATSymbol selector, ATTable arguments, ATTable types) throws InterpreterException { 89 ATAsyncMessage msg = new NATAsyncMessage(selector, arguments, types); 90 // types.inject: msg into: { |constructingMsg, type| type.annotate(constructingMsg) } 91 return types.base_inject_into_(msg, new NativeClosure(this) { 92 public ATObject base_apply(ATTable args) throws InterpreterException { 93 checkArity(args, 2); 94 ATObject newMessage = get(args, 1); 95 ATObject type = get(args, 2); 96 return type.asTypeTag().base_annotateMessage(newMessage); 97 } 98 }).asAsyncMessage(); 99 } 100 101 public ATObject base_createMirror(ATObject reflectee) throws InterpreterException { 102 return NATIntrospectiveMirror.atValue(reflectee); 103 } 104 105 /** 106 * A publication object is defined as: 107 * object: { 108 * def topic := //topic under which service is published; 109 * def service := //the exported service object; 110 * def cancel() { //unexport the service object } 111 * } 112 */ 113 public static class NATPublication extends NATObject { 114 private static final AGSymbol _TOPIC_ = AGSymbol.jAlloc("topic"); 115 private static final AGSymbol _SERVICE_ = AGSymbol.jAlloc("service"); 116 private static final AGSymbol _CANCEL_ = AGSymbol.jAlloc("cancel"); 117 public NATPublication(final ELDiscoveryActor discoveryActor, 118 ATTypeTag topic, ATObject service, 119 final Publication pub) throws InterpreterException { 120 meta_defineField(_TOPIC_, topic); 121 meta_defineField(_SERVICE_, service); 122 meta_defineField(_CANCEL_, new NativeClosure(this) { 123 public ATObject base_apply(ATTable args) throws InterpreterException { 124 discoveryActor.event_cancelPublication(pub); 125 return Evaluator.getNil(); 126 } 127 }); 128 } 129 public NATText meta_print() throws InterpreterException { 130 return NATText.atValue("<publication:"+impl_invokeAccessor(this, _TOPIC_, NATTable.EMPTY)+">"); 131 } 132 } 133 134 /** 135 * A subscription object is defined as: 136 * object: { 137 * def topic := //topic subscribed to; 138 * def handler := //the closure to be triggered; 139 * def cancel() { //unsubscribe the handler } 140 * } 141 */ 142 public static class NATSubscription extends NATObject { 143 private static final AGSymbol _TOPIC_ = AGSymbol.jAlloc("topic"); 144 private static final AGSymbol _HANDLER_ = AGSymbol.jAlloc("handler"); 145 private static final AGSymbol _CANCEL_ = AGSymbol.jAlloc("cancel"); 146 public NATSubscription(final ELDiscoveryActor discoveryActor, 147 ATTypeTag topic, ATClosure handler, 148 final Subscription sub) throws InterpreterException { 149 meta_defineField(_TOPIC_, topic); 150 meta_defineField(_HANDLER_, handler); 151 meta_defineField(_CANCEL_, new NativeClosure(this) { 152 public ATObject base_apply(ATTable args) throws InterpreterException { 153 discoveryActor.event_cancelSubscription(sub); 154 return Evaluator.getNil(); 155 } 156 }); 157 } 158 public NATText meta_print() throws InterpreterException { 159 return NATText.atValue("<subscription:"+impl_invokeAccessor(this, _TOPIC_, NATTable.EMPTY)+">"); 160 } 161 } 162 163 public ATObject base_provide(final ATTypeTag topic, final ATObject service) throws InterpreterException { 164 Publication pub = new Publication(ELActor.currentActor(), 165 new Packet(topic), 166 new Packet(service)); 167 discoveryActor_.event_servicePublished(pub); 168 return new NATPublication(discoveryActor_, topic, service, pub); 169 } 170 171 public ATObject base_require(final ATTypeTag topic, final ATClosure handler, ATBoolean isPermanent) throws InterpreterException { 172 Subscription sub = new Subscription(ELActor.currentActor(), 173 new Packet(topic), 174 new Packet(handler), 175 isPermanent.asNativeBoolean().javaValue); 176 discoveryActor_.event_clientSubscribed(sub); 177 return new NATSubscription(discoveryActor_, topic, handler, sub); 178 } 179 180 public ATTable base_listPublications() throws InterpreterException { 181 ELActor myEventLoop = ELActor.currentActor(); 182 Publication[] pubs = discoveryActor_.sync_event_listPublications(myEventLoop); 183 NATPublication[] natpubs = new NATPublication[pubs.length]; 184 for(int i = 0; i < pubs.length; i++) { 185 Publication pub = pubs[i]; 186 natpubs[i] = new NATPublication( 187 discoveryActor_, 188 pub.providedTypeTag_.unpack().asTypeTag(), 189 pub.exportedService_.unpack(), 190 pub); 191 } 192 return NATTable.atValue(natpubs); 193 } 194 195 public ATTable base_listSubscriptions() throws InterpreterException { 196 ELActor myEventLoop = ELActor.currentActor(); 197 Subscription[] subs = discoveryActor_.sync_event_listSubscriptions(myEventLoop); 198 NATSubscription[] natsubs = new NATSubscription[subs.length]; 199 for(int i = 0; i < subs.length; i++) { 200 Subscription sub = subs[i]; 201 natsubs[i] = new NATSubscription( 202 discoveryActor_, 203 sub.requiredTypeTag_.unpack().asTypeTag(), 204 sub.registeredHandler_.unpack().asClosure(), 205 sub); 206 } 207 return NATTable.atValue(natsubs); 208 } 209 210 /* -------------------------- 211 * -- VM to Actor Protocol -- 212 * -------------------------- */ 213 214 public ATObject meta_clone() throws InterpreterException { 215 throw new XIllegalOperation("Cannot clone actor " + toString()); 216 } 217 218 /** 219 * actor.new(closure) 220 * => same effect as evaluating 'actor: closure' 221 */ 222 public ATObject meta_newInstance(ATTable initargs) throws InterpreterException { 223 int length = initargs.base_length().asNativeNumber().javaValue; 224 if(length != 1) 225 throw new XArityMismatch("newInstance", 1, length); 226 227 ATClosure closure = initargs.base_at(NATNumber.ONE).asClosure(); 228 return OBJLexicalRoot._INSTANCE_.base_actor_(closure); 229 } 230 231 public NATText meta_print() throws InterpreterException { 232 return NATText.atValue("<actormirror:" + this.hashCode() + ">"); 233 } 234 235 public ATTable meta_typeTags() throws InterpreterException { 236 return NATTable.of(NativeTypeTags._ACTORMIRROR_); 237 } 238 239 /* ----------------------------- 240 * -- Object Passing Protocol -- 241 * ----------------------------- */ 242 243 /** 244 * When default base-level objects send an asynchronous message, they delegate 245 * this responsibility to their actor by means of this base-level method. 246 * 247 * The actor's default implementation is to invoke the receiver mirror's <tt>receive</tt> method 248 * which defines the default asynchronous message reception semantics. 249 * 250 * Note: in pre-2.9 versions of AmbientTalk, this method did not immediately pass 251 * control to the receiver via the <tt>receive</tt> method. By delegating to the receiver 252 * in the same execution turn as the message send, we allow possible proxies (custom eventual 253 * references) to intervene in the message sending process. 254 */ 255 public ATObject base_send(ATObject receiver, ATAsyncMessage message) throws InterpreterException { 256 return receiver.meta_receive(message); 257 } 258 259 /** 260 * def becomeMirroredBy: protocol 261 * => returns the old installed protocol 262 * 263 * @see ATActorMirror#base_becomeMirroredBy_(ATClosure) 264 */ 265 public ATObject base_becomeMirroredBy_(ATActorMirror newActorMirror) throws InterpreterException { 266 ELActor myEventLoop = ELActor.currentActor(); 267 ATActorMirror oldMirror = myEventLoop.getImplicitActorMirror(); 268 myEventLoop.setActorMirror(newActorMirror); 269 return oldMirror; 270 } 271 272 /** 273 * def getExplicitActorMirror() 274 * => return an explicit actor mirror for the current actor. 275 * 276 * The default implementation uses the actor's implicit mirror as the 277 * default explicit mirror. 278 * 279 * @see ATActorMirror#base_getExplicitActorMirror() 280 */ 281 public ATActorMirror base_getExplicitActorMirror() throws InterpreterException { 282 return ELActor.currentActor().getImplicitActorMirror(); 283 } 284 285 /** 286 * This operation is 287 * introduced as a mechanism to alter the semantics of message reception for all objects 288 * owned by an actor. It can be used e.g. to keep track of all successfully processed messages. 289 * 290 * Note that this operation is *only* invoked for messages received from *other* 291 * actors (i.e. local or remote actors), it is *not* invoked for recursive asynchronous self-sends 292 * (intra-actor message sends)! This is an important change w.r.t pre-2.9 versions of AmbientTalk. 293 */ 294 public ATObject base_receive(ATObject receiver, ATAsyncMessage message) throws InterpreterException { 295 // this additional dispatch to receive will schedule an async self-send when performed 296 // on near references, which then invokes message.base_process in a later execution turn 297 // We do not short-circuit this behaviour for consistency purposes: receive is invoked 298 // on all receiver objects consistently, whether they are near refs, far refs, custom eventual 299 // refs or any other kind of mirage. 300 return receiver.meta_receive(message); 301 } 302 303 /** 304 * Export the given local object such that it is now remotely accessible via the 305 * returned object id. 306 * @param object a **near** reference to the object to export 307 * @return a local far reference to the object being exported 308 * @throws XIllegalOperation if the passed object is a far reference, i.e. non-local 309 */ 310 public ATObject base_createReference(ATObject object) throws InterpreterException { 311 // receptionist set will check whether ATObject is really local to me 312 return ELActor.currentActor().receptionists_.exportObject(object); 313 } 314 315 public ATActorMirror asActorMirror() throws XTypeMismatch { 316 return this; 317 } 318 319 /* ------------------------- 320 * -- Scheduling Protocol -- 321 * ------------------------- */ 322 323 /** 324 * The inbox of this actor. It contains objects that implement the {@link ATLetter} interface 325 */ 326 private LinkedList inbox_ = new LinkedList(); 327 328 /** 329 * A letter object is defined as: 330 * object: { 331 * def receiver := //receiver of the letter; 332 * def message := //the message that is being sent; 333 * def cancel() { //cancel the delivery of the letter } 334 * } 335 */ 336 public static class NATLetter extends NATObject { 337 private static final AGSymbol _RCVR_ = AGSymbol.jAlloc("receiver"); 338 private static final AGSymbol _MSG_ = AGSymbol.jAlloc("message"); 339 private static final AGSymbol _CANCEL_ = AGSymbol.jAlloc("cancel"); 340 public NATLetter(final LinkedList inbox, ATObject receiver, ATObject message) throws InterpreterException { 341 super(new ATTypeTag[] { NativeTypeTags._LETTER_ }); 342 meta_defineField(_RCVR_, receiver); 343 meta_defineField(_MSG_, message); 344 meta_defineField(_CANCEL_, new NativeClosure(this) { 345 public ATObject base_apply(ATTable args) throws InterpreterException { 346 inbox.remove(this); 347 return Evaluator.getNil(); 348 } 349 }); 350 } 351 public NATText meta_print() throws InterpreterException { 352 return NATText.atValue("<letter:"+impl_invokeAccessor(this, _MSG_, NATTable.EMPTY)+">"); 353 } 354 } 355 356 /** 357 * Returns a table with all letters currently in the inbox 358 */ 359 public ATTable base_listIncomingLetters() throws InterpreterException { 360 ATObject[] incoming = (ATObject[]) inbox_.toArray(new ATObject[inbox_.size()]); 361 return NATTable.atValue(incoming); 362 } 363 364 /** 365 * Creates a letter object and adds it to the actor's inbox 366 */ 367 public ATObject base_schedule(ATObject receiver, ATAsyncMessage message) throws InterpreterException { 368 NATLetter letter = new NATLetter(inbox_, receiver, message); 369 inbox_.addFirst(letter); 370 return letter; 371 } 372 373 /** 374 * Fetches the next letter from the actor's inbox, if any, and processes it. 375 */ 376 public ATObject base_serve() throws InterpreterException { 377 if (inbox_.size() > 0) { 378 ATObject next = (ATObject) inbox_.removeLast(); 379 ATLetter letter = next.asLetter(); 380 // receive has already been invoked prior to scheduling 381 // the receive is known to be a local object, therefore we 382 // can immediately process the message 383 return letter.base_message().base_process(letter.base_receiver()); 384 } else { 385 return Evaluator.getNil(); 386 } 387 } 388 389}