PageRenderTime 68ms CodeModel.GetById 39ms app.highlight 24ms RepoModel.GetById 1ms app.codeStats 0ms

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

http://ambienttalk.googlecode.com/
Java | 509 lines | 290 code | 60 blank | 159 comment | 32 complexity | 6302b1d4abd6a2769bb0291edce74cd2 MD5 | raw file
  1/**
  2 * AmbientTalk/2 Project
  3 * NATFarReference.java created on Dec 6, 2006 at 9:53:20 AM
  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 java.util.Iterator;
 31import java.util.Vector;
 32
 33import edu.vub.at.actors.ATAsyncMessage;
 34import edu.vub.at.actors.ATFarReference;
 35import edu.vub.at.actors.id.ATObjectID;
 36import edu.vub.at.eval.Evaluator;
 37import edu.vub.at.exceptions.InterpreterException;
 38import edu.vub.at.exceptions.XIllegalOperation;
 39import edu.vub.at.exceptions.XObjectOffline;
 40import edu.vub.at.exceptions.XSelectorNotFound;
 41import edu.vub.at.exceptions.XTypeMismatch;
 42import edu.vub.at.objects.ATBoolean;
 43import edu.vub.at.objects.ATClosure;
 44import edu.vub.at.objects.ATField;
 45import edu.vub.at.objects.ATMethod;
 46import edu.vub.at.objects.ATNil;
 47import edu.vub.at.objects.ATObject;
 48import edu.vub.at.objects.ATStripe;
 49import edu.vub.at.objects.ATTable;
 50import edu.vub.at.objects.grammar.ATSymbol;
 51import edu.vub.at.objects.mirrors.NativeClosure;
 52import edu.vub.at.objects.natives.NATBoolean;
 53import edu.vub.at.objects.natives.NATByCopy;
 54import edu.vub.at.objects.natives.NATNil;
 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.grammar.AGSymbol;
 59import edu.vub.at.util.logging.Logging;
 60
 61/**
 62 * 
 63 * NATFarReference is the root of the native classes that represent native far references.
 64 * The AmbientTalk/2 implementation distinguishes between two kinds of far references:
 65 * local and remote far references. The former denote far references to objects hosted by
 66 * actors on the same virtual machine. The latter ones denote far references to remote objects
 67 * that are hosted on a separate virtual (and usually even physical) machine.
 68 * 
 69 * This abstract superclass encapsulates all of the code that these two kinds of far references
 70 * have in common. The variabilities are delegated to the subclasses. Subclasses should implement
 71 * an abstract method (transmit) which is invoked by this class when the far reference receives
 72 * a message to be forwarded to the remote principal.
 73 * 
 74 * Note that far references are pass by copy and resolve to either a near or a new
 75 * actor-local far reference.
 76 * 
 77 * Far references encapsulate the same stripes as the remote object they represent.
 78 * As such it becomes possible to perform a stripe test on a far reference as if it
 79 * was performed on the local object itself!
 80 * 
 81 * @author tvcutsem
 82 * @author smostinc
 83 */
 84public abstract class NATFarReference extends NATByCopy implements ATFarReference {
 85	
 86	// encodes the identity of the far object pointed at
 87	private final ATObjectID objectId_;
 88	
 89	// the stripes with which the remote object is tagged
 90	private final ATStripe[] stripes_;
 91
 92	private transient Vector disconnectedListeners_; // lazy initialization
 93	private transient Vector reconnectedListeners_; // lazy initialization
 94	private transient Vector expiredListeners_; // lazy initialization
 95    private transient boolean connected_;
 96    private final transient ELActor owner_;
 97	
 98	protected NATFarReference(ATObjectID objectId, ATStripe[] stripes, ELActor owner) {
 99		objectId_ = objectId;
100		stripes_ = stripes;
101		connected_ = true;
102		owner_ = owner;
103	}
104	
105	public ATObjectID getObjectId() {
106		return objectId_;
107	}
108	
109	public NATFarReference asNativeFarReference() throws XTypeMismatch {
110		return this;
111	}
112		
113	public synchronized void addDisconnectionListener(ATObject listener) {
114		if (disconnectedListeners_ == null) {
115			disconnectedListeners_ = new Vector(1);
116		}
117		disconnectedListeners_.add(listener);
118		
119		if (!connected_) {
120			try {
121
122				owner_.event_acceptSelfSend(new NATAsyncMessage(
123						listener, Evaluator._APPLY_, NATTable.atValue(new ATObject[] { NATTable.EMPTY }), NATTable.EMPTY));
124			} catch (InterpreterException e) {
125				Logging.RemoteRef_LOG.error(
126						"error invoking when:disconnected: listener", e);
127			}
128		}
129	}
130	
131	public synchronized void addReconnectionListener(ATObject listener) {
132		if (reconnectedListeners_ == null) {
133			reconnectedListeners_ = new Vector(1);
134		}
135		reconnectedListeners_.add(listener);
136	}
137
138	public synchronized void removeDisconnectionListener(ATObject listener) {
139		if (disconnectedListeners_ != null) {
140			disconnectedListeners_.remove(listener);
141		}
142	}
143	
144	public synchronized void removeReconnectionListener(ATObject listener) {
145		if (reconnectedListeners_ != null) {
146			reconnectedListeners_.remove(listener);
147		}
148	}
149	
150	public synchronized void addExpiredListener(ATObject listener) {
151		if (expiredListeners_ == null) {
152			expiredListeners_ = new Vector(1);
153		}
154		expiredListeners_.add(listener);
155	}
156
157	public synchronized void removeExpiredListener(ATObject listener) {
158		if (expiredListeners_ != null) {
159			expiredListeners_.remove(listener);
160		}
161	}
162	
163	public synchronized void notifyConnected() {	
164		connected_= true;
165		if (reconnectedListeners_ != null) {
166			for (Iterator reconnectedIter = reconnectedListeners_.iterator(); reconnectedIter.hasNext();) {
167				triggerListener((ATObject) reconnectedIter.next(), "when:reconnected:");
168			}	
169		}
170	}
171	
172	public synchronized void notifyDisconnected(){
173		connected_ = false;
174		if (disconnectedListeners_ != null) {
175			for (Iterator disconnectedIter = disconnectedListeners_.iterator(); disconnectedIter.hasNext();) {
176				triggerListener((ATObject) disconnectedIter.next(), "when:disconnected:");
177			}	
178		}
179	}
180
181	/**
182	 * Taking offline an object results in a "logical" disconnection of the far remote reference.
183	 * This means that the ref becomes expired but also disconnected.
184	 * Thus, all disconnectedlisteners and expiredlisteners are notified.
185	 */
186	public synchronized void notifyExpired(){
187		connected_ = false;
188		if (expiredListeners_ != null) {
189			for (Iterator expiredIter = expiredListeners_.iterator(); expiredIter.hasNext();) {
190				triggerListener((ATObject) expiredIter.next(), "when:expired:");
191			}
192		}
193		notifyDisconnected();
194	}
195	
196	/**
197	 * After deserialization, ensure that only one unique remote reference exists for
198	 * my target.
199	 */
200	public ATObject meta_resolve() throws InterpreterException, XObjectOffline {
201		// it may be that the once local target object is now remote!
202		return ELActor.currentActor().resolve(objectId_, stripes_);
203	}
204
205	/* ------------------------------
206     * -- Message Sending Protocol --
207     * ------------------------------ */
208
209	public ATObject meta_receive(ATAsyncMessage message) throws InterpreterException {
210		return this.transmit(message);
211	}
212	
213	protected abstract ATObject transmit(ATAsyncMessage passedMessage) throws InterpreterException;
214
215	/**
216	 * The only operation that is allowed to be synchronously invoked on far references is '=='
217	 * @throws XIllegalOperation Cannot synchronously invoke a method on a far reference
218	 */
219	public ATObject meta_invoke(ATObject receiver, ATSymbol atSelector, ATTable arguments) throws InterpreterException {
220		if (atSelector.equals(NATObject._EQL_NAME_)) {
221			return super.meta_invoke(receiver, atSelector, arguments);
222		}
223		throw new XIllegalOperation("Cannot invoke " + atSelector + " on far reference " + this);
224	}
225
226	/**
227	 * @return true if and only if the far object is queried for responses to basic operations such as ==
228	 */
229	public ATBoolean meta_respondsTo(ATSymbol atSelector) throws InterpreterException {
230		return super.meta_respondsTo(atSelector);
231	}
232
233	/**
234	 * @throws XSelectorNotFound to ensure proper semantics should the interpreter be
235	 * extended such that it allows extending a far reference in the future.
236	 */
237	public ATObject meta_doesNotUnderstand(ATSymbol selector) throws InterpreterException {
238		return super.meta_doesNotUnderstand(selector);
239	}
240
241	/* ------------------------------------
242     * -- Extension and cloning protocol --
243     * ------------------------------------ */
244
245	/**
246	 * References to objects hosted by another actor are forced to be unique. Therefore
247	 * cloning them throws an XIllegalOperation to avoid inconsistencies by performing
248	 * state updates (through sent messages) after a clone operation. 
249	 * 
250	 * TODO(discuss) clone: farObject may create a clone on the other actor.
251	 */
252	public ATObject meta_clone() throws InterpreterException {
253		throw new XIllegalOperation("Cannot clone far reference " + this);
254	}
255
256	/**
257	 * Cannot create a new instance using a farObject, this should be done either by 
258	 * sending rather than invoking new(args) such that the correct method is triggered
259	 * or by invoking newInstance on a farMirror, which will send the call as well. 
260	 */
261	public ATObject meta_newInstance(ATTable initargs) throws InterpreterException {
262		throw new XIllegalOperation("Cannot create new instance of far reference " + this);
263	}
264	
265	/* ------------------------------------------
266     * -- Slot accessing and mutating protocol --
267     * ------------------------------------------ */
268	
269	/**
270	 * @throws XIllegalOperation - cannot select in objects hosted by another actor.
271	 */
272	public ATObject meta_select(ATObject receiver, ATSymbol selector) throws InterpreterException {
273		throw new XIllegalOperation("Cannot select " + selector + " from far reference " + this);
274	}
275
276	/**
277	 * @throws XIllegalOperation - cannot lookup in objects hosted by another actor.
278	 */
279	public ATObject meta_lookup(ATSymbol selector) throws InterpreterException {
280		throw new XIllegalOperation("Cannot lookup " + selector + " from far reference " + this);
281	}
282
283	/**
284	 * @throws XIllegalOperation - cannot define in objects hosted by another actor.
285	 */
286	public ATNil meta_defineField(ATSymbol name, ATObject value) throws InterpreterException {
287		throw new XIllegalOperation("Cannot define field " + name + " in far reference " + this);
288	}
289
290	/**
291	 * @throws XIllegalOperation - cannot assign in objects hosted by another actor.
292	 */
293	public ATNil meta_assignField(ATObject receiver, ATSymbol name, ATObject value) throws InterpreterException {
294		throw new XIllegalOperation("Cannot assign field " + name + " in far reference " + this);
295	}
296
297	/**
298	 * @throws XIllegalOperation - cannot assign in objects hosted by another actor.
299	 */
300	public ATNil meta_assignVariable(ATSymbol name, ATObject value) throws InterpreterException {
301		throw new XIllegalOperation("Cannot assign variable " + name + " in far reference " + this);
302	}
303
304    /* ----------------------------------------
305     * -- Object Relation Testing Protocol   --
306     * ---------------------------------------- */
307
308    /**
309     * @return false unless this == original
310     */
311	public ATBoolean meta_isCloneOf(ATObject original) throws InterpreterException {
312		return NATBoolean.atValue(this == original);
313	}
314
315    /**
316     * @return false unless this == original
317     */
318	public ATBoolean meta_isRelatedTo(ATObject object) throws InterpreterException {
319		return this.meta_isCloneOf(object);
320	}
321
322    /* ---------------------------------
323     * -- Structural Access Protocol  --
324     * --------------------------------- */
325	
326	/**
327	 * @throws XIllegalOperation - cannot add fields to an object in another actor.
328	 */
329	public ATNil meta_addField(ATField field) throws InterpreterException {
330		return super.meta_addField(field);
331	}
332
333	/**
334	 * @throws XIllegalOperation - cannot add methods to an object in another actor.
335	 */
336	public ATNil meta_addMethod(ATMethod method) throws InterpreterException {
337		return super.meta_addMethod(method);
338	}
339
340	/**
341	 * @throws XSelectorNotFound - as the far object has no fields of its own
342	 */
343	public ATField meta_grabField(ATSymbol fieldName) throws InterpreterException {
344		return super.meta_grabField(fieldName);
345	}
346
347	/**
348	 * @return a method if and only if the requested selector is a default operator such as == 
349	 * @throws XSelectorNotFound otherwise
350	 */
351	public ATMethod meta_grabMethod(ATSymbol methodName) throws InterpreterException {
352		return super.meta_grabMethod(methodName);
353	}
354
355	/**
356	 * @return an empty table
357	 */
358	public ATTable meta_listFields() throws InterpreterException {
359		return super.meta_listFields();
360	}
361
362	/**
363	 * @return a table of default methods
364	 */
365	public ATTable meta_listMethods() throws InterpreterException {
366		return super.meta_listMethods();
367	}
368
369    /* ----------------------
370     * -- Output Protocol  --
371     * ---------------------- */
372	
373	public NATText meta_print() throws InterpreterException {
374		return NATText.atValue("<far ref to:"+objectId_.getDescription()+">");
375	}
376	
377    /* --------------------
378     * -- Mirror Fields  --
379     * -------------------- */
380	
381	/**
382	 * The stripes of a far reference are the stripes of the remote object
383	 * it points to, plus the FarReference stripe.
384	 */
385    public ATTable meta_getStripes() throws InterpreterException {
386    	return NATTable.atValue(stripes_);
387    }
388	
389	public boolean isFarReference() {
390		return true;
391	}
392
393    public ATFarReference asFarReference() throws XTypeMismatch {
394  	    return this;
395  	}
396    
397    /**
398     * Two far references are equal if and only if they point to the same object Id.
399     */
400    public ATBoolean base__opeql__opeql_(ATObject other) throws InterpreterException {
401		if (this == other) {
402			return NATBoolean._TRUE_;
403		} else if (other instanceof NATFarReference) {
404			ATObjectID otherId = ((NATFarReference) other).getObjectId();
405			return NATBoolean.atValue(objectId_.equals(otherId));
406		} else {
407			return NATBoolean._FALSE_;
408		}
409	}
410
411	public ATObject base_init(ATObject[] initargs) throws InterpreterException {
412		throw new XIllegalOperation("Cannot initialize far reference " + this);
413	}
414
415	public ATObject base_new(ATObject[] initargs) throws InterpreterException {
416		throw new XIllegalOperation("Cannot instantiate far reference " + this);
417	}
418
419	/**
420     * Performs listener&lt;-apply([ [] ])
421     * 
422     * @param type the kind of listener, used for logging/debugging purposes only
423     */
424    private void triggerListener(ATObject listener, String type) {
425		try {
426			// listener<-apply([ [] ])
427			owner_.event_acceptSelfSend(
428					new NATAsyncMessage(listener,
429							            Evaluator._APPLY_,
430							            NATTable.atValue(new ATObject[] { NATTable.EMPTY }),
431							            NATTable.EMPTY));
432		} catch (InterpreterException e) {
433			Logging.RemoteRef_LOG.error("error invoking " + type +" listener", e);
434		}
435    }
436    
437	public static class NATDisconnectionSubscription extends NATObject {
438		private static final AGSymbol _REFERENCE_ = AGSymbol.jAlloc("reference");
439		private static final AGSymbol _HANDLER_ = AGSymbol.jAlloc("handler");
440		private static final AGSymbol _CANCEL_ = AGSymbol.jAlloc("cancel");
441		public NATDisconnectionSubscription(final NATFarReference reference, ATClosure handler) throws InterpreterException {
442			this.meta_defineField(_REFERENCE_, reference);
443			this.meta_defineField(_HANDLER_, handler);
444			this.meta_defineField(_CANCEL_, 	new NativeClosure(this) {
445				public ATObject base_apply(ATTable args) throws InterpreterException {
446					NATFarReference reference = scope_.meta_select(scope_, _REFERENCE_).asNativeFarReference();
447					if(reference instanceof NATRemoteFarRef) {
448						NATRemoteFarRef remote = (NATRemoteFarRef)reference;
449						ATObject handler = scope_.meta_select(scope_, _HANDLER_);
450						remote.removeDisconnectionListener(handler);
451					}
452					return NATNil._INSTANCE_;
453				}
454			});
455		}
456		public NATText meta_print() throws InterpreterException {
457			return NATText.atValue("<disconnection subscription:"+ this.meta_select(this, _REFERENCE_)+">");
458		}
459	}
460	
461	public static class NATReconnectionSubscription extends NATObject {
462		private static final AGSymbol _REFERENCE_ = AGSymbol.jAlloc("reference");
463		private static final AGSymbol _HANDLER_ = AGSymbol.jAlloc("handler");
464		private static final AGSymbol _CANCEL_ = AGSymbol.jAlloc("cancel");
465		public NATReconnectionSubscription(final NATFarReference reference, ATClosure handler) throws InterpreterException {
466			this.meta_defineField(_REFERENCE_, reference);
467			this.meta_defineField(_HANDLER_, handler);
468			this.meta_defineField(_CANCEL_, 	new NativeClosure(this) {
469				public ATObject base_apply(ATTable args) throws InterpreterException {
470					NATFarReference reference = scope_.meta_select(scope_, _REFERENCE_).asNativeFarReference();
471					if(reference instanceof NATRemoteFarRef) {
472						NATRemoteFarRef remote = (NATRemoteFarRef)reference;
473						ATObject handler = scope_.meta_select(scope_, _HANDLER_);
474						remote.removeReconnectionListener(handler);
475					}
476					return NATNil._INSTANCE_;
477				}
478			});
479		}
480		public NATText meta_print() throws InterpreterException {
481			return NATText.atValue("<reconnection subscription:"+ this.meta_select(this, _REFERENCE_)+">");
482		}
483	}
484	
485	public static class NATExpiredSubscription extends NATObject {
486		private static final AGSymbol _REFERENCE_ = AGSymbol.jAlloc("reference");
487		private static final AGSymbol _HANDLER_ = AGSymbol.jAlloc("handler");
488		private static final AGSymbol _CANCEL_ = AGSymbol.jAlloc("cancel");
489		public NATExpiredSubscription(final NATFarReference reference, ATClosure handler) throws InterpreterException {
490			this.meta_defineField(_REFERENCE_, reference);
491			this.meta_defineField(_HANDLER_, handler);
492			this.meta_defineField(_CANCEL_, 	new NativeClosure(this) {
493				public ATObject base_apply(ATTable args) throws InterpreterException {
494					NATFarReference reference = scope_.meta_select(scope_, _REFERENCE_).asNativeFarReference();
495					if(reference instanceof NATRemoteFarRef) {
496						NATRemoteFarRef remote = (NATRemoteFarRef)reference;
497						ATObject handler = scope_.meta_select(scope_, _HANDLER_);
498						remote.removeExpiredListener(handler);
499					}
500					return NATNil._INSTANCE_;
501				}
502			});
503		}
504		public NATText meta_print() throws InterpreterException {
505			return NATText.atValue("<expired subscription:"+ this.meta_select(this, _REFERENCE_)+">");
506		}
507	}
508	
509}