FileDocCategorySizeDatePackage
RoundRobinPolicy.javaAPI DocGlassfish v2 API16106Fri May 04 22:32:54 BST 2007com.sun.appserv.naming

RoundRobinPolicy

public class RoundRobinPolicy extends Object
The list of endpoints are randomized the very first time. This happens only once( when called from the static block of S1ASCtxFactory class). Simple RoundRobin is a special case of Weighted Round Robin where the weight per endpoint is equal.With the dynamic reconfiguration implementation, the endpoints list willhave the following structure: - server_identifier (a stringified name for the machine) - weight- list of SocketInfo {type (type = CLEAR_TEXT or SSL) + IP address + port } The above structure supports multi-homed machines i.e. one machinehosting multiple IP addresses. The RoundRobinPolicy class can be the class that is also implementing the Listener interface for listening to events generated whenever there is a change in the cluster shape. The listener/event design is still under construction.This list of endpoints will have to be created during bootstrapping(i.e. when the client first starts up.) This list will comprise of theendpoints specified by the user in "com.sun.appserv.iiop.endpoints" property. We can assume a default weight for these endpoints (e.g 10). This list will be used to make the first lookup call. During the first lookup call, the actual list of endpoints will beprovided back. Then on, whenever there is any change in the clustershape, the listener will get the updated list of endpoints from theserver. The implementation for choosing the endpoint from the list of endpoints is as follows:Let's assume 4 endpoints:A(wt=10), B(wt=30), C(wt=40), D(wt=20). Using the Random API, generate a random number between 1 and10+30+40+20. Let's assume that the above list is randomized. Based on the weights, we have intervals as follows: 1-----10 (A's weight) 11----40 (A's weight + B's weight) 41----80 (A's weight + B's weight + C's weight) 81----100(A's weight + B's weight + C's weight + C's weight) Here's the psuedo code for deciding where to send the request: if (random_number between 1 & 10) {send request to A;} else if (random_number between 11 & 40) {send request to B;} else if (random_number between 41 & 80) {send request to C;} else if (random_number between 81 & 100) {send request to D;} For simple Round Robin, we can assume the same weight for all endpointsand perform the above.
author
Sheetal Vartak
date
8/2/05

Fields Summary
private List
endpointsList
private static Logger
_logger
private static Random
rand
private int
sumOfAllWeights
private static final int
default_weight
Constructors Summary
public RoundRobinPolicy(String[] list)


    //called during bootstrapping
               
	setClusterInstanceInfo(list);
    
Methods Summary
private java.lang.Object[]convertIntoCorbaloc(java.util.List list)

	List host_port = new LinkedList();
	for (ClusterInstanceInfo endpoint : list) {
	    SocketInfo[] socketInfo = endpoint.endpoints;
	    for (int j = 0; j < socketInfo.length; j++) {
		if (!host_port.contains(socketInfo[j].host.trim() +
					":" + socketInfo[j].port)) {
		    host_port.add(socketInfo[j].host.trim() + 
				  ":" + socketInfo[j].port);
		}
	    }
	}
	return host_port.toArray();
    
private java.lang.String[]getAddressPortList(java.lang.String[] hostPortList)
following methods (over-loaded) for getting all IP addresses corresponding to a particular host. (multi-homed hosts).

        // The list is assumed to contain <HOST NAME>:<PORT> values
        Vector addressPortVector = new Vector();
        for (int i=0; i<hostPortList.length; i++) {
            try {
                IiopUrl url = new IiopUrl("iiop://"+hostPortList[i]);
                String [] apList = getAddressPortList(url);
                for (int j=0; j<apList.length; j++) {
                    addressPortVector.addElement(apList[j]);
                }
            } catch (MalformedURLException me) {
                _logger.log(Level.WARNING, "bad.host.port", 
			    new Object[] {hostPortList[i],
					  me.getMessage()});
            }
        }
        String [] ret = new String[addressPortVector.size()];
        for (int i=0; i<ret.length; i++) {
            ret[i] = (String)addressPortVector.elementAt(i);
        }
        // We return a list of <IP ADDRESS>:<PORT> values
        return ret;
    
private java.lang.String[]getAddressPortList(com.sun.jndi.cosnaming.IiopUrl iiopUrl)

        // Pull out the host name and port
        IiopUrl.Address iiopUrlAddress = 
                (IiopUrl.Address)(iiopUrl.getAddresses().elementAt(0));
        String host = iiopUrlAddress.host;
        int portNumber = iiopUrlAddress.port;
        String port = Integer.toString(portNumber);
        // We return a list of <IP ADDRESS>:<PORT> values
        return getAddressPortList(host, port);        
    
