PageRenderTime 68ms CodeModel.GetById 16ms app.highlight 45ms RepoModel.GetById 2ms app.codeStats 0ms

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