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

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