PageRenderTime 54ms CodeModel.GetById 14ms app.highlight 32ms RepoModel.GetById 2ms app.codeStats 0ms

/interpreter/tags/at2-build060407/src/edu/vub/at/actors/natives/ELFarReference.java

http://ambienttalk.googlecode.com/
Java | 271 lines | 140 code | 45 blank | 86 comment | 16 complexity | 8d93a118f0a73b3e685b8cc3e24ecff5 MD5 | raw file
  1/**
  2 * AmbientTalk/2 Project
  3 * ELFarReference.java created on 28-dec-2006 at 10:45:41
  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.ATAsyncMessage;
 31import edu.vub.at.actors.eventloops.BlockingFuture;
 32import edu.vub.at.actors.eventloops.Event;
 33import edu.vub.at.actors.eventloops.EventLoop;
 34import edu.vub.at.actors.id.ATObjectID;
 35import edu.vub.at.actors.net.ConnectionListener;
 36import edu.vub.at.actors.net.cmd.CMDTransmitATMessage;
 37import edu.vub.at.actors.net.comm.Address;
 38import edu.vub.at.actors.net.comm.CommunicationBus;
 39import edu.vub.at.actors.net.comm.NetworkException;
 40import edu.vub.at.exceptions.InterpreterException;
 41import edu.vub.at.exceptions.XIOProblem;
 42import edu.vub.at.objects.ATObject;
 43import edu.vub.at.objects.ATTable;
 44import edu.vub.at.objects.natives.NATTable;
 45import edu.vub.at.util.logging.Logging;
 46
 47import java.util.Vector;
 48
 49/**
 50 * An instance of the class ELFarReference represents the event loop processor for
 51 * a remote far reference. That is, the event queue of this event loop serves as 
 52 * an 'outbox' which is dedicated to a certain receiver object hosted by a remote
 53 * virtual machine.
 54 * 
 55 * This event loop handles event from its event queue by trying to transmit them
 56 * to a remote virtual machine.
 57 * 
 58 * @author tvcutsem
 59 */
 60public final class ELFarReference extends EventLoop implements ConnectionListener {
 61	
 62	// When the Far Reference needs to be interrupted, this field will be set to a non-null value
 63	// The handle tests for the presence of such an interrupt and will call the handleInterrupt() 
 64	// method if necessary
 65	private BlockingFuture outboxFuture_ = null;
 66	
 67	/**
 68	 * Signals the far reference that its owning actor has requested to retract unsent messages.
 69	 * The interrupt will be handled as soon as the processing of the current event has finished
 70	 * @return a blocking future the ELActor thread can wait on.
 71	 */
 72	public BlockingFuture setRetractingFuture() {
 73		outboxFuture_ = new BlockingFuture();
 74		
 75		// the reception of a new interrupt may awaken a sleeping ELFarReference 
 76		// thread, so we interrupt them, forcing them to reevaluate their conditions
 77		processor_.interrupt();
 78		return outboxFuture_;
 79	}
 80	
 81	/**
 82	 * Resolves the current interrupt's future with the vector of transmission events that are 
 83	 * in the event queue of the far reference. This is used to retrieve copies of all messages
 84	 * being sent through this far reference. Note that this method performs no deserialisation
 85	 * of the events into (copied) messages. Such deserialisation needs to be done by an ELActor,
 86	 * not the ELFarReference which will execute this method.
 87	 */
 88	public void handleRetractRequest() {
 89		outboxFuture_.resolve(eventQueue_.flush());
 90	}
 91	
 92	private final ELActor owner_;
 93	private final NATRemoteFarRef farRef_;
 94	private final ATObjectID destination_;
 95	private final CommunicationBus dispatcher_;
 96	
 97	private boolean connected_;
 98		
 99	public ELFarReference(ATObjectID destination, ELActor owner, NATRemoteFarRef ref) {
100		super("far reference " + destination);
101		
102		farRef_ = ref;
103		destination_ = destination;
104		owner_ = owner;
105		
106		connected_ = true;
107		// register the remote reference with the MembershipNotifier to keep track
108		// of the state of the connection with the remote VM
109		owner_.getHost().connectionManager_.addConnectionListener(destination_.getVirtualMachineId(), this);
110		
111		dispatcher_ = owner_.getHost().communicationBus_;
112	}
113	
114	/**
115	 * Process message transmission events only when the remote reference
116	 * is connected. Otherwise, wait until notified by the <tt>connected</tt> callback.
117	 */
118	public void handle(Event event) {
119		synchronized (this) {
120			while (!connected_ && outboxFuture_ == null) {
121				try {
122					this.wait();
123				} catch (InterruptedException e) { }
124			}
125			
126			if(outboxFuture_ != null) {
127				// re-enqueue the current event in its proper position
128				receivePrioritized(event);
129				
130				// flush the queue
131				handleRetractRequest();
132				
133			// else is strictly necessary as the handleInterrupt method has side effects, 
134			// removing the current event from the queue, such that it would be incorrect 
135			// to still send it 
136			} else { // if (connected_) {
137				event.process(this);
138			}
139		}
140	}
141	
142	/**
143	 * TransmissionEvent is a named subclass of event, which allows access to the message the
144	 * packet it is trying to send which is used, should the event be retracted. Moreover, the
145	 * notion of an explicit constructor which is called by the ELActor scheduling it, ensures
146	 * that the serialization of the message happens in the correct thread.
147	 *
148	 * @author smostinc
149	 */
150	private class TransmissionEvent extends Event {
151		public final Packet serializedMessage_;
152		
153		// Called by ELActor
154		public TransmissionEvent(ATAsyncMessage msg) throws XIOProblem {
155			super("transmit("+msg+")");
156			serializedMessage_ = new Packet(msg.toString(), msg);
157		}
158		
159		// Called by ELFarReference
160		public void process(Object owner) {
161			Address destAddress = getDestinationVMAddress();
162
163			if (destAddress != null) {
164				try {
165					new CMDTransmitATMessage(destination_.getActorId(), serializedMessage_).send(
166							dispatcher_, destAddress);
167
168					// getting here means the message was succesfully transmitted
169					
170				} catch (NetworkException e) {
171					Logging.RemoteRef_LOG.warn(this
172									+ ": timeout while trying to transmit message, retrying");
173					receivePrioritized(this);
174				}
175			} else {
176				Logging.RemoteRef_LOG.info(this + ": suspected a disconnection from " +
177						destination_ + " because destination VM ID was not found in address book");
178				connected_ = false;
179				receivePrioritized(this);
180			}
181		}
182	}
183	
184	public void event_transmit(final ATAsyncMessage msg) throws XIOProblem {
185		receive(new TransmissionEvent(msg));
186		
187		// the reception of a new event may awaken a sleeping ELFarReference thread, 
188		// so we interrupt the processor, forcing it to reevaluate its conditions
189		processor_.interrupt();
190	}
191	
192	public ATTable retractUnsentMessages() throws InterpreterException {
193		
194		BlockingFuture eventVectorF = setRetractingFuture();
195		
196		
197		try {
198			
199			Vector events = (Vector)eventVectorF.get();
200			ATObject[] messages = new ATObject[events.size()];
201			
202			for(int i = 0; i < events.size(); i++) {
203				TransmissionEvent current = (TransmissionEvent)events.get(i);
204				messages[i] = current.serializedMessage_.unpack();
205			}
206			
207			return NATTable.atValue(messages);
208
209		} catch (Exception e) {
210			e.printStackTrace();
211			//throw (InterpreterException) e;
212			return NATTable.EMPTY;
213		}
214	}
215	
216	/* ========================================================
217	 * == Implementation of the ConnectionListener interface ==
218	 * ========================================================
219	 */
220
221	public synchronized void connected() {
222		Logging.RemoteRef_LOG.info(this + ": reconnected to " + destination_);
223		connected_ = true;
224		this.notify();
225		farRef_.notifyConnected();
226	}
227
228	public synchronized void disconnected() {
229		// Will only take effect when next trying to send a message
230		// If currently sending, the message will time out first.
231		Logging.RemoteRef_LOG.info(this + ": disconnected from " + destination_);
232		connected_ = false;
233		farRef_.notifyDisconnected();
234	}
235	
236	public synchronized void expired(){
237		
238		Logging.RemoteRef_LOG.info(this + ": " + destination_ + " expired");
239		connected_ = false;
240		farRef_.notifyExpired();
241	}
242	
243	private Address getDestinationVMAddress() {
244		return owner_.getHost().vmAddressBook_.getAddressOf(destination_.getVirtualMachineId());
245	}
246	
247	public ATObjectID getDestination() {
248		return destination_;
249	}
250	
251	
252	public void execute() {
253
254		synchronized (this) {
255			while (eventQueue_.isEmpty() && outboxFuture_ == null) {
256				try {
257					this.wait();
258				} catch (InterruptedException e) { }
259			}
260
261			if (outboxFuture_ != null) {
262				handleRetractRequest();
263			} else { // if(! eventQueue_.isEmpty()) {
264				try {
265					handle(eventQueue_.dequeue());
266				} catch (InterruptedException e) { }
267			}
268		}
269	}
270
271}