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

http://ambienttalk.googlecode.com/ · Java · 317 lines · 146 code · 44 blank · 127 comment · 7 complexity · 3ca96accad20a85846ce157e37b3db08 MD5 · raw file

  1. /**
  2. * AmbientTalk/2 Project
  3. * ELVirtualMachine.java created on Nov 1, 2006 at 8:32:31 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.eventloops.BlockingFuture;
  30. import edu.vub.at.actors.eventloops.Event;
  31. import edu.vub.at.actors.eventloops.EventLoop;
  32. import edu.vub.at.actors.id.ATObjectID;
  33. import edu.vub.at.actors.id.ActorID;
  34. import edu.vub.at.actors.id.VirtualMachineID;
  35. import edu.vub.at.actors.net.ConnectionListenerManager;
  36. import edu.vub.at.actors.net.VMAddressBook;
  37. import edu.vub.at.actors.net.cmd.CMDHandshake;
  38. import edu.vub.at.actors.net.cmd.CMDObjectTakenOffline;
  39. import edu.vub.at.actors.net.comm.Address;
  40. import edu.vub.at.actors.net.comm.CommunicationBus;
  41. import edu.vub.at.actors.net.comm.NetworkException;
  42. import edu.vub.at.eval.Evaluator;
  43. import edu.vub.at.exceptions.InterpreterException;
  44. import edu.vub.at.objects.ATAbstractGrammar;
  45. import edu.vub.at.objects.natives.NATMethod;
  46. import edu.vub.at.objects.natives.NATTable;
  47. import edu.vub.at.objects.natives.grammar.AGBegin;
  48. import edu.vub.at.util.logging.Logging;
  49. import java.util.Hashtable;
  50. /**
  51. * A ELVirtualMachine represents a virtual machine which hosts several actors. The
  52. * virtual machine is in charge of creating connections with other virtual machines
  53. * and orchestrates the broadcasting of its presence, the exchange of service
  54. * descriptions and messages. It also contains a set of runtime parameters (such as
  55. * the objectpath and initfile) which are needed to initialise a new actor.
  56. *
  57. * @author tvcutsem
  58. * @author smostinc
  59. */
  60. public final class ELVirtualMachine extends EventLoop {
  61. public static final String _DEFAULT_GROUP_NAME_ = "AmbientTalk";
  62. /** startup parameter to the VM: the code of the init.at file to use */
  63. private final ATAbstractGrammar initialisationCode_;
  64. /** startup parameter to the VM: the list of fields to be initialized in every hosted actor */
  65. private final SharedActorField[] sharedFields_;
  66. /** the VirtualMachineID of this VM */
  67. private final VirtualMachineID vmId_;
  68. /**
  69. * A table mapping VM GUIDs to Address objects.
  70. * Each time a VM connects, it sends its VirtualMachineID and an entry
  71. * mapping that VirtualMachineID to its current Address is registered in this table. When a remote reference
  72. * needs to send a message to the remote object, the VM is contacted based on its VirtualMachineID and this
  73. * table. When a VM disconnects, the disconnecting address is removed from this table.
  74. */
  75. public final VMAddressBook vmAddressBook_;
  76. /** a table mapping actor IDs to local native actors (int -> ELActor) */
  77. private final Hashtable localActors_;
  78. /** the communication bus for this Virtual Machine */
  79. public final CommunicationBus communicationBus_;
  80. /** manager for disconnection and reconnection observers */
  81. public final ConnectionListenerManager connectionManager_;
  82. /** the actor responsible for hosting the publications and subscriptions of this VM's actors */
  83. public final ELDiscoveryActor discoveryActor_;
  84. /**
  85. * Construct a new AmbientTalk virtual machine where...
  86. * @param initCode is the code to be executed in each new created actor (the content of the init.at file)
  87. * @param fields are all of the fields that should be present in each new created actor (e.g. the 'system' object of IAT)
  88. * @param groupName is the name of the overlay network to join
  89. */
  90. public ELVirtualMachine(ATAbstractGrammar initCode, SharedActorField[] fields, String groupName) {
  91. super("virtual machine");
  92. // used to initialize actors
  93. initialisationCode_ = initCode;
  94. sharedFields_ = fields;
  95. // used to allow actors to send messages to remote vms/actors
  96. vmAddressBook_ = new VMAddressBook();
  97. vmId_ = new VirtualMachineID();
  98. localActors_ = new Hashtable();
  99. discoveryActor_ = new ELDiscoveryActor(this);
  100. localActors_.put(discoveryActor_.getActorID(), discoveryActor_);
  101. discoveryActor_.event_init();
  102. // initialize the message dispatcher using a JChannel
  103. connectionManager_ = new ConnectionListenerManager();
  104. communicationBus_ = new CommunicationBus(this, groupName);
  105. Logging.VirtualMachine_LOG.info(this + ": VM created on network " + groupName);
  106. }
  107. public static final ELVirtualMachine currentVM() {
  108. return ELActor.currentActor().getHost();
  109. }
  110. public VirtualMachineID getGUID() { return vmId_; }
  111. public ATAbstractGrammar getInitialisationCode() {
  112. return initialisationCode_;
  113. }
  114. public SharedActorField[] getFieldsToInitialize() {
  115. return sharedFields_;
  116. }
  117. public ELVirtualMachine getHost() { return this; }
  118. /**
  119. * An event loop handles events by dispatching to the event itself.
  120. */
  121. public void handle(Event event) {
  122. // make the event process itself
  123. event.process(this);
  124. }
  125. /**
  126. * returns the local actor corresponding to the given actor Id.
  127. * This method synchronizes on the localActors_ table to ensure that
  128. * insertion and lookup are properly synchronized.
  129. */
  130. public ELActor getActor(ActorID id) {
  131. ELActor entry;
  132. synchronized (localActors_) {
  133. entry = (ELActor) localActors_.get(id);
  134. }
  135. if (entry != null) {
  136. return entry;
  137. } else {
  138. throw new RuntimeException("Asked for unknown actor id: " + id);
  139. }
  140. }
  141. /**
  142. * Signals that this VM can connect to the underlying network channel
  143. * and can start distributed interaction.
  144. */
  145. public void event_goOnline() {
  146. this.receive(new Event("goOnline") {
  147. public void process(Object myself) {
  148. try {
  149. Address myAddress = communicationBus_.connect();
  150. Logging.VirtualMachine_LOG.info(this + ": interpreter online, address = " + myAddress);
  151. } catch (NetworkException e) {
  152. Logging.VirtualMachine_LOG.fatal(this + ": could not connect to network:", e);
  153. }
  154. }
  155. });
  156. }
  157. /**
  158. * Signals that this VM must disconnect from the underlying discovery channel and communication bus
  159. */
  160. public void event_goOffline() {
  161. this.receive(new Event("goOffline") {
  162. public void process(Object myself) {
  163. try {
  164. communicationBus_.disconnect();
  165. Logging.VirtualMachine_LOG.info(this + ": interpreter offline");
  166. } catch (Exception e) {
  167. Logging.VirtualMachine_LOG.fatal(this + ": error while going offline:", e);
  168. }
  169. }
  170. });
  171. }
  172. /**
  173. * Notifies the discovery manager that a VM has joined the network.
  174. * This VM may be a first-time participant or it may be a previously
  175. * disconnected VM that has become reconnected.
  176. *
  177. * This VM will handshake with the connected VM to exchange their actual
  178. * {@link VirtualMachineID}s rather than their network addresses.
  179. */
  180. public void event_memberJoined(final Address remoteVMAddress) {
  181. this.receive(new Event("memberJoined("+remoteVMAddress+")") {
  182. public void process(Object myself) {
  183. Logging.VirtualMachine_LOG.info(this + ": VM connected: " + remoteVMAddress);
  184. // send a handshake message to exchange IDs
  185. new CMDHandshake(vmId_).send(communicationBus_, remoteVMAddress);
  186. }
  187. });
  188. }
  189. public void event_memberLeft(final Address virtualMachine) {
  190. this.receive(new Event("memberLeft("+virtualMachine+")") {
  191. public void process(Object myself) {
  192. Logging.VirtualMachine_LOG.info(this + ": VM disconnected: " + virtualMachine);
  193. // Identify the VirtualMachineID that corresponds to this address
  194. VirtualMachineID disconnected = vmAddressBook_.getGUIDOf(virtualMachine);
  195. // disconnected may be null if the memberJoined event was ignored because this VM
  196. // was already offline when the event was being processed.
  197. if(disconnected != null) {
  198. // delete entries mapping to Address from the vm Address Book table first,
  199. // so sending threads may have 'premonitions' that they are no longer connected
  200. vmAddressBook_.removeEntry(virtualMachine);
  201. // properly (but synchronously) notify all remote references of a disconnection
  202. connectionManager_.notifyDisconnected(disconnected);
  203. }
  204. }
  205. });
  206. }
  207. /* ==========================
  208. * == Actor -> VM Protocol ==
  209. * ========================== */
  210. // All methods prefixed by event_ denote asynchronous message sends that will be
  211. // scheduled in the receiving event loop's event queue
  212. /**
  213. * Event that signals the deletion of an object from the export table of an
  214. * actor on this virtual machine.
  215. */
  216. public void event_objectTakenOffline(final ATObjectID objId, final Address receiver) {
  217. this.receive( new Event("objectTakenOffline(" + objId +")") {
  218. public void process(Object myself){
  219. if ( receiver == null){
  220. //broadcast to other virtual machines that an object has gone offline.
  221. new CMDObjectTakenOffline(objId).broadcast(communicationBus_);
  222. } else{
  223. //sending to a known virtual machine in response to an XObjectOffline exception.
  224. new CMDObjectTakenOffline(objId).send(communicationBus_, receiver);
  225. }
  226. }
  227. });
  228. }
  229. /**
  230. * Auxiliary creation method to create an actor with an empty behaviour.
  231. * Equivalent to evaluating:
  232. *
  233. * actor: { nil }
  234. */
  235. public NATLocalFarRef createEmptyActor() throws InterpreterException {
  236. Packet noParams = new Packet(NATTable.EMPTY);
  237. Packet noinitcode = new Packet(new NATMethod(Evaluator._ANON_MTH_NAM_, NATTable.EMPTY, new AGBegin(NATTable.of(Evaluator.getNil())), NATTable.EMPTY));
  238. return createActor(noParams, noinitcode);
  239. }
  240. /**
  241. * Creates a new actor on this Virtual Machine. The actor its behaviour
  242. * is intialized by means of the passed parameters and initialization code. The calling
  243. * thread is **blocked** until the actor has been constructed. However, actor behaviour
  244. * and root initialization is carried out by the newly created actor itself.
  245. *
  246. * @param parametersPkt the serialized parameters used to invoke the initialization code
  247. * @param initcodePkt the serialized initialization code used to initialize the actor behaviour
  248. * @param actorMirror this actor's mirror
  249. * @return a far reference to the behaviour of the actor
  250. * @throws InterpreterException
  251. */
  252. public NATLocalFarRef createActor(Packet parametersPkt,
  253. Packet initcodePkt) throws InterpreterException {
  254. BlockingFuture future = new BlockingFuture();
  255. ELActor processor = new ELActor(new NATActorMirror(this), this);
  256. // lock the localActors_ table first to ensure addition is
  257. // atomic w.r.t. lookup in getActor
  258. synchronized (localActors_) {
  259. localActors_.put(processor.getActorID(), processor);
  260. }
  261. // schedule special 'init' message which will:
  262. // A) create a new behaviour and will unblock creating actor (by passing it a far ref via the future)
  263. // B) unpack the parameters used to invoke the initialization code
  264. // C) unpack the init code to initialize the behaviour
  265. // D) initialize the root and lobby objects of this actor
  266. processor.event_init(future, parametersPkt, initcodePkt);
  267. try {
  268. return (NATLocalFarRef) future.get();
  269. } catch (Exception e) {
  270. throw (InterpreterException) e;
  271. }
  272. }
  273. }