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

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