PageRenderTime 39ms CodeModel.GetById 13ms app.highlight 23ms RepoModel.GetById 1ms app.codeStats 0ms

/interpreter/tags/at2-build060407/src/edu/vub/at/actors/natives/NATActorMirror.java

http://ambienttalk.googlecode.com/
Java | 346 lines | 154 code | 33 blank | 159 comment | 4 complexity | 8719acded08723864bb8f0eaf18283c3 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.eventloops.BlockingFuture;
 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.ATStripe;
 44import edu.vub.at.objects.ATTable;
 45import edu.vub.at.objects.coercion.NativeStripes;
 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.NATMethod;
 51import edu.vub.at.objects.natives.NATNil;
 52import edu.vub.at.objects.natives.NATNumber;
 53import edu.vub.at.objects.natives.NATObject;
 54import edu.vub.at.objects.natives.NATTable;
 55import edu.vub.at.objects.natives.NATText;
 56import edu.vub.at.objects.natives.OBJLexicalRoot;
 57import edu.vub.at.objects.natives.grammar.AGBegin;
 58import edu.vub.at.objects.natives.grammar.AGSymbol;
 59
 60/**
 61 * The NATActorMirror class implements the concurrency model of ambienttalk. It continually
 62 * consumes meta-events which are written to a synchronized queue. This way the actor
 63 * is notified of incoming messages, discovered and lost services, etc. When no meta-
 64 * messages are available, the actor consumes base-level messages as they are stored
 65 * in its inbox. These messages have a receiver object internal to the actor and they 
 66 * will be invoked on this receiver by the actor's thread.
 67 *
 68 * @author smostinc
 69 */
 70public class NATActorMirror extends NATByRef implements ATActorMirror {
 71	
 72	// INSTANCE VARIABLES
 73	
 74	private final ELDiscoveryActor discoveryActor_;
 75	
 76	/**
 77	 * Creates a new actor on the specified host Virtual Machine. The actor its behaviour
 78	 * is intialized by means of the passed parameters and initialization code. The calling
 79	 * thread is **blocked** until the actor has been constructed. However, actor behaviour
 80	 * and root initialization is carried out by the newly created actor itself.
 81	 * 
 82	 * @param host the VM hosting this actor - after creation, the actor registers itself with this VM
 83	 * @param parametersPkt the serialized parameters used to invoke the initialization code
 84	 * @param initcodePkt the serialized initialization code used to initialize the actor behaviour
 85	 * @param actorMirror this actor's mirror
 86	 * @return a far reference to the behaviour of the actor
 87	 * @throws InterpreterException
 88	 */
 89	public static NATLocalFarRef createActor(ELVirtualMachine host,
 90			                                 Packet parametersPkt,
 91			                                 Packet initcodePkt,
 92			                                 ATActorMirror actorMirror) throws InterpreterException {
 93		
 94		BlockingFuture future = new BlockingFuture();
 95		ELActor processor = new ELActor(actorMirror, host);
 96		
 97		// notify host VM about my creation
 98		host.actorCreated(processor);
 99		
100		// schedule special 'init' message which will:
101		// A) create a new behaviour and will unblock creating actor (by passing it a far ref via the future)
102		// B) unpack the parameters used to invoke the initializatin code
103		// C) unpack the init code to initialize the behaviour
104		// D) initialize the root and lobby objects of this actor
105		processor.event_init(future, parametersPkt, initcodePkt);
106	    
107		try {
108			return (NATLocalFarRef) future.get();
109		} catch (Exception e) {
110			throw (InterpreterException) e;
111		}
112	}
113	
114	/**
115	 * Auxiliary creation method to create an actor with an empty behaviour.
116	 * Equivalent to evaluating:
117	 * 
118	 * actor: { nil }
119	 */
120	public static NATLocalFarRef createEmptyActor(ELVirtualMachine host, ATActorMirror actorMirror) throws InterpreterException {
121		Packet noParams = new Packet(NATTable.EMPTY);
122		Packet noinitcode = new Packet(new NATMethod(Evaluator._ANON_MTH_NAM_, NATTable.EMPTY, new AGBegin(NATTable.of(NATNil._INSTANCE_))));
123		return createActor(host, noParams, noinitcode, actorMirror);
124	}
125	
126	
127	/**
128	 * When initializing a new actor, do not forget that this constructor is still executed by the
129	 * creating actor, not by the created actor. To make the created actor perform something, it is
130	 * necessary to use meta_receive to send itself messages for later execution.
131	 */
132	public NATActorMirror(ELVirtualMachine host) {
133		discoveryActor_ = host.discoveryActor_;
134	}
135	
136    /* ------------------------------------------
137     * -- Language Construct to Actor Protocol --
138     * ------------------------------------------ */
139
140	public ATAsyncMessage base_createMessage(ATSymbol selector, ATTable arguments, ATTable stripes) throws InterpreterException {
141		return new NATAsyncMessage(NATNil._INSTANCE_, selector, arguments, stripes);
142	}
143	
144	public ATObject base_createMirror(ATObject reflectee) throws InterpreterException {
145		return NATIntrospectiveMirror.atValue(reflectee);
146	}
147	
148	/**
149	 * A publication object is defined as:
150	 * object: {
151	 *   def topic := //topic under which service is published;
152	 *   def service := //the exported service object;
153	 *   def cancel() { //unexport the service object }
154	 * }
155	 */
156	public static class NATPublication extends NATObject {
157		private static final AGSymbol _TOPIC_ = AGSymbol.jAlloc("topic");
158		private static final AGSymbol _SERVICE_ = AGSymbol.jAlloc("service");
159		private static final AGSymbol _CANCEL_ = AGSymbol.jAlloc("cancel");
160		public NATPublication(final ELDiscoveryActor discoveryActor, ATStripe topic, ATObject service, final Publication pub) throws InterpreterException {
161			meta_defineField(_TOPIC_, topic);
162			meta_defineField(_SERVICE_, service);
163			meta_defineField(_CANCEL_, 	new NativeClosure(this) {
164				public ATObject base_apply(ATTable args) throws InterpreterException {
165					discoveryActor.event_cancelPublication(pub);
166					return NATNil._INSTANCE_;
167				}
168			});
169		}
170		public NATText meta_print() throws InterpreterException {
171			return NATText.atValue("<publication:"+meta_select(this, _TOPIC_)+">");
172		}
173	}
174	
175	/**
176	 * A subscription object is defined as:
177	 * object: {
178	 *   def topic := //topic subscribed to;
179	 *   def handler := //the closure to be triggered;
180	 *   def cancel() { //unsubscribe the handler }
181	 * }
182	 */
183	public static class NATSubscription extends NATObject {
184		private static final AGSymbol _TOPIC_ = AGSymbol.jAlloc("topic");
185		private static final AGSymbol _HANDLER_ = AGSymbol.jAlloc("handler");
186		private static final AGSymbol _CANCEL_ = AGSymbol.jAlloc("cancel");
187		public NATSubscription(final ELDiscoveryActor discoveryActor,
188				               ATStripe topic, ATClosure handler,
189				               final Subscription sub) throws InterpreterException {
190			meta_defineField(_TOPIC_, topic);
191			meta_defineField(_HANDLER_, handler);
192			meta_defineField(_CANCEL_, 	new NativeClosure(this) {
193				public ATObject base_apply(ATTable args) throws InterpreterException {
194					discoveryActor.event_cancelSubscription(sub);
195					return NATNil._INSTANCE_;
196				}
197			});
198		}
199		public NATText meta_print() throws InterpreterException {
200			return NATText.atValue("<subscription:"+meta_select(this, _TOPIC_)+">");
201		}
202	}
203	
204	public ATObject base_provide(final ATStripe topic, final ATObject service) throws InterpreterException {
205		Publication pub = new Publication(ELActor.currentActor(),
206				                          new Packet(topic),
207				                          new Packet(service));
208		discoveryActor_.event_servicePublished(pub);
209		return new NATPublication(discoveryActor_, topic, service, pub);
210	}
211	
212	public ATObject base_require(final ATStripe topic, final ATClosure handler, ATBoolean isPermanent) throws InterpreterException {
213		Subscription sub = new Subscription(ELActor.currentActor(),
214				                            new Packet(topic),
215				                            new Packet(handler),
216				                            isPermanent.asNativeBoolean().javaValue);
217		discoveryActor_.event_clientSubscribed(sub);
218		return new NATSubscription(discoveryActor_, topic, handler, sub);
219	}
220	
221    /* --------------------------
222     * -- VM to Actor Protocol --
223     * -------------------------- */
224
225    public ATObject meta_clone() throws InterpreterException {
226        throw new XIllegalOperation("Cannot clone actor " + toString());
227    }
228
229    /**
230     * actor.new(closure)
231     *  => same effect as evaluating 'actor: closure'
232     */
233	public ATObject meta_newInstance(ATTable initargs) throws InterpreterException {
234		int length = initargs.base_getLength().asNativeNumber().javaValue;
235		if(length != 1)
236			throw new XArityMismatch("newInstance", 1, length);
237		
238		ATClosure closure = initargs.base_at(NATNumber.ONE).asClosure();
239		return OBJLexicalRoot._INSTANCE_.base_actor_(closure);
240	}
241	
242	public NATText meta_print() throws InterpreterException {
243		return NATText.atValue("<actormirror:" + this.hashCode() + ">");
244	}
245
246	/* -----------------------------
247	 * -- Object Passing Protocol --
248	 * ----------------------------- */
249	
250	/**
251	 * To send a message msg to a receiver object rcv:
252	 *  - if rcv is a local reference, schedule accept(msg) in my incoming event queue
253	 *  - if rcv is a far reference, schedule msg in far reference's outbox
254	 */
255	public ATObject meta_send(ATAsyncMessage msg) throws InterpreterException {
256		ATObject rcv = msg.base_getReceiver();
257		if (rcv.isFarReference()) {
258			return rcv.meta_receive(msg);
259		} else {
260			return this.meta_receive(msg);
261		}
262	}
263	
264	public ATObject meta_receive(ATAsyncMessage msg) throws InterpreterException {
265		ELActor.currentActor().event_acceptSelfSend(msg);
266		return NATNil._INSTANCE_;
267	}
268	
269    public ATTable meta_getStripes() throws InterpreterException {
270    	return NATTable.of(NativeStripes._ACTORMIRROR_);
271    }
272	
273	/**
274	 * When default base-level objects send an asynchronous message, they delegate
275	 * this responsibility to their actor by means of this base-level method. The actor's
276	 * base-level 'send' operation dispatches to its meta-level 'send' operation. In effect,
277	 * the semantics of an object sending an async message are the same as those of an actor
278	 * sending an async message directly.
279	 * 
280	 * TODO(discuss) is this the desirable semantics for the base-level hook?
281	 */
282	public ATObject base_send(ATAsyncMessage message) throws InterpreterException {
283		return meta_send(message);
284	}
285	
286	/**
287	 * def install: protocol
288	 *  => returns the old installed protocol
289	 * 
290	 * @see ATActorMirror#base_install_(ATClosure)
291	 */
292	public ATObject base_install_(ATActorMirror newActorMirror) throws InterpreterException {
293		ELActor myEventLoop = ELActor.currentActor();
294		ATActorMirror oldMirror = myEventLoop.getActorMirror();
295		myEventLoop.setActorMirror(newActorMirror);
296		return oldMirror;
297	}
298	
299	/**
300	 * A protocol object is defined as:
301	 * object: {
302	 *   def installedMirror := //the installed actor mirror;
303	 *   def uninstall() { //uninstall the protocol object }
304	 * }
305	 */
306	/*public static class NATMOPInstallation extends NATObject {
307		private static final AGSymbol _INSTALLED_ = AGSymbol.jAlloc("installedMirror");
308		private static final AGSymbol _UNINSTALL_ = AGSymbol.jAlloc("uninstall");
309		public NATMOPInstallation(final ELActor eventLoop, ATActorMirror newMirror) throws InterpreterException {
310			meta_defineField(_INSTALLED_, newMirror);
311			meta_defineField(_UNINSTALL_, 	new NativeClosure(this) {
312				public ATObject base_apply(ATTable args) throws InterpreterException {
313					ATObject mirrorToRemove = scope_.meta_select(scope_, _INSTALLED_);
314					
315					ATObject current = eventLoop.getActorMirror();
316					if (current.equals(mirrorToRemove)) {
317						// just set the actor mirror to the parent
318						eventLoop.setActorMirror(mirrorToRemove.meta_getDynamicParent().base_asActorMirror());
319					} else {
320						// find the child of the mirror to remove
321						while ((current != NATNil._INSTANCE_) && !current.meta_getDynamicParent().equals(mirrorToRemove)) {
322							current = current.meta_getDynamicParent();
323						}
324						if (current == NATNil._INSTANCE_) {
325							// mirror not found
326							throw new XIllegalOperation("Tried to uninstall a protocol that was not installed: " + mirrorToRemove);
327						} else {
328							// current.super := mirrorToRemove.super
329							current.meta_assignField(current, NATObject._SUPER_NAME_, mirrorToRemove.meta_getDynamicParent());
330						}
331					}
332					
333					return NATNil._INSTANCE_;
334				}
335			});
336	    }
337		public NATText meta_print() throws InterpreterException {
338			return NATText.atValue("<protocol:"+meta_select(this, _INSTALLED_)+">");
339		}
340	}*/
341	
342    public ATActorMirror asActorMirror() throws XTypeMismatch {
343    	return this;
344    }
345		
346}