/interpreter/tags/at2-build190607/src/edu/vub/at/actors/natives/DiscoveryManager.java

http://ambienttalk.googlecode.com/ · Java · 283 lines · 151 code · 24 blank · 108 comment · 20 complexity · 3f9ebf990b1ee7eb35b4d13c8da41180 MD5 · raw file

  1. /**
  2. * AmbientTalk/2 Project
  3. * DiscoveryManager.java created on 18-jan-2007 at 16:03:30
  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.eval.Evaluator;
  30. import edu.vub.at.exceptions.InterpreterException;
  31. import edu.vub.at.objects.ATObject;
  32. import edu.vub.at.objects.ATTypeTag;
  33. import edu.vub.at.objects.natives.NATTable;
  34. import edu.vub.at.util.logging.Logging;
  35. import java.util.HashSet;
  36. import java.util.Iterator;
  37. import java.util.LinkedList;
  38. import java.util.Set;
  39. /**
  40. * The DiscoveryManager is responsible for coupling subscriptions to
  41. * corresponding publications.
  42. *
  43. * @author tvcutsem
  44. */
  45. public final class DiscoveryManager {
  46. /**
  47. * Small container class that represents an entry in the publications list.
  48. */
  49. public static class Publication {
  50. public final ELActor providerActor_;
  51. public final Packet providedTypeTag_;
  52. public final Packet exportedService_;
  53. public ATTypeTag deserializedTopic_;
  54. public Publication(ELActor provider, Packet type, Packet exportedService) {
  55. providerActor_ = provider;
  56. providedTypeTag_ = type;
  57. exportedService_ = exportedService;
  58. }
  59. }
  60. /**
  61. * Small container class that represents an entry in the subscriptions list.
  62. */
  63. public static class Subscription {
  64. public final ELActor subscriberActor_;
  65. public final Packet requiredTypeTag_;
  66. public final Packet registeredHandler_;
  67. public final boolean isPermanentSubscription_;
  68. public ATTypeTag deserializedTopic_;
  69. public ATObject deserializedHandler_;
  70. public Subscription(ELActor subscriber, Packet type, Packet registeredHandler, boolean permanent) {
  71. subscriberActor_ = subscriber;
  72. requiredTypeTag_ = type;
  73. registeredHandler_ = registeredHandler;
  74. isPermanentSubscription_ = permanent;
  75. }
  76. }
  77. /**
  78. * A list of Publication objects that represent locally exported service objects.
  79. */
  80. private final LinkedList publications_;
  81. /**
  82. * A list of Subscription objects that represent local subscription handlers.
  83. */
  84. private final LinkedList subscriptions_;
  85. public DiscoveryManager() {
  86. publications_ = new LinkedList();
  87. subscriptions_ = new LinkedList();
  88. }
  89. /**
  90. * A new local publication:
  91. * - is stored locally
  92. * - is checked against local subscriptions, which fire immediately
  93. * - is broadcast to all currently connected members (done by VM)
  94. */
  95. public void addLocalPublication(Publication pub) {
  96. publications_.add(pub);
  97. notifyLocalSubscribers(pub);
  98. }
  99. /**
  100. * A deleted local publication is simply deleted locally. No further actions
  101. * are required because remote VMs do not cache publications.
  102. */
  103. public void deleteLocalPublication(Publication pub) {
  104. publications_.remove(pub);
  105. }
  106. /**
  107. * A new local subscription:
  108. * - is stored locally
  109. * - is checked against local publications, which may cause the subscrption
  110. * to fire immediately
  111. * - is broadcast to all currently connected members (done by VM)
  112. */
  113. public void addLocalSubscription(Subscription sub) {
  114. subscriptions_.add(sub);
  115. checkLocalPublishers(sub);
  116. }
  117. /**
  118. * A deleted local subscription is simply deleted locally. No further actions
  119. * are required because remote VMs do not cache subscriptions.
  120. */
  121. public void deleteLocalSubscription(Subscription sub) {
  122. subscriptions_.remove(sub);
  123. }
  124. /**
  125. * Returns all local publications matching the given topic. This method is used
  126. * when a remote VM has broadcast a subscription request or when two VMs discover
  127. * one another.
  128. *
  129. * @return a Set of Packet objects representing the serialized form of objects
  130. * published under a topic matching the argument topic.
  131. */
  132. public Set getLocalPublishedServicesMatching(ATTypeTag topic) {
  133. HashSet matchingPubs = new HashSet();
  134. for (Iterator iter = publications_.iterator(); iter.hasNext();) {
  135. Publication pub = (Publication) iter.next();
  136. try {
  137. if (pub.deserializedTopic_.base_isSubtypeOf(topic).asNativeBoolean().javaValue) {
  138. matchingPubs.add(pub.exportedService_);
  139. }
  140. } catch (InterpreterException e) {
  141. Logging.Actor_LOG.error("error matching types while querying local publications:",e);
  142. }
  143. }
  144. return matchingPubs;
  145. }
  146. /**
  147. * @return a Set of Packet objects denoting the serialized form of all topics for which
  148. * a local subscription is still open.
  149. */
  150. public Set getAllLocalSubscriptionTopics() {
  151. HashSet openSubs = new HashSet();
  152. for (Iterator iter = subscriptions_.iterator(); iter.hasNext();) {
  153. Subscription sub = (Subscription) iter.next();
  154. openSubs.add(sub.requiredTypeTag_);
  155. }
  156. return openSubs;
  157. }
  158. /**
  159. * When a remote VM hears the request of the local VM for services it requires,
  160. * it returns its own matching services, using a CMDJoinServices command. Via this
  161. * command, the local discovery manager is notified of external matches.
  162. *
  163. * @param topic an outstanding subscription topic of this VM
  164. * @param remoteService the remote service matching the topic
  165. */
  166. public void notifyOfExternalPublication(ATTypeTag pubTopic, ATObject remoteService) {
  167. for (Iterator iter = subscriptions_.iterator(); iter.hasNext();) {
  168. Subscription sub = (Subscription) iter.next();
  169. try {
  170. // publication type Tp <: subscription type Ts
  171. if (pubTopic.base_isSubtypeOf(sub.deserializedTopic_).asNativeBoolean().javaValue) {
  172. // no need to test for separate actors, publisher is remote to this VM, so surely different actors
  173. notify(sub.deserializedHandler_, remoteService);
  174. // if the subscription is not permanent, cancel it
  175. if (!sub.isPermanentSubscription_) {
  176. iter.remove();
  177. }
  178. }
  179. } catch (InterpreterException e) {
  180. Logging.Actor_LOG.error("error matching types during external notification:",e);
  181. }
  182. }
  183. }
  184. /**
  185. * When a new publication is added locally, it is first checked whether this publication
  186. * can already satisfy some outstanding subscriptions on this VM (but from different actors)
  187. */
  188. private void notifyLocalSubscribers(Publication pub) {
  189. ATObject deserializedService = null; // only deserialize once we have a match
  190. for (Iterator iter = subscriptions_.iterator(); iter.hasNext();) {
  191. Subscription sub = (Subscription) iter.next();
  192. try {
  193. // publication type Tp <: subscription type Ts
  194. if (pub.deserializedTopic_.base_isSubtypeOf(sub.deserializedTopic_).asNativeBoolean().javaValue) {
  195. // only notify if subscriber is hosted by another actor than publisher
  196. if (sub.subscriberActor_ != pub.providerActor_) {
  197. if (deserializedService == null) {
  198. // first deserialize publisher
  199. deserializedService = pub.exportedService_.unpack();
  200. }
  201. notify(sub.deserializedHandler_, deserializedService);
  202. // if the subscription is not permanent, cancel it
  203. if (!sub.isPermanentSubscription_) {
  204. iter.remove();
  205. }
  206. }
  207. }
  208. } catch (InterpreterException e) {
  209. Logging.Actor_LOG.error("error matching types during local notification:",e);
  210. }
  211. }
  212. }
  213. /**
  214. * When a new subscription is added locally, it is first checked whether this subscription
  215. * can already be satisfied by some local publications on this VM (but from different actors)
  216. */
  217. private void checkLocalPublishers(Subscription sub) {
  218. ATObject deserializedService = null; // only deserialize once we have a match
  219. for (Iterator iter = publications_.iterator(); iter.hasNext();) {
  220. Publication pub = (Publication) iter.next();
  221. try {
  222. // publication type Tp <: subscription type Ts
  223. if (pub.deserializedTopic_.base_isSubtypeOf(sub.deserializedTopic_).asNativeBoolean().javaValue) {
  224. // only notify if subscriber is hosted by another actor than publisher
  225. if (sub.subscriberActor_ != pub.providerActor_) {
  226. if (deserializedService == null) {
  227. // first deserialize publisher
  228. deserializedService = pub.exportedService_.unpack();
  229. }
  230. notify(sub.deserializedHandler_, deserializedService);
  231. // if the subscription is not permanent, cancel it
  232. if (!sub.isPermanentSubscription_) {
  233. this.deleteLocalSubscription(sub);
  234. }
  235. }
  236. }
  237. } catch (InterpreterException e) {
  238. Logging.Actor_LOG.error("error matching types during local notification:",e);
  239. }
  240. }
  241. }
  242. /**
  243. * Performs <code>handler&lt;-apply([ service ])</code>
  244. */
  245. private void notify(ATObject handler, ATObject service) {
  246. Logging.VirtualMachine_LOG.debug("notifying: "+handler+"<-(["+service+"])");
  247. try {
  248. handler.meta_receive(
  249. new NATAsyncMessage(handler,
  250. Evaluator._APPLY_,
  251. NATTable.atValue(new ATObject[] {
  252. NATTable.atValue(new ATObject[] {service})
  253. }),
  254. NATTable.EMPTY));
  255. } catch (InterpreterException e) {
  256. Logging.VirtualMachine_LOG.error("DiscoveryManager: error notifying subscriber closure:", e);
  257. }
  258. }
  259. }