KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > appserv > naming > RoundRobinPolicy


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 package com.sun.appserv.naming;
25
26 import java.util.logging.Level JavaDoc;
27 import com.sun.logging.LogDomains;
28 import java.util.logging.Logger JavaDoc;
29
30 import java.util.LinkedList JavaDoc;
31 import java.util.List JavaDoc;
32 import java.util.Vector JavaDoc;
33 import java.net.InetAddress JavaDoc;
34
35 import java.net.MalformedURLException JavaDoc;
36 import java.net.UnknownHostException JavaDoc;
37
38 import com.sun.jndi.cosnaming.IiopUrl;
39 import com.sun.corba.ee.spi.folb.ClusterInstanceInfo;
40 import com.sun.corba.ee.spi.folb.SocketInfo;
41 import com.sun.enterprise.util.ORBManager;
42
43 /**
44  * The list of endpoints are randomized the very first time.
45  * This happens only once( when called from the static block
46  * of S1ASCtxFactory class).
47  * Simple RoundRobin is a special case of Weighted Round Robin where the
48  * weight per endpoint is equal.With the dynamic reconfiguration
49  * implementation, the endpoints list willhave the following structure:
50  * - server_identifier (a stringified name for the machine)
51  * - weight- list of SocketInfo {type (type = CLEAR_TEXT or SSL) +
52  * IP address + port }
53  * The above structure supports multi-homed machines
54  * i.e. one machinehosting multiple IP addresses.
55  * The RoundRobinPolicy class can be the class that is also implementing
56  * the Listener interface for listening to events generated whenever there
57  * is a change in the cluster shape. The listener/event design is still
58  * under construction.This list of endpoints will have to be created during
59  * bootstrapping(i.e. when the client first starts up.) This list will comprise
60  * of theendpoints specified by the user in "com.sun.appserv.iiop.endpoints"
61  * property. We can assume a default weight for these endpoints (e.g 10).
62  * This list will be used to make the first lookup call. During the first
63  * lookup call, the actual list of endpoints will beprovided back.
64  * Then on, whenever there is any change in the clustershape,
65  * the listener will get the updated list of endpoints from theserver.
66  * The implementation for choosing the endpoint from the list of endpoints
67  * is as follows:Let's assume 4 endpoints:A(wt=10), B(wt=30), C(wt=40),
68  * D(wt=20).
69  * Using the Random API, generate a random number between 1 and10+30+40+20.
70  * Let's assume that the above list is randomized. Based on the weights, we
71  * have intervals as follows:
72  * 1-----10 (A's weight)
73  * 11----40 (A's weight + B's weight)
74  * 41----80 (A's weight + B's weight + C's weight)
75  * 81----100(A's weight + B's weight + C's weight + C's weight)
76  * Here's the psuedo code for deciding where to send the request:
77  * if (random_number between 1 & 10) {send request to A;}
78  * else if (random_number between 11 & 40) {send request to B;}
79  * else if (random_number between 41 & 80) {send request to C;}
80  * else if (random_number between 81 & 100) {send request to D;}
81  * For simple Round Robin, we can assume the same weight for all endpointsand
82  * perform the above.
83  * @author Sheetal Vartak
84  * @date 8/2/05
85  **/

