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