/interpreter/tags/at_build150307/src/edu/vub/at/actors/natives/ELActor.java

http://ambienttalk.googlecode.com/ · Java · 376 lines · 185 code · 35 blank · 156 comment · 4 complexity · 8697659efa39c2be33bfc9993849d2ce MD5 · raw file

  1. /**
  2. * AmbientTalk/2 Project
  3. * ELActor.java created on 27-dec-2006 at 16:17:23
  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.ATFarReference;
  32. import edu.vub.at.actors.eventloops.BlockingFuture;
  33. import edu.vub.at.actors.eventloops.Callable;
  34. import edu.vub.at.actors.eventloops.Event;
  35. import edu.vub.at.actors.eventloops.EventLoop;
  36. import edu.vub.at.actors.id.ATObjectID;
  37. import edu.vub.at.actors.net.Logging;
  38. import edu.vub.at.eval.Evaluator;
  39. import edu.vub.at.exceptions.InterpreterException;
  40. import edu.vub.at.exceptions.XClassNotFound;
  41. import edu.vub.at.exceptions.XIOProblem;
  42. import edu.vub.at.exceptions.XIllegalOperation;
  43. import edu.vub.at.exceptions.XObjectOffline;
  44. import edu.vub.at.objects.ATAbstractGrammar;
  45. import edu.vub.at.objects.ATMethod;
  46. import edu.vub.at.objects.ATObject;
  47. import edu.vub.at.objects.ATStripe;
  48. import edu.vub.at.objects.ATTable;
  49. import edu.vub.at.objects.natives.NATContext;
  50. import edu.vub.at.objects.natives.NATNil;
  51. import edu.vub.at.objects.natives.NATObject;
  52. import edu.vub.at.objects.natives.NATTable;
  53. import edu.vub.at.objects.natives.OBJLexicalRoot;
  54. /**
  55. * An instance of the class ELActor represents a programmer-defined
  56. * AmbientTalk/2 actor. The event queue of the actor event loop serves as the
  57. * actor's 'meta-level' queue.
  58. *
  59. * The events in the 'meta-level' queue are handled by the actor's mirror object.
  60. * This mirror is normally an instance of NATActorMirror, but it can be any
  61. * programmer-defined object that adheres to the ATActorMirror interface.
  62. *
  63. * @author tvcutsem
  64. */
  65. public class ELActor extends EventLoop {
  66. /**
  67. * A thread-local variable that contains the 'default actor' to use
  68. * when there is currently no ELActor event loop thread running.
  69. * This is primarily useful for performing unit tests where an actor
  70. * is automatically created when actor semantics is required.
  71. *
  72. * A warning is printed to the log because using the default actor should
  73. * only be used for testing purposes.
  74. */
  75. private static final ThreadLocal _DEFAULT_ACTOR_ = new ThreadLocal() {
  76. protected synchronized Object initialValue() {
  77. Logging.Actor_LOG.warn("Creating a default actor for thread " + Thread.currentThread());
  78. try {
  79. ELVirtualMachine host = new ELVirtualMachine(NATNil._INSTANCE_, new SharedActorField[] { });
  80. return NATActorMirror.createEmptyActor(host, new NATActorMirror(host)).getFarHost();
  81. } catch (InterpreterException e) {
  82. throw new RuntimeException("Failed to initialize default actor",e);
  83. }
  84. }
  85. };
  86. /**
  87. * Retrieves the currently running actor. If there is no running actor thread,
  88. * this returns the value stored in the thread-local default actor field.
  89. */
  90. public static final ELActor currentActor() {
  91. try {
  92. return ((ELActor) EventLoop.currentEventLoop());
  93. } catch (ClassCastException e) {
  94. // current event loop is not an actor event loop
  95. } catch (IllegalStateException e) {
  96. // current thread is not an event loop
  97. }
  98. Logging.Actor_LOG.warn("Asked for an actor in non-actor thread " + Thread.currentThread());
  99. return (ELActor) _DEFAULT_ACTOR_.get();
  100. }
  101. private ATActorMirror mirror_;
  102. protected final ELVirtualMachine host_;
  103. protected final ReceptionistsSet receptionists_;
  104. /*
  105. * This object is created when the actor is initialized: i.e. it is the passed
  106. * version of the isolate that was passed to the actor: primitive by the creating actor.
  107. */
  108. private ATObject behaviour_;
  109. public ELActor(ATActorMirror mirror, ELVirtualMachine host) {
  110. super("actor " + mirror.toString());
  111. mirror_ = mirror;
  112. host_ = host;
  113. receptionists_ = new ReceptionistsSet(this);
  114. }
  115. /** constructor dedicated to initialization of discovery actor */
  116. protected ELActor(ELVirtualMachine host) {
  117. super("discovery actor");
  118. mirror_ = new NATActorMirror(host);
  119. host_ = host;
  120. receptionists_ = new ReceptionistsSet(this);
  121. }
  122. /**
  123. * Actor event loops handle events by allowing the meta-level events to
  124. * process themselves.
  125. */
  126. public void handle(Event event) {
  127. event.process(mirror_);
  128. }
  129. public ATActorMirror getActorMirror() { return mirror_; }
  130. public void setActorMirror(ATActorMirror mirror) { mirror_ = mirror; }
  131. public ELVirtualMachine getHost() {
  132. return host_;
  133. }
  134. /**
  135. * Export the given local object such that it is now remotely accessible via the
  136. * returned object id.
  137. * @param object a **near** reference to the object to export
  138. * @return a unique identifier by which this object can be retrieved via the resolve method.
  139. * @throws XIllegalOperation if the passed object is a far reference, i.e. non-local
  140. */
  141. public NATLocalFarRef export(ATObject object) throws InterpreterException {
  142. // receptionist set will check whether ATObject is really local to me
  143. return receptionists_.exportObject(object);
  144. }
  145. /**
  146. * Resolve the given object id into a local reference. There are three cases to
  147. * consider:
  148. * A) The given id designates an object local to this actor: the returned object
  149. * will be a **near** reference to the object (i.e. the object itself)
  150. * B) The given id designates a far (non-local) object that lives in the same
  151. * address space as this actor: the returned object wil be a **far** reference
  152. * to the object.
  153. * C) The given id designates a far object that lives on a remote machine: the
  154. * returned object will be a **far** and **remote** reference to the object.
  155. *
  156. * @param id the identifier of the object to resolve
  157. * @return a near or far reference to the object, depending on where the designated object lives
  158. */
  159. public ATObject resolve(ATObjectID id, ATStripe[] stripes) throws XObjectOffline {
  160. return receptionists_.resolveObject(id, stripes);
  161. }
  162. /* -----------------------------
  163. * -- Initialisation Protocol --
  164. * ----------------------------- */
  165. /**
  166. * Initialises the root using the contents of the init file stored by
  167. * the hosting virtual machine.
  168. * @throws InterpreterException
  169. */
  170. protected void initRootObject() throws InterpreterException {
  171. ATAbstractGrammar initialisationCode = host_.getInitialisationCode();
  172. // evaluate the initialization code in the context of the global scope
  173. NATObject globalScope = Evaluator.getGlobalLexicalScope();
  174. NATContext initCtx = new NATContext(globalScope, globalScope);
  175. initialisationCode.meta_eval(initCtx);
  176. }
  177. /**
  178. * Initialises various fields in the lexical root of the actor, which are defined in the
  179. * context of every actor. Candidates are a "system" field which allows the program to
  180. * perform IO operations or a "~" field denoting the current working directory.
  181. *
  182. * @throws InterpreterException when initialisation of a field fails
  183. */
  184. protected void initSharedFields() throws InterpreterException {
  185. SharedActorField[] fields = host_.getFieldsToInitialize();
  186. NATObject globalScope = Evaluator.getGlobalLexicalScope();
  187. for (int i = 0; i < fields.length; i++) {
  188. SharedActorField field = fields[i];
  189. ATObject value = field.initialize();
  190. if (value != null) {
  191. globalScope.meta_defineField(field.getName(), value);
  192. }
  193. }
  194. }
  195. // Events to be processed by the actor event loop
  196. /**
  197. * The initial event sent by the actor mirror to its event loop to intialize itself.
  198. * @param future the synchronization point with the creating actor, needs to be fulfilled with a far ref to the behaviour.
  199. * @param parametersPkt the serialized parameters for the initialization code
  200. * @param initcodePkt the serialized initialization code
  201. */
  202. protected void event_init(final BlockingFuture future, final Packet parametersPkt, final Packet initcodePkt) {
  203. receive(new Event("init("+this+")") {
  204. public void process(Object byMyself) {
  205. try {
  206. behaviour_ = new NATObject();
  207. // pass far ref to behaviour to creator actor who is waiting for this
  208. future.resolve(receptionists_.exportObject(behaviour_));
  209. // initialize lexically visible fields
  210. initSharedFields();
  211. ATTable params = parametersPkt.unpack().asTable();
  212. ATMethod initCode = initcodePkt.unpack().asMethod();
  213. // initialize the behaviour using the parameters and the code
  214. initCode.base_applyInScope(params, new NATContext(behaviour_, behaviour_));
  215. // go on to initialize the root and all lexically visible fields
  216. initRootObject();
  217. } catch (InterpreterException e) {
  218. Logging.Actor_LOG.error(behaviour_ + ": could not initialize actor behaviour", e);
  219. }
  220. }
  221. });
  222. }
  223. /**
  224. * The main entry point for any asynchronous self-sends.
  225. * Asynchronous self-sends do not undergo any form of parameter passing, there is no need
  226. * to serialize and deserialize the message parameter in a Packet.
  227. */
  228. public void event_acceptSelfSend(final ATAsyncMessage msg) {
  229. receive(new Event("accept("+msg+")") {
  230. public void process(Object myActorMirror) {
  231. performAccept(msg);
  232. }
  233. });
  234. }
  235. /**
  236. * The main entry point for any asynchronous messages sent to this actor
  237. * by external sources (e.g. the VM or other local actors).
  238. * @param msg the asynchronous AmbientTalk base-level message to enqueue
  239. */
  240. public void event_accept(final Packet serializedMessage) {
  241. receive(new Event("accept("+serializedMessage+")") {
  242. public void process(Object myActorMirror) {
  243. try {
  244. ATAsyncMessage msg = serializedMessage.unpack().asAsyncMessage();
  245. performAccept(msg);
  246. } catch (InterpreterException e) {
  247. Logging.Actor_LOG.error(mirror_ + ": error unpacking "+ serializedMessage, e);
  248. } catch (RuntimeException e) {
  249. throw e;
  250. }
  251. }
  252. });
  253. }
  254. private void performAccept(ATAsyncMessage msg) {
  255. try {
  256. ATObject result = msg.base_getReceiver().meta_receive(msg);
  257. // TODO what to do with return value?
  258. Logging.Actor_LOG.info(mirror_ + ": "+ msg + " returned " + result);
  259. } catch (InterpreterException e) {
  260. // TODO what to do with exception?
  261. Logging.Actor_LOG.error(mirror_ + ": "+ msg + " failed ", e);
  262. }
  263. }
  264. /**
  265. * This method is invoked by a coercer in order to schedule a symbiotic invocation
  266. * from the Java world, which should be synchronous to the Java thread, but which
  267. * must be scheduled asynchronously to comply with the AT/2 actor model.
  268. * @param invocation a functor object that will perform the symbiotic invocation
  269. * @return the result of the symbiotic invocation
  270. * @throws Exception if the symbiotic invocation fails
  271. */
  272. public Object sync_event_symbioticInvocation(Callable invocation) throws Exception {
  273. return receiveAndWait("symbioticInvocation", invocation);
  274. }
  275. /**
  276. * This method should only be used for purposes such as the IAT shell or unit testing.
  277. * It allows an external thread to make this actor evaluate an arbitrary expression.
  278. *
  279. * @param ast an abstract syntax tree to be evaluated by the receiving actor (in the
  280. * scope of its behaviour).
  281. * @return the result of the evaluation
  282. * @throws InterpreterException if the evaluation fails
  283. */
  284. public ATObject sync_event_eval(final ATAbstractGrammar ast) throws InterpreterException {
  285. try {
  286. return (ATObject) receiveAndWait("nativeEval("+ast+")", new Callable() {
  287. public Object call(Object inActor) throws Exception {
  288. return OBJLexicalRoot._INSTANCE_.base_eval_in_(ast, behaviour_);
  289. }
  290. });
  291. } catch (Exception e) {
  292. throw (InterpreterException) e;
  293. }
  294. }
  295. /**
  296. * This method should only be used for purposes of unit testing. It allows
  297. * arbitary code to be scheduled by external threads such as unit testing frameworks.
  298. */
  299. public Object sync_event_performTest(final Callable c) throws Exception {
  300. return (ATObject) receiveAndWait("performTest("+c+")", c);
  301. }
  302. /**
  303. * When the discovery manager receives a publication from another local actor or
  304. * another remote VM, the actor is asked to compare the incoming publication against
  305. * a subscription that it had announced previously.
  306. *
  307. * @param requiredStripe serialized form of the stripe attached to the actor's subscription
  308. * @param myHandler the closure specified as a handler for the actor's subscription
  309. * @param discoveredStripe serialized form of the stripe attached to the new publication
  310. * @param remoteService serialized form of the reference to the remote discovered service
  311. */
  312. public void event_serviceJoined(final Packet requiredStripePkt, final ATFarReference myHandler,
  313. final Packet discoveredStripePkt, final Packet remoteServicePkt) {
  314. receive(new Event("serviceJoined") {
  315. public void process(Object myActorMirror) {
  316. try {
  317. ATStripe requiredStripe = requiredStripePkt.unpack().asStripe();
  318. ATStripe discoveredStripe = discoveredStripePkt.unpack().asStripe();
  319. // is there a match?
  320. if (discoveredStripe.base_isSubstripeOf(requiredStripe).asNativeBoolean().javaValue) {
  321. ATObject remoteService = remoteServicePkt.unpack();
  322. // myhandler<-apply([remoteService])
  323. myHandler.meta_receive(
  324. NATAsyncMessage.createAsyncMessage(myHandler, myHandler, Evaluator._APPLY_,
  325. NATTable.atValue(new ATObject[] {
  326. NATTable.atValue(new ATObject[] { remoteService })
  327. })
  328. )
  329. );
  330. }
  331. } catch (XIOProblem e) {
  332. Logging.Actor_LOG.error("Error deserializing joined stripes or services: ", e.getCause());
  333. } catch (XClassNotFound e) {
  334. Logging.Actor_LOG.fatal("Could not find class while deserializing joined stripes or services: ", e.getCause());
  335. } catch (InterpreterException e) {
  336. Logging.Actor_LOG.error("Error while joining services: ", e);
  337. }
  338. }
  339. });
  340. }
  341. }