PageRenderTime 24ms CodeModel.GetById 7ms app.highlight 13ms RepoModel.GetById 1ms app.codeStats 0ms

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