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