PageRenderTime 90ms CodeModel.GetById 75ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

/interpreter/tags/at2dist090708/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 */
 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}