PageRenderTime 59ms CodeModel.GetById 2ms app.highlight 50ms RepoModel.GetById 2ms app.codeStats 0ms

/interpreter/tags/at2dist110511/src/edu/vub/at/actors/natives/NATActorMirror.java

http://ambienttalk.googlecode.com/
Java | 448 lines | 246 code | 38 blank | 164 comment | 13 complexity | abbf3d043324cc8bb47690335fbb2321 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.ATContext;
 43import edu.vub.at.objects.ATNil;
 44import edu.vub.at.objects.ATObject;
 45import edu.vub.at.objects.ATTable;
 46import edu.vub.at.objects.ATTypeTag;
 47import edu.vub.at.objects.coercion.NativeTypeTags;
 48import edu.vub.at.objects.grammar.ATSymbol;
 49import edu.vub.at.objects.mirrors.NATIntrospectiveMirror;
 50import edu.vub.at.objects.mirrors.NativeClosure;
 51import edu.vub.at.objects.mirrors.PrimitiveMethod;
 52import edu.vub.at.objects.natives.NATByRef;
 53import edu.vub.at.objects.natives.NATMethodInvocation;
 54import edu.vub.at.objects.natives.NATNumber;
 55import edu.vub.at.objects.natives.NATObject;
 56import edu.vub.at.objects.natives.NATTable;
 57import edu.vub.at.objects.natives.NATText;
 58import edu.vub.at.objects.natives.OBJLexicalRoot;
 59import edu.vub.at.objects.natives.grammar.AGSymbol;
 60
 61import java.util.LinkedList;
 62
 63/**
 64 * The NATActorMirror class implements the concurrency model of ambienttalk. It continually
 65 * consumes meta-events which are written to a synchronized queue. This way the actor
 66 * is notified of incoming messages, discovered and lost services, etc. When no meta-
 67 * messages are available, the actor consumes base-level messages as they are stored
 68 * in its inbox. These messages have a receiver object internal to the actor and they 
 69 * will be invoked on this receiver by the actor's thread.
 70 *
 71 * @author smostinc
 72 */
 73public class NATActorMirror extends NATByRef implements ATActorMirror {
 74	
 75	// INSTANCE VARIABLES
 76	
 77	// the actor mirror refers directly to its ELActor because
 78	// using ELActor.currentActor is slower
 79	private ELActor myActor_;
 80	private final ELDiscoveryActor discoveryActor_;
 81	
 82	/**
 83	 * When initializing a new actor, do not forget that this constructor is still executed by the
 84	 * creating actor, not by the created actor. To make the created actor perform something, it is
 85	 * necessary to use meta_receive to send itself messages for later execution.
 86	 */
 87	public NATActorMirror(ELVirtualMachine host) {
 88		discoveryActor_ = host.discoveryActor_;
 89	}
 90	
 91	/** set the mirror's base actor instance */
 92	protected void setActor(ELActor myActor) {
 93		myActor_ = myActor;
 94	}
 95	
 96    /* ------------------------------------------
 97     * -- Language Construct to Actor Protocol --
 98     * ------------------------------------------ */
 99
100	public ATAsyncMessage base_createMessage(ATSymbol selector, ATTable arguments, ATTable types) throws InterpreterException {
101		ATAsyncMessage msg = new NATAsyncMessage(selector, arguments, types);
102		// types.inject: msg into: { |constructingMsg, type| type.annotate(constructingMsg) }
103		ATAsyncMessage returnMsg = types.base_inject_into_(msg, new NativeClosure(this) {
104			public ATObject base_apply(ATTable args) throws InterpreterException {
105				checkArity(args, 2);
106				ATObject newMessage = get(args, 1);
107				ATObject type = get(args, 2);
108				return type.asTypeTag().base_annotateMessage(newMessage);
109			}
110		}).asAsyncMessage();
111		// if the message was indeed annotated, set the correct location informal on the original message.
112		if (! returnMsg.equals(msg)){
113			msg.impl_setLocation(types.impl_getLocation());
114		}
115		return returnMsg;
116	}
117	
118	public ATObject base_createMirror(ATObject reflectee) throws InterpreterException {
119		return NATIntrospectiveMirror.atValue(reflectee);
120	}
121	
122	/**
123	 * A publication object is defined as:
124	 * object: {
125	 *   def topic := //topic under which service is published;
126	 *   def service := //the exported service object;
127	 *   def cancel() { //unexport the service object }
128	 * }
129	 */
130	public static class NATPublication extends NATObject {
131		private static final AGSymbol _TOPIC_ = AGSymbol.jAlloc("topic");
132		private static final AGSymbol _SERVICE_ = AGSymbol.jAlloc("service");
133		private static final AGSymbol _CANCEL_ = AGSymbol.jAlloc("cancel");
134		public NATPublication(final ELDiscoveryActor discoveryActor,
135				              ATTypeTag topic, ATObject service,
136				              final Publication pub) throws InterpreterException {
137			meta_defineField(_TOPIC_, topic);
138			meta_defineField(_SERVICE_, service);
139			meta_addMethod(new PrimitiveMethod(_CANCEL_, NATTable.EMPTY) {
140			      public ATObject base_apply(ATTable arguments, ATContext ctx) throws InterpreterException {
141						int arity = arguments.base_length().asNativeNumber().javaValue;
142						if (arity != 0) {
143							throw new XArityMismatch("cancel", 0, arity);
144						}
145						discoveryActor.event_cancelPublication(pub);
146						return Evaluator.getNil();
147			      }
148			});
149		}
150		public NATText meta_print() throws InterpreterException {
151			return NATText.atValue("<publication:"+impl_invokeAccessor(this, _TOPIC_, NATTable.EMPTY)+">");
152		}
153	}
154	
155	/**
156	 * A subscription object is defined as:
157	 * object: {
158	 *   def topic := //topic subscribed to;
159	 *   def handler := //the closure to be triggered;
160	 *   def cancel() { //unsubscribe the handler }
161	 * }
162	 */
163	public static class NATSubscription extends NATObject {
164		private static final AGSymbol _TOPIC_ = AGSymbol.jAlloc("topic");
165		private static final AGSymbol _HANDLER_ = AGSymbol.jAlloc("handler");
166		private static final AGSymbol _CANCEL_ = AGSymbol.jAlloc("cancel");
167		public NATSubscription(final ELDiscoveryActor discoveryActor,
168				               ATTypeTag topic, ATClosure handler,
169				               final Subscription sub) throws InterpreterException {
170			meta_defineField(_TOPIC_, topic);
171			meta_defineField(_HANDLER_, handler);
172			meta_addMethod(new PrimitiveMethod(_CANCEL_, NATTable.EMPTY) {
173			      public ATObject base_apply(ATTable arguments, ATContext ctx) throws InterpreterException {
174						int arity = arguments.base_length().asNativeNumber().javaValue;
175						if (arity != 0) {
176							throw new XArityMismatch("cancel", 0, arity);
177						}
178						discoveryActor.event_cancelSubscription(sub);
179						return Evaluator.getNil();
180			      }
181			});
182		}
183		public NATText meta_print() throws InterpreterException {
184			return NATText.atValue("<subscription:"+impl_invokeAccessor(this, _TOPIC_, NATTable.EMPTY)+">");
185		}
186	}
187	
188	public ATObject base_provide(final ATTypeTag topic, final ATObject service) throws InterpreterException {
189		Publication pub = new Publication(myActor_,
190				new Packet(topic),
191				new Packet(service),
192				service);
193		discoveryActor_.event_servicePublished(pub);
194		return new NATPublication(discoveryActor_, topic, service, pub);
195	}
196	
197	public ATObject base_require(final ATTypeTag topic, final ATClosure handler, ATBoolean isPermanent) throws InterpreterException {
198		Subscription sub = new Subscription(myActor_,
199				                            new Packet(topic),
200				                            new Packet(handler),
201				                            isPermanent.asNativeBoolean().javaValue);
202		discoveryActor_.event_clientSubscribed(sub);
203		return new NATSubscription(discoveryActor_, topic, handler, sub);
204	}
205
206	public ATTable base_listPublications() throws InterpreterException {
207		Publication[] pubs = discoveryActor_.sync_event_listPublications(myActor_);
208        NATPublication[] natpubs = new NATPublication[pubs.length];
209        for(int i = 0; i < pubs.length; i++) {
210        	Publication pub = pubs[i];
211        	natpubs[i] = new NATPublication(
212        			discoveryActor_,
213        			pub.providedTypeTag_.unpack().asTypeTag(),
214        			pub.exportedService_.unpack(),
215        			pub);
216        }
217        return NATTable.atValue(natpubs);
218	}
219
220	public ATTable base_listSubscriptions() throws InterpreterException {
221		Subscription[] subs = discoveryActor_.sync_event_listSubscriptions(myActor_);
222		NATSubscription[] natsubs = new NATSubscription[subs.length];
223        for(int i = 0; i < subs.length; i++) {
224        	Subscription sub = subs[i];
225        	natsubs[i] = new NATSubscription(
226        			discoveryActor_,
227        			sub.requiredTypeTag_.unpack().asTypeTag(),
228        			sub.registeredHandler_.unpack().asClosure(),
229        			sub);
230        }
231        return NATTable.atValue(natsubs);
232	}
233	
234    /* --------------------------
235     * -- VM to Actor Protocol --
236     * -------------------------- */
237
238    public ATObject meta_clone() throws InterpreterException {
239        throw new XIllegalOperation("Cannot clone actor " + toString());
240    }
241
242    /**
243     * actor.new(closure)
244     *  => same effect as evaluating 'actor: closure'
245     */
246	public ATObject meta_newInstance(ATTable initargs) throws InterpreterException {
247		int length = initargs.base_length().asNativeNumber().javaValue;
248		if(length != 1)
249			throw new XArityMismatch("newInstance", 1, length);
250		
251		ATClosure closure = initargs.base_at(NATNumber.ONE).asClosure();
252		return OBJLexicalRoot._INSTANCE_.base_actor_(closure);
253	}
254	
255	public NATText meta_print() throws InterpreterException {
256		return NATText.atValue("<actormirror:" + this.hashCode() + ">");
257	}
258
259    public ATTable meta_typeTags() throws InterpreterException {
260    	return NATTable.of(NativeTypeTags._ACTORMIRROR_);
261    }
262	
263	/* -----------------------------
264	 * -- Object Passing Protocol --
265	 * ----------------------------- */
266	
267	/**
268	 * When default base-level objects send an asynchronous message, they delegate
269	 * this responsibility to their actor by means of this base-level method.
270	 * 
271	 * The actor's default implementation is to invoke the receiver mirror's <tt>receive</tt> method
272	 * which defines the default asynchronous message reception semantics.
273	 * 
274	 * Note: in pre-2.9 versions of AmbientTalk, this method did not immediately pass
275	 * control to the receiver via the <tt>receive</tt> method. By delegating to the receiver
276	 * in the same execution turn as the message send, we allow possible proxies (custom eventual
277	 * references) to intervene in the message sending process.
278	 */
279	public ATObject base_send(ATObject receiver, ATAsyncMessage message) throws InterpreterException {
280		return receiver.meta_receive(message);
281	}
282	
283	/**
284	 * def becomeMirroredBy: protocol
285	 *  => returns the old installed protocol
286	 * 
287	 * @see ATActorMirror#base_becomeMirroredBy_(ATClosure)
288	 */
289	public ATObject base_becomeMirroredBy_(ATActorMirror newActorMirror) throws InterpreterException {
290		ATActorMirror oldMirror = myActor_.getImplicitActorMirror();
291		myActor_.setActorMirror(newActorMirror);
292		return oldMirror;
293	}
294	
295	/**
296	 * def getExplicitActorMirror()
297	 *  => return an explicit actor mirror for the current actor.
298	 * 
299	 * The default implementation uses the actor's implicit mirror as the
300	 * default explicit mirror.
301	 * 
302	 * @see ATActorMirror#base_getExplicitActorMirror()
303	 */
304	public ATActorMirror base_getExplicitActorMirror() throws InterpreterException {
305		return myActor_.getImplicitActorMirror();
306	}
307	
308	/**
309	 * This operation is
310	 * introduced as a mechanism to alter the semantics of message reception for all objects
311	 * owned by an actor. It can be used e.g. to keep track of all successfully processed messages. 
312	 * 
313	 * Note that this operation is *only* invoked for messages received from *other*
314	 * actors (i.e. local or remote actors), it is *not* invoked for recursive asynchronous self-sends
315	 * (intra-actor message sends)! This is an important change w.r.t pre-2.9 versions of AmbientTalk.
316	 */
317	public ATObject base_receive(ATObject receiver, ATAsyncMessage message) throws InterpreterException {
318		// this additional dispatch to receive will schedule an async self-send when performed
319		// on near references, which then invokes message.base_process in a later execution turn
320		// We do not short-circuit this behaviour for consistency purposes: receive is invoked
321		// on all receiver objects consistently, whether they are near refs, far refs, custom eventual
322		// refs or any other kind of mirage.
323		return receiver.meta_receive(message);
324	}
325	
326	/**
327	 * Export the given local object such that it is now remotely accessible via the
328	 * returned object id.
329	 * @param object a **near** reference to the object to export
330	 * @return a local far reference to the object being exported
331	 * @throws XIllegalOperation if the passed object is a far reference, i.e. non-local
332	 */
333	public ATObject base_createReference(ATObject object) throws InterpreterException {
334		// receptionist set will check whether ATObject is really local to me
335		return myActor_.receptionists_.exportObject(object);
336	}
337	
338	/**
339	 * Provides access to this actor's "behaviour" object. This is the first
340	 * object created within an actor.
341	 * 
342	 * Note: if the behaviour is accessed when evaluating the "init.at" initialization
343	 * file of an actor, the behaviour will <em>not have been initialized</em> yet.
344	 * It will appear as an empty object.
345	 */
346	public ATObject base_behaviour() throws InterpreterException {
347		return myActor_.behaviour_;
348	}
349	
350    public ATActorMirror asActorMirror() throws XTypeMismatch {
351    	return this;
352    }
353    
354    public NATActorMirror asNativeActorMirror() throws XTypeMismatch {
355    	return this;
356    }
357    
358    /* -------------------------
359	 * -- Scheduling Protocol --
360	 * ------------------------- */
361    
362    /**
363     * The inbox of this actor. It contains objects that implement the {@link ATLetter} interface
364     */
365    private LinkedList inbox_ = new LinkedList();
366	
367	/**
368	 * A letter object is defined as:
369	 * object: {
370	 *   def receiver := //receiver of the letter;
371	 *   def message := //the message that is being sent;
372	 *   def cancel() { //cancel the delivery of the letter }
373	 * }
374	 */
375	public static class NATLetter extends NATObject implements ATLetter {
376		private static final AGSymbol _RCVR_ = AGSymbol.jAlloc("receiver");
377		private static final AGSymbol _MSG_ = AGSymbol.jAlloc("message");
378		private static final AGSymbol _CANCEL_ = AGSymbol.jAlloc("cancel");
379		public NATLetter(final LinkedList mailbox, ATObject receiver, ATObject message) throws InterpreterException {
380			super(new ATTypeTag[] { NativeTypeTags._LETTER_ });
381			meta_defineField(_RCVR_, receiver);
382			meta_defineField(_MSG_, message);
383			final NATLetter thisLetter = this;
384			meta_addMethod(new PrimitiveMethod(_CANCEL_, NATTable.EMPTY) {
385			      public ATObject base_apply(ATTable arguments, ATContext ctx) throws InterpreterException {
386						int arity = arguments.base_length().asNativeNumber().javaValue;
387						if (arity != 0) {
388							throw new XArityMismatch("cancel", 0, arity);
389						}
390						// Note: if the receiver and message fields are changed by an AmbientTalk program
391						// canceling the letter will still remove the original letter, not a letter that corresponds
392						// to the new receiver and message.
393						mailbox.remove(thisLetter);
394						return Evaluator.getNil();
395			      }
396			});
397		}
398		public NATText meta_print() throws InterpreterException {
399			return NATText.atValue("<letter:"+impl_invokeAccessor(this, _MSG_, NATTable.EMPTY)+">");
400		}
401
402		public ATLetter asLetter() { return this; }
403		public ATObject base_cancel() throws InterpreterException {
404			return this.meta_invoke(this, new NATMethodInvocation(_CANCEL_, NATTable.EMPTY, NATTable.EMPTY));
405		}
406		public ATAsyncMessage base_message() throws InterpreterException {
407			return this.meta_invokeField(this, _MSG_).asAsyncMessage();
408		}
409		public ATObject base_receiver() throws InterpreterException {
410			return this.meta_invokeField(this, _RCVR_);
411		}
412	}
413
414	/**
415	 * Returns a table with all letters currently in the inbox
416	 */
417	public ATTable base_listIncomingLetters() throws InterpreterException {
418		ATObject[] incoming = (ATObject[]) inbox_.toArray(new ATObject[inbox_.size()]);
419		return NATTable.atValue(incoming);
420	}
421
422	/**
423	 * Creates a letter object and adds it to the actor's inbox
424	 */
425	public ATObject base_schedule(ATObject receiver, ATAsyncMessage message) throws InterpreterException {
426		NATLetter letter = new NATLetter(inbox_, receiver, message);
427		inbox_.addFirst(letter);
428    	// signal a serve event for every message that is scheduled
429    	myActor_.event_serve();
430		return letter;
431	}
432
433	/**
434	 * Fetches the next letter from the actor's inbox, if any, and processes it.
435	 */
436	public ATObject base_serve() throws InterpreterException {
437		if (inbox_.size() > 0) {
438			ATObject next = (ATObject) inbox_.removeLast();
439			ATLetter letter = next.asLetter();
440			// receive has already been invoked prior to scheduling
441			// the receive is known to be a local object, therefore we
442			// can immediately process the message
443			return letter.base_message().base_process(letter.base_receiver());
444		} else {
445			return Evaluator.getNil();
446		}
447	}
448}