PageRenderTime 34ms CodeModel.GetById 10ms app.highlight 19ms RepoModel.GetById 1ms app.codeStats 0ms

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