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