86
87 public class RoundRobinPolicy {
88
89      private List JavaDoc<ClusterInstanceInfo> endpointsList =
90      new LinkedList JavaDoc<ClusterInstanceInfo>();
91
92     private static Logger JavaDoc _logger = LogDomains.getLogger(
93                     LogDomains.JNDI_LOGGER);
94
95     private static java.util.Random JavaDoc rand = new java.util.Random JavaDoc();
96
97     private int sumOfAllWeights = 0;
98
99     private static final int default_weight = 10;
100
101     //called during bootstrapping
102
public RoundRobinPolicy(String JavaDoc[] list) {
103     setClusterInstanceInfo(list);
104     }
105
106     //will be called after dynamic reconfig
107
public void setClusterInstanceInfo(List JavaDoc<ClusterInstanceInfo> list) {
108     sumOfAllWeights = 0;
109     endpointsList = list;
110
111     String JavaDoc policy = System.getProperty(S1ASCtxFactory.LOAD_BALANCING_PROPERTY);
112     boolean isWeighted;
113     if (policy == null) {
114         //default is ic-based
115
policy = S1ASCtxFactory.IC_BASED;
116     }
117     if (policy.equals(S1ASCtxFactory.IC_BASED_WEIGHTED)) {
118         isWeighted = true;
119     } else if (policy.equals(S1ASCtxFactory.IC_BASED)) {
120         isWeighted = false;
121     } else {
122         isWeighted = false;
123         _logger.warning("loadbalancing.policy.incorrect");
124     }
125     //make the weights of all endpoints = default_weight
126
for (ClusterInstanceInfo endpoint : endpointsList) {
127         if (! isWeighted) {
128         endpoint.weight = default_weight;
129         }
130         sumOfAllWeights += endpoint.weight;
131     }
132     }
133     
134     /**
135      * add a string array of endpoints to list
136      */

137     public void setClusterInstanceInfo(String JavaDoc[] list) {
138         String JavaDoc[] newList = null;
139     
140     //if no endpoints are specified as a system property,
141
//then look for JNDI provider url
142
//we are not looking for the host:port sys property
143
//because ORBManager assumes default values of localhost
144
//and 3700
145
//localhost is an issue since it gives back both IPv4 and
146
// IPv6 addresses
147
//3700 is a problem since it is specifically used as a DAS port.
148
//If resources are deployed to a cluster, they are not available
149
// to DAS.
150
//So if the DAS host:port is used,
151
//then it will definitely result in a NameNotFoundException
152
if (list != null && list.length > 0) {
153         newList = getAddressPortList(list);
154     } else {
155         newList = getEndpointForProviderURL(
156       System.getProperty(ORBManager.JNDI_PROVIDER_URL_PROPERTY));
157     }
158     //randomize the list before adding it to linked list
159
if (newList != null && newList.length > 0) {
160         String JavaDoc[] new_list = randomize(newList);
161         List JavaDoc<ClusterInstanceInfo> targetServerList =
162         new LinkedList JavaDoc <ClusterInstanceInfo> ();
163         for (int i = 0; i < new_list.length; i++) {
164         if (notDuplicate(new_list[i])) {
165             targetServerList.add(
166                      makeClusterInstanceInfo(
167                                  new_list[i],
168                                  default_weight));
169         }
170         }
171         if (!targetServerList.isEmpty()) {
172         targetServerList.addAll(endpointsList);
173         setClusterInstanceInfo(targetServerList);
174         }
175     } else {
176         _logger.log(Level.WARNING,"no.endpoints");
177     }
178     }
179
180     /**
181      * during bootstrapping, weight is assumed "10" for all endpoints
182      * then on, whenever server sends updates list,
183      * create the list again here with right weights
184      */

185     private ClusterInstanceInfo makeClusterInstanceInfo(String JavaDoc str, int weight) {
186     String JavaDoc[] host_port = str.split(":");
187     String JavaDoc server_identifier = ""; //for bootstrapping, can be ""
188
String JavaDoc type = "CLEAR_TEXT"; //will be clear_text for bootstrapping
189
SocketInfo socketInfo = new SocketInfo(type,
190                            host_port[0],
191                            new Integer JavaDoc(host_port[1]).intValue());
192     ClusterInstanceInfo instanceInfo =
193         new ClusterInstanceInfo(server_identifier,
194                     weight,
195                     new SocketInfo[]{socketInfo});
196     return instanceInfo;
197     
198     }
199
200     /**
201     * find whether the string argument is already
202     * present in the endpointsList vector
203     */

204     private boolean notDuplicate(String JavaDoc str) {
205     String JavaDoc[] host_port = str.split(":");
206     for (ClusterInstanceInfo endpoint : endpointsList) {
207         ClusterInstanceInfo instanceInfo = endpoint;
208         for(int j = 0; j < instanceInfo.endpoints.length; j++) {
209         if (instanceInfo.endpoints[j].host.equals(host_port[0]) &&
210             instanceInfo.endpoints[j].port ==
211             new Integer JavaDoc(host_port[1]).intValue()) {
212             return false;
213         }
214         }
215     }
216     return true;
217     }
218     
219     /**
220      * This method checks for other ways of specifying endpoints
221      * namely JNDI provider url
222      * orb host:port is used only if even env passed into
223      * getInitialContext is empty. This check is performed in
224      * S1ASCtxFactory.getInitialContext()
225      */

226     public String JavaDoc[] getEndpointForProviderURL(String JavaDoc providerURLString) {
227         String JavaDoc[] newList = null;
228     if (providerURLString != null) {
229         try {
230         IiopUrl providerURL = new IiopUrl(providerURLString);
231         newList = getAddressPortList(providerURL);
232         _logger.log(Level.WARNING, "no.endpoints.selected.provider",
233                 new Object JavaDoc[] {providerURLString});
234         } catch (MalformedURLException JavaDoc me) {
235         _logger.log(Level.WARNING, "provider.exception",
236                 new Object JavaDoc[] {me.getMessage(),
237                       providerURLString});
238         }
239     }
240     return newList;
241     }
242     
243     /**
244      * randomize the list
245      */

246     public String JavaDoc[] randomize(String JavaDoc[] list) {
247         //randomise the list to enable loadbalancing
248
String JavaDoc[] randomizedList = new String JavaDoc[list.length];
249         for (int i = 0; i < list.length; i++) {
250         int random;
251         do {
252             random = rand.nextInt(list.length);
253         _logger.fine("random ==> " + random);
254         } while (list[random] == null);
255         randomizedList[i] = list[random];
256         _logger.fine("randomisedList[" + i + "] ==> " +
257              randomizedList[i]);
258         list[random] = null;
259     }
260     return randomizedList;
261     }
262
263    /**
264     * return true of endpoints list is empty
265     */

266       public boolean isEmpty() {
267     if (endpointsList.size() == 0)
268         return true;
269     else return false;
270       }
271
272
273     /**
274      * get a new shape of the endpoints
275      * For e.g. if list contains A,B,C
276      * if the logic below chooses B as the endpoint to send the req to
277      * then return B,C,A.
278      * logic used is as described in Class description comments
279      */

280     public Object JavaDoc[] getNextRotation() {
281     int lowerLimit = 0; //lowerLimit
282
int random = 0;
283     //make sure that the random # is not 0
284
//Random API gives a number between 0 and sumOfAllWeights
285
//But our range intervals are from 1-upperLimit,
286
//11-upperLimit and so
287
//on. Hence we dont want random # to be 0.
288
while( random == 0) {
289         random = rand.nextInt(sumOfAllWeights);
290         if ( random != 0) {
291         break;
292         }
293     }
294     _logger.fine("random # = " + random +
295              " sum of all weights = " + sumOfAllWeights);
296     int i = 0;
297     for (ClusterInstanceInfo endpoint : endpointsList) {
298         int upperLimit = lowerLimit + endpoint.weight;
299         _logger.fine("upperLimit = " + upperLimit);
300         if (random > lowerLimit && random <= upperLimit) {
301         List JavaDoc<ClusterInstanceInfo> instanceInfo =
302             new LinkedList JavaDoc<ClusterInstanceInfo>();
303         
304         //add the sublist at index 0
305
instanceInfo.addAll(0,
306                     endpointsList.subList(i,
307                               endpointsList.size()));
308         //add the remaining list
309
instanceInfo.addAll(endpointsList.subList(0, i));
310         
311         //print the contents...
312
_logger.fine("returning the following list..." +
313                  instanceInfo.toString());
314         
315         return convertIntoCorbaloc(instanceInfo);
316         }
317         lowerLimit = upperLimit;
318         _logger.fine("lowerLimit = " + lowerLimit);
319         i++;
320     }
321     _logger.warning("Could not find an endpoint to send request to!");
322     return null;
323     }
324     
325     private Object JavaDoc[] convertIntoCorbaloc(List JavaDoc<ClusterInstanceInfo> list) {
326     List JavaDoc host_port = new LinkedList JavaDoc();
327     for (ClusterInstanceInfo endpoint : list) {
328         SocketInfo[] socketInfo = endpoint.endpoints;
329         for (int j = 0; j < socketInfo.length; j++) {
330         if (!host_port.contains(socketInfo[j].host.trim() +
331                     ":" + socketInfo[j].port)) {
332             host_port.add(socketInfo[j].host.trim() +
333                   ":" + socketInfo[j].port);
334         }
335         }
336     }
337     return host_port.toArray();
338     }
339
340
341  
342
343   /**
344    * following methods (over-loaded) for getting all IP addresses
345    * corresponding to a particular host.
346    * (multi-homed hosts).
347    */

348     private String JavaDoc [] getAddressPortList(String JavaDoc [] hostPortList) {
349         // The list is assumed to contain <HOST NAME>:<PORT> values
350
Vector JavaDoc addressPortVector = new Vector JavaDoc();
351         for (int i=0; i<hostPortList.length; i++) {
352             try {
353                 IiopUrl url = new IiopUrl("iiop://"+hostPortList[i]);
354                 String JavaDoc [] apList = getAddressPortList(url);
355                 for (int j=0; j<apList.length; j++) {
356                     addressPortVector.addElement(apList[j]);
357                 }
358             } catch (MalformedURLException JavaDoc me) {
359                 _logger.log(Level.WARNING, "bad.host.port",
360                 new Object JavaDoc[] {hostPortList[i],
361                       me.getMessage()});
362             }
363         }
364         String JavaDoc [] ret = new String JavaDoc[addressPortVector.size()];
365         for (int i=0; i<ret.length; i++) {
366             ret[i] = (String JavaDoc)addressPortVector.elementAt(i);
367         }
368         // We return a list of <IP ADDRESS>:<PORT> values
369
return ret;
370     }
371     
372     private String JavaDoc [] getAddressPortList(IiopUrl iiopUrl) {
373         // Pull out the host name and port
374
IiopUrl.Address iiopUrlAddress =
375                 (IiopUrl.Address)(iiopUrl.getAddresses().elementAt(0));
376         String JavaDoc host = iiopUrlAddress.host;
377         int portNumber = iiopUrlAddress.port;
378         String JavaDoc port = Integer.toString(portNumber);
379         // We return a list of <IP ADDRESS>:<PORT> values
380
return getAddressPortList(host, port);
381     }
382     
383     public String JavaDoc [] getAddressPortList(String JavaDoc host, String JavaDoc port) {
384         // Get the ip addresses corresponding to the host
385
try {
386             InetAddress JavaDoc [] addresses = InetAddress.getAllByName(host);
387             String JavaDoc[] ret = new String JavaDoc[addresses.length];
388             for (int i = 0; i < addresses.length; i++) {
389                 ret[i] = addresses[i].getHostAddress() + ":" + port;
390             }
391             // We return a list of <IP ADDRESS>:<PORT> values
392
return ret;
393         } catch (UnknownHostException JavaDoc ukhe) {
394             _logger.log(Level.WARNING, "unknown.host",
395             new Object JavaDoc[] {host, ukhe.getMessage()});
396             return null;
397         }
398     }
399
400   /**
401    * log list contents
402    */

403     public void print() {
404         _logger.fine("List contents ==> ");
405     int i = 0;
406     for (ClusterInstanceInfo endpoint : endpointsList) {
407         ClusterInstanceInfo instanceInfo = endpoint;
408         
409         _logger.fine("endpoint[" + i + "] ==> name =" +
410              instanceInfo.name + " weight = " +
411              instanceInfo.weight);
412         for (int j = 0; j < instanceInfo.endpoints.length; j++ ) {
413         _logger.fine("IP addresses = " +
414                  instanceInfo.endpoints[j].host + ":" +
415                  instanceInfo.endpoints[j].port +
416                  " type = " + instanceInfo.endpoints[j].type);
417         }
418         i++;
419     }
420     }
421 }
422
Popular Tags