public java.lang.String[]getAddressPortList(java.lang.String host, java.lang.String port)

        // Get the ip addresses corresponding to the host
        try {
            InetAddress [] addresses = InetAddress.getAllByName(host);
            String[] ret = new String[addresses.length];
            for (int i = 0; i < addresses.length; i++) {
                ret[i] = addresses[i].getHostAddress() + ":" + port;
            }
            // We return a list of <IP ADDRESS>:<PORT> values
            return ret;
        } catch (UnknownHostException ukhe) {
            _logger.log(Level.WARNING, "unknown.host",
			new Object[] {host, ukhe.getMessage()});
            return null;
        }
    
public java.lang.String[]getEndpointForProviderURL(java.lang.String providerURLString)
This method checks for other ways of specifying endpoints namely JNDI provider url orb host:port is used only if even env passed into getInitialContext is empty. This check is performed in S1ASCtxFactory.getInitialContext()

     	String[] newList = null;
	if (providerURLString != null) {
	    try {
		IiopUrl providerURL = new IiopUrl(providerURLString);
		newList = getAddressPortList(providerURL);	
		_logger.log(Level.WARNING, "no.endpoints.selected.provider", 
			    new Object[] {providerURLString});
	    } catch (MalformedURLException me) {
		_logger.log(Level.WARNING, "provider.exception", 
			    new Object[] {me.getMessage(), 
					  providerURLString});
	    }	    
	} 
	return newList;
    
public synchronized java.lang.Object[]getNextRotation()
get a new shape of the endpoints For e.g. if list contains A,B,C if the logic below chooses B as the endpoint to send the req to then return B,C,A. logic used is as described in Class description comments

	int lowerLimit = 0; //lowerLimit
	int random = 0;
	//make sure that the random # is not 0
	//Random API gives a number between 0 and sumOfAllWeights
	//But our range intervals are from 1-upperLimit, 
	//11-upperLimit and so
	//on. Hence we dont want random # to be 0.
	_logger.fine("RoundRobinPolicy.getNextRotation -> sumOfAllWeights = " + sumOfAllWeights);
	while( random == 0) {
	    random = rand.nextInt(sumOfAllWeights);
	    if ( random != 0) {
		break;
	    }
	}
	_logger.fine("getNextRotation : random # = " + random + 
		     " sum of all weights = " + sumOfAllWeights);
	int i = 0;
	for (ClusterInstanceInfo endpoint : endpointsList) {
	    int upperLimit = lowerLimit + endpoint.weight;	    
	    _logger.fine("upperLimit = " + upperLimit);
	    if (random > lowerLimit && random <= upperLimit) {
		List<ClusterInstanceInfo> instanceInfo = 
		    new LinkedList<ClusterInstanceInfo>();
		
		//add the sublist at index 0 
		instanceInfo.addAll(0, 
				    endpointsList.subList(i, 
							  endpointsList.size()));
		//add the remaining list
		instanceInfo.addAll(endpointsList.subList(0, i));
		
		//print the contents...
		_logger.fine("returning the following list..." + 
			     instanceInfo.toString());
		
		return convertIntoCorbaloc(instanceInfo);
	    }
	    lowerLimit = upperLimit;
	    _logger.fine("lowerLimit = " + lowerLimit);	
	    i++;    
	}
	_logger.warning("Could not find an endpoint to send request to!");
	return null;
    
public synchronized booleanisEmpty()
return true of endpoints list is empty

	if (endpointsList.size() == 0)
	    return true;
	else return false;
      
private com.sun.corba.ee.spi.folb.ClusterInstanceInfomakeClusterInstanceInfo(java.lang.String str, int weight)
during bootstrapping, weight is assumed "10" for all endpoints then on, whenever server sends updates list, create the list again here with right weights

	String[] host_port = str.split(":");
	String server_identifier = ""; //for bootstrapping, can be ""
	String type = "CLEAR_TEXT"; //will be clear_text for bootstrapping
	SocketInfo socketInfo = new SocketInfo(type,
					       host_port[0],
					       new Integer(host_port[1]).intValue());
	ClusterInstanceInfo instanceInfo = 
	    new ClusterInstanceInfo(server_identifier, 
				    weight,
				    new SocketInfo[]{socketInfo});
	return instanceInfo;
	
    
