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