/interpreter/tags/reactive-pattern-matching/src/edu/vub/at/actors/natives/NATFarReference.java

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