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