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

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