private synchronized booleannotDuplicate(java.lang.String str)
find whether the string argument is already present in the endpointsList vector

	String[] host_port = str.split(":");
	for (ClusterInstanceInfo endpoint : endpointsList) {
	    ClusterInstanceInfo instanceInfo = endpoint;
	    for(int j = 0; j < instanceInfo.endpoints.length; j++) {
		if (instanceInfo.endpoints[j].host.equals(host_port[0]) && 
		    instanceInfo.endpoints[j].port == 
		    new Integer(host_port[1]).intValue()) {
		    return false;
		}
	    }
	}
	return true;
    
public synchronized voidprint()
log list contents

        _logger.fine("List contents ==> ");
	int i = 0;
	for (ClusterInstanceInfo endpoint : endpointsList) {
	    ClusterInstanceInfo instanceInfo = endpoint;
	    
	    _logger.fine("endpoint[" + i + "] ==> name =" + 
			 instanceInfo.name + " weight = " + 
			 instanceInfo.weight);
	    for (int j = 0; j < instanceInfo.endpoints.length; j++ ) {
		_logger.fine("IP addresses = " + 
			     instanceInfo.endpoints[j].host + ":" + 
			     instanceInfo.endpoints[j].port  + 
			     " type = " + instanceInfo.endpoints[j].type);
	    }
	    i++;
	}
    
public java.lang.String[]randomize(java.lang.String[] list)
randomize the list

        //randomise the list to enable loadbalancing
	String[] randomizedList = new String[list.length];
        for (int i = 0; i < list.length; i++) {
	    int random;
	    do {		
	        random = rand.nextInt(list.length);
		_logger.fine("random ==> " + random);
	    } while (list[random] == null);
	    randomizedList[i] = list[random];
	    _logger.fine("randomisedList[" + i + "] ==> " + 
			 randomizedList[i]);
	    list[random] = null;
	}
	return randomizedList;
    
public synchronized voidsetClusterInstanceInfo(java.util.List list)

	sumOfAllWeights = 0;
	endpointsList = list;

	String policy = System.getProperty(S1ASCtxFactory.LOAD_BALANCING_PROPERTY);
	boolean isWeighted;
	if (policy == null) {
	    //default is ic-based
	    policy = S1ASCtxFactory.IC_BASED;
	}
	if (policy.equals(S1ASCtxFactory.IC_BASED_WEIGHTED)) {
	    isWeighted = true;
	} else if (policy.equals(S1ASCtxFactory.IC_BASED)) {
	    isWeighted = false;
	} else {
	    isWeighted = false;
	    _logger.warning("loadbalancing.policy.incorrect");
	}	
	_logger.fine("isWeighted = " + isWeighted);
	//make the weights of all endpoints = default_weight
	for (ClusterInstanceInfo endpoint : endpointsList) {
	    if (! isWeighted) {
		endpoint.weight = default_weight;
	    }
	    _logger.info("endpoint.weight after checking isWeight = " + endpoint.weight);
	    sumOfAllWeights += endpoint.weight;
	} 
	_logger.info("sumOfAllWeights = " + sumOfAllWeights);
    
public synchronized voidsetClusterInstanceInfo(java.lang.String[] list)
add a string array of endpoints to list

        String[] newList = null;
	
	//if no endpoints are specified as a system property,
        //then look for JNDI provider url
        //we are not looking for the host:port sys property
        //because ORBManager assumes default values of localhost 
	//and 3700
        //localhost is an issue since it gives back both IPv4 and
	// IPv6 addresses
        //3700 is a problem since it is specifically used as a DAS port. 
        //If resources are deployed to a cluster, they are not available
	// to DAS. 
        //So if the DAS host:port is used, 
        //then it will definitely result in a NameNotFoundException
	if (list != null && list.length > 0) {
	    newList = getAddressPortList(list);
	} else {
	    newList = getEndpointForProviderURL(
	  System.getProperty(ORBManager.JNDI_PROVIDER_URL_PROPERTY));
	}
	//randomize the list before adding it to linked list
	if (newList != null && newList.length > 0) {
	    String[] new_list = randomize(newList);
	    List<ClusterInstanceInfo> targetServerList = 
		new LinkedList <ClusterInstanceInfo> ();
	    for (int i = 0; i < new_list.length; i++) {
		if (notDuplicate(new_list[i])) {
		    targetServerList.add(
					 makeClusterInstanceInfo(
								 new_list[i], 
								 default_weight));
		}
	    }
	    if (!targetServerList.isEmpty()) {
		targetServerList.addAll(endpointsList);
		setClusterInstanceInfo(targetServerList); 
	    }
	} else {
	    _logger.log(Level.WARNING,"no.endpoints");	 
	}