PageRenderTime 33ms CodeModel.GetById 16ms app.highlight 12ms RepoModel.GetById 2ms app.codeStats 0ms

/interpreter/tags/at_build150307/src/edu/vub/at/actors/net/MembershipNotifier.java

http://ambienttalk.googlecode.com/
Java | 187 lines | 69 code | 25 blank | 93 comment | 11 complexity | a3b22cfbeb3470c40143c86754bfa76f MD5 | raw file
  1/**
  2 * AmbientTalk/2 Project
  3 * MembershipNotifier.java created on Feb 16, 2007 at 1:14:08 PM
  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.net;
 29
 30import edu.vub.at.actors.id.GUID;
 31import edu.vub.util.MultiMap;
 32
 33import java.util.Iterator;
 34import java.util.Set;
 35import java.util.Vector;
 36
 37import org.jgroups.Address;
 38import org.jgroups.ExtendedReceiverAdapter;
 39import org.jgroups.MembershipListener;
 40import org.jgroups.View;
 41
 42/**
 43 * An instance of the class MembershipNotifier is registered with an instance of the JGroups
 44 * MessageDispatcher class as its MembershipListener. Whenever virtual machines connect or
 45 * disconnect from the multicast group, this object is notified. Its role is to propagate
 46 * these notifications to:
 47 *  A) The AT/2 DiscoveryManager which is interested in contacting newly joined virtual machines
 48 *     to see whether they provide some services that this VM requires.
 49 *  B) All connected ConnectionListeners, which will usually be remote references pointing to
 50 *     objects hosted by the connecting/disconnecting VM.
 51 *
 52 *
 53 * TODO: change Address keys of ConnectionListeners to GUIDs to support changing addresses.
 54 *
 55 * @author tvcutsem
 56 */
 57public class MembershipNotifier extends ExtendedReceiverAdapter implements MembershipListener {
 58    
 59	/**
 60	 * Members of the previously accepted view are stored to evaluate the difference with any
 61	 * new view that may be signalled to this class. 
 62	 */
 63	private final Vector knownMembers_;
 64	
 65	/**
 66	 * A collection of ConnectionListeners which are interested in the (dis)appearance of a single
 67	 * node in the JGroups overlay network.
 68	 */
 69	private final MultiMap connectionListeners_;
 70	
 71	/**
 72	 * The general manager for service discovery for the entire virtual machine. Whenever a new VM
 73	 * is encountered, this manager needs to be notified such that it can exchange the necessary 
 74	 * service descriptions. Likewise, VM disconnections should be delegated to this listener.
 75	 */
 76	private final DiscoveryListener discoveryManager_;
 77	
 78	/**
 79	 * Creates a new MembershipNotifier on which ConnectionListeners monitoring the (dis)appearance
 80	 * of a single address can register to. 
 81	 * @param discoveryManager - the service discovery manager for the current address.
 82	 */
 83	public MembershipNotifier(DiscoveryListener discoveryManager) {
 84		discoveryManager_ = discoveryManager;
 85		connectionListeners_ = new MultiMap();
 86		knownMembers_ = new Vector();
 87	}
 88	
 89	/**
 90	 * Registers <code>listener</code> to be notified whenever a virtual machine becomes (un)reachable.
 91	 * 
 92	 * TODO: store only WEAK references to the remote references
 93	 * 
 94	 * @param virtualMachine - an address of the virtual machine hosting the object the listener is interested in
 95	 * @param listener - a listener which will be notified whenever the said address connects or disconnects
 96	 */
 97	public synchronized void addConnectionListener(GUID virtualMachine, ConnectionListener listener) {
 98		connectionListeners_.put(virtualMachine, listener);
 99	}
100	
101	/**
102	 * Unregisters <code>listener</code> such that it will no longer be notified whenever a 
103	 * particular virtual machine becomes (un)reachable.
104	 */
105	public synchronized void removeConnectionListener(GUID virtualMachine, ConnectionListener listener) {
106		connectionListeners_.removeValue(virtualMachine, listener);
107	}
108	
109    /**
110     * This method is a callback from the JGroups framework that is invoked whenever the
111     * set of connected group members has changed. The callback responds to such an event
112     * by comparing the new set of members with the previously known set of members to calculate
113     * which members joined and left. For each of these joined and left members, the corresponding
114     * connection listeners are notified. Also, the discovery manager is always notified when
115     * a member has joined.
116     */
117	public synchronized void viewAccepted(View newView) {
118		Vector newMembers = newView.getMembers();
119		Logging.VirtualMachine_LOG.debug("received new view: " + newView);
120		
121		// for each new member, check whether that new member was present in previous view
122		for (Iterator iter = newMembers.iterator(); iter.hasNext();) {
123			Address member = (Address) iter.next();
124			if (!knownMembers_.contains(member)) {
125				// member who is in new view but not in old view: joined
126				
127				// notify discovery manager
128				discoveryManager_.memberJoined(member);
129				
130			}
131		}
132		
133		// for each old member, check whether the old member is still present in new view
134		for (Iterator iter = knownMembers_.iterator(); iter.hasNext();) {
135			Address member = (Address) iter.next();
136			if (!newMembers.contains(member)) {
137				// member who is in old view but not in new view: left
138				
139				// notify discovery manager
140				discoveryManager_.memberLeft(member);
141				
142			}
143		}
144		
145		// new view becomes previous view
146		knownMembers_.clear();
147		knownMembers_.addAll(newMembers);
148	}
149
150	public synchronized void notifyConnected(GUID vmId){
151		//notify all connectionlisteners for this member
152		Set listeners = (Set)connectionListeners_.get(vmId);
153		if(listeners != null) {
154			for (Iterator i = listeners.iterator(); i.hasNext();) {
155				ConnectionListener listener = (ConnectionListener) i.next();
156				listener.connected();
157			}
158		}
159	}
160	
161	public synchronized void notifyDisconnected(GUID vmId){
162		
163		//notify all connectionlisteners for this member
164		Set listeners = (Set)connectionListeners_.get(vmId);
165		if(listeners != null) {
166			for (Iterator i = listeners.iterator(); i.hasNext();) {
167				ConnectionListener listener = (ConnectionListener) i.next();
168				listener.disconnected();
169			}
170		}
171	}
172	
173	// Called by the VM when it has disconnected from the underlying channel
174	public synchronized void channelDisconnected() {
175		for (Iterator membersI = knownMembers_.iterator(); membersI.hasNext();) {
176			// for all members who were in the view
177			Address member = (Address) membersI.next();
178			
179			// notify discovery manager
180			discoveryManager_.memberLeft(member);
181
182		}
183		
184		// clear the set of known members
185		knownMembers_.clear();
186	}
187}