package org.jgroups.util;
import org.jgroups.Global;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.net.DatagramSocket;
import java.net.ServerSocket;
import java.rmi.server.UID;
import java.util.StringTokenizer;
import java.util.List;
import java.util.ArrayList;
/**
* Manages resources such as multicast addresses and multicast ports, and TCP ports. This class is mainly used for
* running unit tests in parallel (TestNG) and preventing clusters intended to be separate from joining each other.
* @author Bela Ban
* @version $Id: ResourceManager.java,v 1.3 2008/04/10 10:41:41 belaban Exp $
*/
public class ResourceManager {
private static final IpAddressRep rep;
private static short mcast_port;
private static short tcp_port;
static {
String tmp_addr=System.getProperty(Global.INITIAL_MCAST_ADDR, "230.1.1.1");
mcast_port=Short.valueOf(System.getProperty(Global.INITIAL_MCAST_PORT, "7000"));
tcp_port=Short.valueOf(System.getProperty(Global.INITIAL_TCP_PORT, "10000"));
try {
InetAddress tmp=InetAddress.getByName(tmp_addr);
if(!tmp.isMulticastAddress())
throw new IllegalArgumentException("initial multicast address " + tmp_addr +
" is not a valid multicast (class D) address");
rep=new IpAddressRep(tmp_addr);
}
catch(UnknownHostException e) {
throw new RuntimeException("initial multicast address " + tmp_addr + " is incorrect", e);
}
}
private ResourceManager() {
}
/**
* Returns the next available multicast address, e.g. "228.1.2.3". This class is a JVM singleton
* @return
*/
public static String getNextMulticastAddress() {
return rep.nextAddress();
}
public static synchronized short getNextMulticastPort(InetAddress bind_addr) throws Exception {
short port=mcast_port++;
try {
DatagramSocket sock=Util.createDatagramSocket(bind_addr, port);
port=(short)sock.getLocalPort();
sock.close();
ServerSocket srv_sock=Util.createServerSocket(bind_addr, port);
port=(short)srv_sock.getLocalPort();
srv_sock.close();
return port;
}
finally {
mcast_port=(short)(port +1);
}
}
public static synchronized List<Short> getNextTcpPorts(InetAddress bind_addr, int num_requested_ports) throws Exception {
short port=tcp_port++;
List<Short> retval=new ArrayList<Short>(num_requested_ports);
for(int i=0; i < num_requested_ports; i++) {
ServerSocket sock=Util.createServerSocket(bind_addr, port);
port=(short)sock.getLocalPort();
retval.add(port);
tcp_port=++port;
sock.close();
}
return retval;
}
public static String getUniqueClusterName(String base_name) {
return base_name != null? base_name + "-" + new UID().toString() : new UID().toString();
}
public static String getUniqueClusterName() {
return getUniqueClusterName(null);
}
public static void main(String[] args) throws Exception {
List<Short> ports=getNextTcpPorts(InetAddress.getByName("192.168.1.5"), 15);
System.out.println("ports = " + ports);
ports=getNextTcpPorts(InetAddress.getByName("192.168.1.5"), 5);
System.out.println("ports = " + ports);
}
/** Representation of an IP address */
static class IpAddressRep {
short a=225, b=MIN, c=MIN, d=MIN;
private static final short MIN=1, MAX=250;
private static final char DOT='.';
IpAddressRep(String initial_addr) {
StringTokenizer tok=new StringTokenizer(initial_addr, ".", false);
a=Short.valueOf(tok.nextToken());
b=Short.valueOf(tok.nextToken());
c=Short.valueOf(tok.nextToken());
d=Short.valueOf(tok.nextToken());
}
synchronized String nextAddress() {
StringBuilder sb=new StringBuilder();
sb.append(a).append(DOT).append(b).append(DOT).append(c).append(DOT).append(d);
increment();
return sb.toString();
}
private void increment() {
d++;
if(d > MAX) {
d=MIN;
c++;
if(c > MAX) {
c=MIN;
b++;
if(b > MAX) {
b=MIN;
a++;
if(a > MAX)
a=225;
}
}
}
}
}
}