/interpreter/tags/at2dist091109/src/edu/vub/at/actors/natives/NATFarReference.java

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