/interpreter/tags/at2-build270707/src/edu/vub/at/actors/natives/ELDiscoveryActor.java

http://ambienttalk.googlecode.com/ · Java · 288 lines · 154 code · 20 blank · 114 comment · 7 complexity · 8f6fb7754472e4cb9bac05dd81de6f5a MD5 · raw file

  1. /**
  2. * AmbientTalk/2 Project
  3. * ELDiscoveryActor.java created on 23-feb-2007 at 11:45:46
  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.eventloops.Event;
  30. import edu.vub.at.actors.natives.DiscoveryManager.Publication;
  31. import edu.vub.at.actors.natives.DiscoveryManager.Subscription;
  32. import edu.vub.at.actors.net.cmd.CMDInitRequireServices;
  33. import edu.vub.at.actors.net.cmd.CMDJoinServices;
  34. import edu.vub.at.actors.net.cmd.CMDProvideService;
  35. import edu.vub.at.actors.net.cmd.CMDRequireService;
  36. import edu.vub.at.actors.net.comm.Address;
  37. import edu.vub.at.exceptions.InterpreterException;
  38. import edu.vub.at.objects.ATObject;
  39. import edu.vub.at.objects.ATTypeTag;
  40. import edu.vub.at.util.logging.Logging;
  41. import edu.vub.util.MultiMap;
  42. import java.util.Iterator;
  43. import java.util.Set;
  44. /**
  45. * Every VM has an associated DiscoveryBus Actor. This is a regular actor (with a native Actor Mirror)
  46. * which is responsible for matching local publications with local and remote subscriptions.
  47. *
  48. * @author tvcutsem
  49. */
  50. public final class ELDiscoveryActor extends ELActor {
  51. /** manages subscriptions and publications */
  52. private final DiscoveryManager discoveryManager_;
  53. public ELDiscoveryActor(ELVirtualMachine host) {
  54. super(host);
  55. discoveryManager_ = new DiscoveryManager();
  56. }
  57. /**
  58. * This event is fired whenever an object
  59. * is being offered as a service provide using the provide: language construct.
  60. * The discovery actor keeps track of such services and is responsible for the
  61. * matching between services and clients. When such matches are detected the VM
  62. * will send a foundResolution event to both involved actors. If the VM detects
  63. * that one partner has become unavailable it will send the lostResolution event
  64. *
  65. * @param pub - a publication containing the serialized forms of the topic and the exported service object
  66. */
  67. public void event_servicePublished(final Publication pub) {
  68. this.receive(new Event("servicePublished("+pub.providedTypeTag_+")") {
  69. public void process(Object myself) {
  70. try {
  71. pub.deserializedTopic_ = pub.providedTypeTag_.unpack().asTypeTag();
  72. discoveryManager_.addLocalPublication(pub);
  73. // broadcast the new publication to all currently connected VMs
  74. new CMDProvideService(pub.providedTypeTag_, pub.exportedService_).send(host_.communicationBus_);
  75. } catch (InterpreterException e) {
  76. Logging.VirtualMachine_LOG.error("error while publishing service " + pub.providedTypeTag_,e);
  77. }
  78. }
  79. });
  80. }
  81. /**
  82. * This event is fired whenever an object
  83. * requests a service using the require: language construct. The discovery manager
  84. * keeps track of such requests and is responsible matching services and clients.
  85. * When such matches are detected the VM will send a foundResolution event to both
  86. * involved actors. If the VM detects that one partner has become unavailable it
  87. * will send the lostResolution event
  88. *
  89. * @param sub - a subscription containing the serialized forms of the topic and the subscription handler
  90. */
  91. public void event_clientSubscribed(final Subscription sub) {
  92. this.receive(new Event("clientSubscribed("+sub.requiredTypeTag_+")") {
  93. public void process(Object myself) {
  94. try {
  95. sub.deserializedTopic_ = sub.requiredTypeTag_.unpack().asTypeTag();
  96. sub.deserializedHandler_ = sub.registeredHandler_.unpack();
  97. discoveryManager_.addLocalSubscription(sub);
  98. // broadcast the new subscription to all currently connected VMs
  99. new CMDRequireService(sub.requiredTypeTag_).send(host_.communicationBus_);
  100. } catch (InterpreterException e) {
  101. Logging.VirtualMachine_LOG.error("error while subscribing to service " + sub.requiredTypeTag_,e);
  102. }
  103. }
  104. });
  105. }
  106. /**
  107. * This event is fired whenever a service
  108. * offer is being revoked. In this case, the discovery manager ensures that the
  109. * object is no longer discoverable to new clients. However, it will not send
  110. * disconnected events as these signal that an object has become unreachable.
  111. * In other words: remote objects that had already discovered the object linked
  112. * to this publication will maintain their connection.
  113. *
  114. * @param pub - the original publication object to cancel
  115. */
  116. public void event_cancelPublication(final Publication pub) {
  117. this.receive(new Event("cancelPublication("+pub.providedTypeTag_+")") {
  118. public void process(Object myself) {
  119. discoveryManager_.deleteLocalPublication(pub);
  120. }
  121. });
  122. }
  123. /**
  124. * This event is fired whenever a service
  125. * request is being revoked. In this case, the discovery manager ensures that the
  126. * object will no longer discover new services. However, it will not send
  127. * lostResolution events as these signal that the client has become unreachable.
  128. *
  129. * @param sub - the original subscription object to cancel
  130. */
  131. public void event_cancelSubscription(final Subscription sub) {
  132. this.receive(new Event("cancelSubscription("+sub.requiredTypeTag_+")") {
  133. public void process(Object myself) {
  134. discoveryManager_.deleteLocalSubscription(sub);
  135. }
  136. });
  137. }
  138. /**
  139. * Received in response to the CMDProvideService command of a remote VM
  140. */
  141. public void event_remotePublication(final Packet serializedProvidedTopic, final Packet serializedProvidedService) {
  142. this.receive(new Event("remotePublication("+serializedProvidedTopic+")") {
  143. public void process(Object myself) {
  144. try {
  145. ATTypeTag providedTopic = serializedProvidedTopic.unpack().asTypeTag();
  146. ATObject providedService = serializedProvidedService.unpack();
  147. // notify subscribers of the new provided service
  148. Logging.VirtualMachine_LOG.debug("notifyOfExternalPublication("+providedTopic+","+providedService+")");
  149. discoveryManager_.notifyOfExternalPublication(providedTopic, providedService);
  150. } catch (InterpreterException e) {
  151. Logging.VirtualMachine_LOG.error("error while unserializing remote published service",e);
  152. }
  153. }
  154. });
  155. }
  156. /**
  157. * Received in response to the CMDJoinServices command of a remote VM
  158. *
  159. * @param matchingPublications - a map from serialized ATTypeTag topics to Sets of serialized
  160. * ATObjects that provide the serialized topic.
  161. */
  162. public void event_batchRemotePublications(final MultiMap matchingPublications) {
  163. this.receive(new Event("batchRemotePublications") {
  164. public void process(Object myself) {
  165. Set topics = matchingPublications.keySet();
  166. Logging.VirtualMachine_LOG.debug("batchRemotePublications: incoming topics = "+topics+" ("+topics.size()+" items)");
  167. // for each topic in the map
  168. for (Iterator iter = topics.iterator(); iter.hasNext();) {
  169. try {
  170. Packet serializedTopic = (Packet) iter.next();
  171. ATTypeTag unserializedTopic = serializedTopic.unpack().asTypeTag();
  172. Set matchingServices = (Set) matchingPublications.get(serializedTopic);
  173. Logging.VirtualMachine_LOG.debug("matchingPublications.get("+serializedTopic+") = "+matchingServices);
  174. // for each serialized object exported under the topic
  175. for (Iterator iterator = matchingServices.iterator(); iterator.hasNext();) {
  176. Packet serializedService = (Packet) iterator.next();
  177. ATObject unserializedService = serializedService.unpack();
  178. Logging.VirtualMachine_LOG.debug("notifyOfExternalPublication("+unserializedTopic+","+unserializedService+")");
  179. discoveryManager_.notifyOfExternalPublication(unserializedTopic, unserializedService);
  180. }
  181. } catch (InterpreterException e) {
  182. Logging.VirtualMachine_LOG.error("error while unserializing remote published service",e);
  183. }
  184. }
  185. }
  186. });
  187. }
  188. /**
  189. * Received in response to the CMDRequireService command of a remote VM
  190. *
  191. * TODO: perhaps transform this into a sync_event and let CMDRequireService perform the reply
  192. */
  193. public void event_remoteSubscription(final Packet serializedRequiredTopic, final Address replyTo) {
  194. this.receive(new Event("remoteSubscription("+serializedRequiredTopic+")") {
  195. public void process(Object myself) {
  196. try {
  197. ATTypeTag requiredTopic = serializedRequiredTopic.unpack().asTypeTag();
  198. // query local discoverymanager for matching topic
  199. Set matchingServices = discoveryManager_.getLocalPublishedServicesMatching(requiredTopic);
  200. Logging.VirtualMachine_LOG.debug("getLocalPubServMatching("+requiredTopic+") = "+matchingServices+" ("+matchingServices.size()+" items)");
  201. if (!matchingServices.isEmpty()) {
  202. // maps serialized topics to sets of serialized objects that are published under this topic
  203. MultiMap matchingTopics = new MultiMap();
  204. matchingTopics.putValues(serializedRequiredTopic, matchingServices);
  205. // send all matching topics back to the requestor
  206. new CMDJoinServices(matchingTopics).send(host_.communicationBus_, replyTo);
  207. }
  208. } catch (InterpreterException e) {
  209. Logging.VirtualMachine_LOG.error("error while unserializing remote subscription topic",e);
  210. }
  211. }
  212. });
  213. }
  214. /**
  215. * When a new VM has been discovered, the discovery agent is responsible for sending
  216. * all outstanding subscription topics to that VM, such that it can be checked whether
  217. * the newcomer has some publications that can resolve outstanding requests.
  218. */
  219. public void event_sendAllSubscriptionsTo(final Address newMember) {
  220. this.receive(new Event("sendAllSubscriptionsTo("+newMember+")") {
  221. public void process(Object myself) {
  222. // check if this VM has some outstanding subscriptions
  223. Set subscriptionTopics = discoveryManager_.getAllLocalSubscriptionTopics();
  224. Logging.VirtualMachine_LOG.debug("getAllLocalSubTopics() ="+subscriptionTopics+" ("+subscriptionTopics.size()+" items)");
  225. // only send a discovery query if this VM requires some services
  226. if (!subscriptionTopics.isEmpty()) {
  227. // send a discovery query message to the remote VM
  228. new CMDInitRequireServices(subscriptionTopics).send(host_.communicationBus_, newMember);
  229. }
  230. }
  231. });
  232. }
  233. /**
  234. * When a VM is discovered by another VM, that VM can send its outstanding subscriptions
  235. * to this VM. This event is received by an incoming CMDInitRequireServices command.
  236. * The local discovery manager should, for each incoming subscription topic, assemble all matching
  237. * local publication objects. A map of topic -> Set of publication objects is then returned
  238. * to the sender VM.
  239. *
  240. * @param subscriptionTopics - a Set of Packet objects representing serialized ATTypeTag topics
  241. */
  242. public void event_receiveNewSubscriptionsFrom(final Set subscriptionTopics, final Address fromMember) {
  243. this.receive(new Event("receiveNewSubscriptionsFrom("+fromMember+")") {
  244. public void process(Object myself) {
  245. // maps topics to sets of objects that are published under this topic
  246. MultiMap matchingTopics = new MultiMap();
  247. // query local discoverymanager for matching topics
  248. for (Iterator iter = subscriptionTopics.iterator(); iter.hasNext();) {
  249. try {
  250. Packet serializedTopic = (Packet) iter.next();
  251. ATTypeTag topic = serializedTopic.unpack().asTypeTag();
  252. Set matchingServices = discoveryManager_.getLocalPublishedServicesMatching(topic);
  253. Logging.VirtualMachine_LOG.debug("getLocalPubServMatching("+topic+") ="+matchingServices+" ("+matchingServices.size()+" items)");
  254. if (!matchingServices.isEmpty()) {
  255. matchingTopics.putValues(serializedTopic, matchingServices);
  256. }
  257. } catch (InterpreterException e) {
  258. Logging.VirtualMachine_LOG.error("error while unserializing remote subscription topic",e);
  259. }
  260. }
  261. if (!matchingTopics.isEmpty()) {
  262. // send all matching topics back to the requestor
  263. new CMDJoinServices(matchingTopics).send(host_.communicationBus_, fromMember);
  264. }
  265. }
  266. });
  267. }
  268. }