/interpreter/tags/at2dist110511/src/edu/vub/at/actors/natives/NATActorMirror.java

http://ambienttalk.googlecode.com/ · Java · 448 lines · 246 code · 38 blank · 164 comment · 13 complexity · abbf3d043324cc8bb47690335fbb2321 MD5 · raw file

  1. /**
  2. * AmbientTalk/2 Project
  3. * NATActorMirror.java created on Oct 16, 2006 at 1:55:05 PM
  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 edu.vub.at.actors.ATActorMirror;
  30. import edu.vub.at.actors.ATAsyncMessage;
  31. import edu.vub.at.actors.ATLetter;
  32. import edu.vub.at.actors.natives.DiscoveryManager.Publication;
  33. import edu.vub.at.actors.natives.DiscoveryManager.Subscription;
  34. import edu.vub.at.eval.Evaluator;
  35. import edu.vub.at.exceptions.InterpreterException;
  36. import edu.vub.at.exceptions.XArityMismatch;
  37. import edu.vub.at.exceptions.XIllegalOperation;
  38. import edu.vub.at.exceptions.XTypeMismatch;
  39. import edu.vub.at.objects.ATBoolean;
  40. import edu.vub.at.objects.ATClosure;
  41. import edu.vub.at.objects.ATContext;
  42. import edu.vub.at.objects.ATNil;
  43. import edu.vub.at.objects.ATObject;
  44. import edu.vub.at.objects.ATTable;
  45. import edu.vub.at.objects.ATTypeTag;
  46. import edu.vub.at.objects.coercion.NativeTypeTags;
  47. import edu.vub.at.objects.grammar.ATSymbol;
  48. import edu.vub.at.objects.mirrors.NATIntrospectiveMirror;
  49. import edu.vub.at.objects.mirrors.NativeClosure;
  50. import edu.vub.at.objects.mirrors.PrimitiveMethod;
  51. import edu.vub.at.objects.natives.NATByRef;
  52. import edu.vub.at.objects.natives.NATMethodInvocation;
  53. import edu.vub.at.objects.natives.NATNumber;
  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.OBJLexicalRoot;
  58. import edu.vub.at.objects.natives.grammar.AGSymbol;
  59. import java.util.LinkedList;
  60. /**
  61. * The NATActorMirror class implements the concurrency model of ambienttalk. It continually
  62. * consumes meta-events which are written to a synchronized queue. This way the actor
  63. * is notified of incoming messages, discovered and lost services, etc. When no meta-
  64. * messages are available, the actor consumes base-level messages as they are stored
  65. * in its inbox. These messages have a receiver object internal to the actor and they
  66. * will be invoked on this receiver by the actor's thread.
  67. *
  68. * @author smostinc
  69. */
  70. public class NATActorMirror extends NATByRef implements ATActorMirror {
  71. // INSTANCE VARIABLES
  72. // the actor mirror refers directly to its ELActor because
  73. // using ELActor.currentActor is slower
  74. private ELActor myActor_;
  75. private final ELDiscoveryActor discoveryActor_;
  76. /**
  77. * When initializing a new actor, do not forget that this constructor is still executed by the
  78. * creating actor, not by the created actor. To make the created actor perform something, it is
  79. * necessary to use meta_receive to send itself messages for later execution.
  80. */
  81. public NATActorMirror(ELVirtualMachine host) {
  82. discoveryActor_ = host.discoveryActor_;
  83. }
  84. /** set the mirror's base actor instance */
  85. protected void setActor(ELActor myActor) {
  86. myActor_ = myActor;
  87. }
  88. /* ------------------------------------------
  89. * -- Language Construct to Actor Protocol --
  90. * ------------------------------------------ */
  91. public ATAsyncMessage base_createMessage(ATSymbol selector, ATTable arguments, ATTable types) throws InterpreterException {
  92. ATAsyncMessage msg = new NATAsyncMessage(selector, arguments, types);
  93. // types.inject: msg into: { |constructingMsg, type| type.annotate(constructingMsg) }
  94. ATAsyncMessage returnMsg = types.base_inject_into_(msg, new NativeClosure(this) {
  95. public ATObject base_apply(ATTable args) throws InterpreterException {
  96. checkArity(args, 2);
  97. ATObject newMessage = get(args, 1);
  98. ATObject type = get(args, 2);
  99. return type.asTypeTag().base_annotateMessage(newMessage);
  100. }
  101. }).asAsyncMessage();
  102. // if the message was indeed annotated, set the correct location informal on the original message.
  103. if (! returnMsg.equals(msg)){
  104. msg.impl_setLocation(types.impl_getLocation());
  105. }
  106. return returnMsg;
  107. }
  108. public ATObject base_createMirror(ATObject reflectee) throws InterpreterException {
  109. return NATIntrospectiveMirror.atValue(reflectee);
  110. }
  111. /**
  112. * A publication object is defined as:
  113. * object: {
  114. * def topic := //topic under which service is published;
  115. * def service := //the exported service object;
  116. * def cancel() { //unexport the service object }
  117. * }
  118. */
  119. public static class NATPublication extends NATObject {
  120. private static final AGSymbol _TOPIC_ = AGSymbol.jAlloc("topic");
  121. private static final AGSymbol _SERVICE_ = AGSymbol.jAlloc("service");
  122. private static final AGSymbol _CANCEL_ = AGSymbol.jAlloc("cancel");
  123. public NATPublication(final ELDiscoveryActor discoveryActor,
  124. ATTypeTag topic, ATObject service,
  125. final Publication pub) throws InterpreterException {
  126. meta_defineField(_TOPIC_, topic);
  127. meta_defineField(_SERVICE_, service);
  128. meta_addMethod(new PrimitiveMethod(_CANCEL_, NATTable.EMPTY) {
  129. public ATObject base_apply(ATTable arguments, ATContext ctx) throws InterpreterException {
  130. int arity = arguments.base_length().asNativeNumber().javaValue;
  131. if (arity != 0) {
  132. throw new XArityMismatch("cancel", 0, arity);
  133. }
  134. discoveryActor.event_cancelPublication(pub);
  135. return Evaluator.getNil();
  136. }
  137. });
  138. }
  139. public NATText meta_print() throws InterpreterException {
  140. return NATText.atValue("<publication:"+impl_invokeAccessor(this, _TOPIC_, NATTable.EMPTY)+">");
  141. }
  142. }
  143. /**
  144. * A subscription object is defined as:
  145. * object: {
  146. * def topic := //topic subscribed to;
  147. * def handler := //the closure to be triggered;
  148. * def cancel() { //unsubscribe the handler }
  149. * }
  150. */
  151. public static class NATSubscription extends NATObject {
  152. private static final AGSymbol _TOPIC_ = AGSymbol.jAlloc("topic");
  153. private static final AGSymbol _HANDLER_ = AGSymbol.jAlloc("handler");
  154. private static final AGSymbol _CANCEL_ = AGSymbol.jAlloc("cancel");
  155. public NATSubscription(final ELDiscoveryActor discoveryActor,
  156. ATTypeTag topic, ATClosure handler,
  157. final Subscription sub) throws InterpreterException {
  158. meta_defineField(_TOPIC_, topic);
  159. meta_defineField(_HANDLER_, handler);
  160. meta_addMethod(new PrimitiveMethod(_CANCEL_, NATTable.EMPTY) {
  161. public ATObject base_apply(ATTable arguments, ATContext ctx) throws InterpreterException {
  162. int arity = arguments.base_length().asNativeNumber().javaValue;
  163. if (arity != 0) {
  164. throw new XArityMismatch("cancel", 0, arity);
  165. }
  166. discoveryActor.event_cancelSubscription(sub);
  167. return Evaluator.getNil();
  168. }
  169. });
  170. }
  171. public NATText meta_print() throws InterpreterException {
  172. return NATText.atValue("<subscription:"+impl_invokeAccessor(this, _TOPIC_, NATTable.EMPTY)+">");
  173. }
  174. }
  175. public ATObject base_provide(final ATTypeTag topic, final ATObject service) throws InterpreterException {
  176. Publication pub = new Publication(myActor_,
  177. new Packet(topic),
  178. new Packet(service),
  179. service);
  180. discoveryActor_.event_servicePublished(pub);
  181. return new NATPublication(discoveryActor_, topic, service, pub);
  182. }
  183. public ATObject base_require(final ATTypeTag topic, final ATClosure handler, ATBoolean isPermanent) throws InterpreterException {
  184. Subscription sub = new Subscription(myActor_,
  185. new Packet(topic),
  186. new Packet(handler),
  187. isPermanent.asNativeBoolean().javaValue);
  188. discoveryActor_.event_clientSubscribed(sub);
  189. return new NATSubscription(discoveryActor_, topic, handler, sub);
  190. }
  191. public ATTable base_listPublications() throws InterpreterException {
  192. Publication[] pubs = discoveryActor_.sync_event_listPublications(myActor_);
  193. NATPublication[] natpubs = new NATPublication[pubs.length];
  194. for(int i = 0; i < pubs.length; i++) {
  195. Publication pub = pubs[i];
  196. natpubs[i] = new NATPublication(
  197. discoveryActor_,
  198. pub.providedTypeTag_.unpack().asTypeTag(),
  199. pub.exportedService_.unpack(),
  200. pub);
  201. }
  202. return NATTable.atValue(natpubs);
  203. }
  204. public ATTable base_listSubscriptions() throws InterpreterException {
  205. Subscription[] subs = discoveryActor_.sync_event_listSubscriptions(myActor_);
  206. NATSubscription[] natsubs = new NATSubscription[subs.length];
  207. for(int i = 0; i < subs.length; i++) {
  208. Subscription sub = subs[i];
  209. natsubs[i] = new NATSubscription(
  210. discoveryActor_,
  211. sub.requiredTypeTag_.unpack().asTypeTag(),
  212. sub.registeredHandler_.unpack().asClosure(),
  213. sub);
  214. }
  215. return NATTable.atValue(natsubs);
  216. }
  217. /* --------------------------
  218. * -- VM to Actor Protocol --
  219. * -------------------------- */
  220. public ATObject meta_clone() throws InterpreterException {
  221. throw new XIllegalOperation("Cannot clone actor " + toString());
  222. }
  223. /**
  224. * actor.new(closure)
  225. * => same effect as evaluating 'actor: closure'
  226. */
  227. public ATObject meta_newInstance(ATTable initargs) throws InterpreterException {
  228. int length = initargs.base_length().asNativeNumber().javaValue;
  229. if(length != 1)
  230. throw new XArityMismatch("newInstance", 1, length);
  231. ATClosure closure = initargs.base_at(NATNumber.ONE).asClosure();
  232. return OBJLexicalRoot._INSTANCE_.base_actor_(closure);
  233. }
  234. public NATText meta_print() throws InterpreterException {
  235. return NATText.atValue("<actormirror:" + this.hashCode() + ">");
  236. }
  237. public ATTable meta_typeTags() throws InterpreterException {
  238. return NATTable.of(NativeTypeTags._ACTORMIRROR_);
  239. }
  240. /* -----------------------------
  241. * -- Object Passing Protocol --
  242. * ----------------------------- */
  243. /**
  244. * When default base-level objects send an asynchronous message, they delegate
  245. * this responsibility to their actor by means of this base-level method.
  246. *
  247. * The actor's default implementation is to invoke the receiver mirror's <tt>receive</tt> method
  248. * which defines the default asynchronous message reception semantics.
  249. *
  250. * Note: in pre-2.9 versions of AmbientTalk, this method did not immediately pass
  251. * control to the receiver via the <tt>receive</tt> method. By delegating to the receiver
  252. * in the same execution turn as the message send, we allow possible proxies (custom eventual
  253. * references) to intervene in the message sending process.
  254. */
  255. public ATObject base_send(ATObject receiver, ATAsyncMessage message) throws InterpreterException {
  256. return receiver.meta_receive(message);
  257. }
  258. /**
  259. * def becomeMirroredBy: protocol
  260. * => returns the old installed protocol
  261. *
  262. * @see ATActorMirror#base_becomeMirroredBy_(ATClosure)
  263. */
  264. public ATObject base_becomeMirroredBy_(ATActorMirror newActorMirror) throws InterpreterException {
  265. ATActorMirror oldMirror = myActor_.getImplicitActorMirror();
  266. myActor_.setActorMirror(newActorMirror);
  267. return oldMirror;
  268. }
  269. /**
  270. * def getExplicitActorMirror()
  271. * => return an explicit actor mirror for the current actor.
  272. *
  273. * The default implementation uses the actor's implicit mirror as the
  274. * default explicit mirror.
  275. *
  276. * @see ATActorMirror#base_getExplicitActorMirror()
  277. */
  278. public ATActorMirror base_getExplicitActorMirror() throws InterpreterException {
  279. return myActor_.getImplicitActorMirror();
  280. }
  281. /**
  282. * This operation is
  283. * introduced as a mechanism to alter the semantics of message reception for all objects
  284. * owned by an actor. It can be used e.g. to keep track of all successfully processed messages.
  285. *
  286. * Note that this operation is *only* invoked for messages received from *other*
  287. * actors (i.e. local or remote actors), it is *not* invoked for recursive asynchronous self-sends
  288. * (intra-actor message sends)! This is an important change w.r.t pre-2.9 versions of AmbientTalk.
  289. */
  290. public ATObject base_receive(ATObject receiver, ATAsyncMessage message) throws InterpreterException {
  291. // this additional dispatch to receive will schedule an async self-send when performed
  292. // on near references, which then invokes message.base_process in a later execution turn
  293. // We do not short-circuit this behaviour for consistency purposes: receive is invoked
  294. // on all receiver objects consistently, whether they are near refs, far refs, custom eventual
  295. // refs or any other kind of mirage.
  296. return receiver.meta_receive(message);
  297. }
  298. /**
  299. * Export the given local object such that it is now remotely accessible via the
  300. * returned object id.
  301. * @param object a **near** reference to the object to export
  302. * @return a local far reference to the object being exported
  303. * @throws XIllegalOperation if the passed object is a far reference, i.e. non-local
  304. */
  305. public ATObject base_createReference(ATObject object) throws InterpreterException {
  306. // receptionist set will check whether ATObject is really local to me
  307. return myActor_.receptionists_.exportObject(object);
  308. }
  309. /**
  310. * Provides access to this actor's "behaviour" object. This is the first
  311. * object created within an actor.
  312. *
  313. * Note: if the behaviour is accessed when evaluating the "init.at" initialization
  314. * file of an actor, the behaviour will <em>not have been initialized</em> yet.
  315. * It will appear as an empty object.
  316. */
  317. public ATObject base_behaviour() throws InterpreterException {
  318. return myActor_.behaviour_;
  319. }
  320. public ATActorMirror asActorMirror() throws XTypeMismatch {
  321. return this;
  322. }
  323. public NATActorMirror asNativeActorMirror() throws XTypeMismatch {
  324. return this;
  325. }
  326. /* -------------------------
  327. * -- Scheduling Protocol --
  328. * ------------------------- */
  329. /**
  330. * The inbox of this actor. It contains objects that implement the {@link ATLetter} interface
  331. */
  332. private LinkedList inbox_ = new LinkedList();
  333. /**
  334. * A letter object is defined as:
  335. * object: {
  336. * def receiver := //receiver of the letter;
  337. * def message := //the message that is being sent;
  338. * def cancel() { //cancel the delivery of the letter }
  339. * }
  340. */
  341. public static class NATLetter extends NATObject implements ATLetter {
  342. private static final AGSymbol _RCVR_ = AGSymbol.jAlloc("receiver");
  343. private static final AGSymbol _MSG_ = AGSymbol.jAlloc("message");
  344. private static final AGSymbol _CANCEL_ = AGSymbol.jAlloc("cancel");
  345. public NATLetter(final LinkedList mailbox, ATObject receiver, ATObject message) throws InterpreterException {
  346. super(new ATTypeTag[] { NativeTypeTags._LETTER_ });
  347. meta_defineField(_RCVR_, receiver);
  348. meta_defineField(_MSG_, message);
  349. final NATLetter thisLetter = this;
  350. meta_addMethod(new PrimitiveMethod(_CANCEL_, NATTable.EMPTY) {
  351. public ATObject base_apply(ATTable arguments, ATContext ctx) throws InterpreterException {
  352. int arity = arguments.base_length().asNativeNumber().javaValue;
  353. if (arity != 0) {
  354. throw new XArityMismatch("cancel", 0, arity);
  355. }
  356. // Note: if the receiver and message fields are changed by an AmbientTalk program
  357. // canceling the letter will still remove the original letter, not a letter that corresponds
  358. // to the new receiver and message.
  359. mailbox.remove(thisLetter);
  360. return Evaluator.getNil();
  361. }
  362. });
  363. }
  364. public NATText meta_print() throws InterpreterException {
  365. return NATText.atValue("<letter:"+impl_invokeAccessor(this, _MSG_, NATTable.EMPTY)+">");
  366. }
  367. public ATLetter asLetter() { return this; }
  368. public ATObject base_cancel() throws InterpreterException {
  369. return this.meta_invoke(this, new NATMethodInvocation(_CANCEL_, NATTable.EMPTY, NATTable.EMPTY));
  370. }
  371. public ATAsyncMessage base_message() throws InterpreterException {
  372. return this.meta_invokeField(this, _MSG_).asAsyncMessage();
  373. }
  374. public ATObject base_receiver() throws InterpreterException {
  375. return this.meta_invokeField(this, _RCVR_);
  376. }
  377. }
  378. /**
  379. * Returns a table with all letters currently in the inbox
  380. */
  381. public ATTable base_listIncomingLetters() throws InterpreterException {
  382. ATObject[] incoming = (ATObject[]) inbox_.toArray(new ATObject[inbox_.size()]);
  383. return NATTable.atValue(incoming);
  384. }
  385. /**
  386. * Creates a letter object and adds it to the actor's inbox
  387. */
  388. public ATObject base_schedule(ATObject receiver, ATAsyncMessage message) throws InterpreterException {
  389. NATLetter letter = new NATLetter(inbox_, receiver, message);
  390. inbox_.addFirst(letter);
  391. // signal a serve event for every message that is scheduled
  392. myActor_.event_serve();
  393. return letter;
  394. }
  395. /**
  396. * Fetches the next letter from the actor's inbox, if any, and processes it.
  397. */
  398. public ATObject base_serve() throws InterpreterException {
  399. if (inbox_.size() > 0) {
  400. ATObject next = (ATObject) inbox_.removeLast();
  401. ATLetter letter = next.asLetter();
  402. // receive has already been invoked prior to scheduling
  403. // the receive is known to be a local object, therefore we
  404. // can immediately process the message
  405. return letter.base_message().base_process(letter.base_receiver());
  406. } else {
  407. return Evaluator.getNil();
  408. }
  409. }
  410. }