PageRenderTime 49ms CodeModel.GetById 25ms app.highlight 18ms RepoModel.GetById 1ms app.codeStats 0ms

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

http://ambienttalk.googlecode.com/
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}