/interpreter/tags/at2dist130208/src/edu/vub/at/actors/natives/ELDiscoveryActor.java

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