PageRenderTime 28ms CodeModel.GetById 14ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

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

http://ambienttalk.googlecode.com/
Java | 304 lines | 156 code | 32 blank | 116 comment | 4 complexity | ef8acfba9152193fe8cd51309ff7e6b2 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.ATTypeTag;
 44import edu.vub.at.objects.ATTable;
 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.NATMethod;
 51import edu.vub.at.objects.natives.OBJNil;
 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(OBJNil._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 types) throws InterpreterException {
141		return new NATAsyncMessage(selector, arguments, types);
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,
161				              ATTypeTag topic, ATObject service,
162				              final Publication pub) throws InterpreterException {
163			meta_defineField(_TOPIC_, topic);
164			meta_defineField(_SERVICE_, service);
165			meta_defineField(_CANCEL_, 	new NativeClosure(this) {
166				public ATObject base_apply(ATTable args) throws InterpreterException {
167					discoveryActor.event_cancelPublication(pub);
168					return OBJNil._INSTANCE_;
169				}
170			});
171		}
172		public NATText meta_print() throws InterpreterException {
173			return NATText.atValue("<publication:"+impl_invokeAccessor(this, _TOPIC_, NATTable.EMPTY)+">");
174		}
175	}
176	
177	/**
178	 * A subscription object is defined as:
179	 * object: {
180	 *   def topic := //topic subscribed to;
181	 *   def handler := //the closure to be triggered;
182	 *   def cancel() { //unsubscribe the handler }
183	 * }
184	 */
185	public static class NATSubscription extends NATObject {
186		private static final AGSymbol _TOPIC_ = AGSymbol.jAlloc("topic");
187		private static final AGSymbol _HANDLER_ = AGSymbol.jAlloc("handler");
188		private static final AGSymbol _CANCEL_ = AGSymbol.jAlloc("cancel");
189		public NATSubscription(final ELDiscoveryActor discoveryActor,
190				               ATTypeTag topic, ATClosure handler,
191				               final Subscription sub) throws InterpreterException {
192			meta_defineField(_TOPIC_, topic);
193			meta_defineField(_HANDLER_, handler);
194			meta_defineField(_CANCEL_, 	new NativeClosure(this) {
195				public ATObject base_apply(ATTable args) throws InterpreterException {
196					discoveryActor.event_cancelSubscription(sub);
197					return OBJNil._INSTANCE_;
198				}
199			});
200		}
201		public NATText meta_print() throws InterpreterException {
202			return NATText.atValue("<subscription:"+impl_invokeAccessor(this, _TOPIC_, NATTable.EMPTY)+">");
203		}
204	}
205	
206	public ATObject base_provide(final ATTypeTag topic, final ATObject service) throws InterpreterException {
207		Publication pub = new Publication(ELActor.currentActor(),
208				                          new Packet(topic),
209				                          new Packet(service));
210		discoveryActor_.event_servicePublished(pub);
211		return new NATPublication(discoveryActor_, topic, service, pub);
212	}
213	
214	public ATObject base_require(final ATTypeTag topic, final ATClosure handler, ATBoolean isPermanent) throws InterpreterException {
215		Subscription sub = new Subscription(ELActor.currentActor(),
216				                            new Packet(topic),
217				                            new Packet(handler),
218				                            isPermanent.asNativeBoolean().javaValue);
219		discoveryActor_.event_clientSubscribed(sub);
220		return new NATSubscription(discoveryActor_, topic, handler, sub);
221	}
222	
223    /* --------------------------
224     * -- VM to Actor Protocol --
225     * -------------------------- */
226
227    public ATObject meta_clone() throws InterpreterException {
228        throw new XIllegalOperation("Cannot clone actor " + toString());
229    }
230
231    /**
232     * actor.new(closure)
233     *  => same effect as evaluating 'actor: closure'
234     */
235	public ATObject meta_newInstance(ATTable initargs) throws InterpreterException {
236		int length = initargs.base_length().asNativeNumber().javaValue;
237		if(length != 1)
238			throw new XArityMismatch("newInstance", 1, length);
239		
240		ATClosure closure = initargs.base_at(NATNumber.ONE).asClosure();
241		return OBJLexicalRoot._INSTANCE_.base_actor_(closure);
242	}
243	
244	public NATText meta_print() throws InterpreterException {
245		return NATText.atValue("<actormirror:" + this.hashCode() + ">");
246	}
247
248	/* -----------------------------
249	 * -- Object Passing Protocol --
250	 * ----------------------------- */
251	
252	/**
253	 * To send a message msg to a receiver object rcv:
254	 *  - if rcv is a local reference, schedule accept(msg) in my incoming event queue
255	 *  - if rcv is a far reference, schedule msg in far reference's outbox
256	 */
257	public ATObject meta_send(ATObject receiver, ATAsyncMessage msg) throws InterpreterException {
258		if (receiver.isFarReference()) {
259			return receiver.meta_receive(msg);
260		} else {
261			//return this.meta_receive(msg);
262			ELActor.currentActor().event_acceptSelfSend(receiver, msg);
263			return OBJNil._INSTANCE_;
264		}
265	}
266	
267	public ATObject meta_receive(ATAsyncMessage msg) throws InterpreterException {
268		ELActor.currentActor().event_acceptSelfSend(this, msg);
269		return OBJNil._INSTANCE_;
270	}
271	
272    public ATTable meta_typeTags() throws InterpreterException {
273    	return NATTable.of(NativeTypeTags._ACTORMIRROR_);
274    }
275	
276	/**
277	 * When default base-level objects send an asynchronous message, they delegate
278	 * this responsibility to their actor by means of this base-level method. The actor's
279	 * base-level 'send' operation dispatches to its meta-level 'send' operation. In effect,
280	 * the semantics of an object sending an async message are the same as those of an actor
281	 * sending an async message directly.
282	 */
283	public ATObject base_send(ATObject receiver, ATAsyncMessage message) throws InterpreterException {
284		return meta_send(receiver, message);
285	}
286	
287	/**
288	 * def install: protocol
289	 *  => returns the old installed protocol
290	 * 
291	 * @see ATActorMirror#base_install_(ATClosure)
292	 */
293	public ATObject base_install_(ATActorMirror newActorMirror) throws InterpreterException {
294		ELActor myEventLoop = ELActor.currentActor();
295		ATActorMirror oldMirror = myEventLoop.getActorMirror();
296		myEventLoop.setActorMirror(newActorMirror);
297		return oldMirror;
298	}
299	
300    public ATActorMirror asActorMirror() throws XTypeMismatch {
301    	return this;
302    }
303		
304}