package org.jgroups.util; import org.jgroups.*; import org.jgroups.TimeoutException; import org.jgroups.auth.AuthToken; import org.jgroups.blocks.Connection; import org.jgroups.conf.ClassConfigurator; import org.jgroups.jmx.JmxConfigurator; import org.jgroups.logging.Log; import org.jgroups.protocols.*; import org.jgroups.protocols.pbcast.FLUSH; import org.jgroups.protocols.pbcast.GMS; import org.jgroups.protocols.relay.SiteMaster; import org.jgroups.protocols.relay.SiteUUID; import org.jgroups.stack.IpAddress; import org.jgroups.stack.Protocol; import org.jgroups.stack.ProtocolStack; import javax.management.MBeanServer; import javax.management.MBeanServerFactory; import java.io.*; import java.lang.annotation.Annotation; import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.*; import java.nio.ByteBuffer; import java.nio.channels.WritableByteChannel; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.text.MessageFormat; import java.text.NumberFormat; import java.util.*; import java.util.concurrent.*; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Collection of various utility routines that can not be assigned to other classes. * @author Bela Ban */ public class Util { private static NumberFormat f; private static Map<Class<? extends Object>,Byte> PRIMITIVE_TYPES=new HashMap<Class<? extends Object>,Byte>(15); private static final byte TYPE_NULL = 0; private static final byte TYPE_STREAMABLE = 1; private static final byte TYPE_SERIALIZABLE = 2; private static final byte TYPE_BOOLEAN = 10; private static final byte TYPE_BYTE = 11; private static final byte TYPE_CHAR = 12; private static final byte TYPE_DOUBLE = 13; private static final byte TYPE_FLOAT = 14; private static final byte TYPE_INT = 15; private static final byte TYPE_LONG = 16; private static final byte TYPE_SHORT = 17; private static final byte TYPE_STRING = 18; private static final byte TYPE_BYTEARRAY = 19; // constants public static final int MAX_PORT=65535; // highest port allocatable static boolean resolve_dns=false; private static short COUNTER=1; private static Pattern METHOD_NAME_TO_ATTR_NAME_PATTERN=Pattern.compile("[A-Z]+"); private static Pattern ATTR_NAME_TO_METHOD_NAME_PATTERN=Pattern.compile("_."); protected static int CCHM_INITIAL_CAPACITY=16; protected static float CCHM_LOAD_FACTOR=0.75f; protected static int CCHM_CONCURRENCY_LEVEL=16; /** The max size of an address list, e.g. used in View or Digest when toString() is called. Limiting this * reduces the amount of log data */ public static int MAX_LIST_PRINT_SIZE=20; public static enum AddressScope {GLOBAL, SITE_LOCAL, LINK_LOCAL, LOOPBACK, NON_LOOPBACK}; private static StackType ip_stack_type=_getIpStackType(); protected static ResourceBundle resource_bundle; static { resource_bundle=ResourceBundle.getBundle("jg-messages",Locale.getDefault(),Util.class.getClassLoader()); /* Trying to get value of resolve_dns. PropertyPermission not granted if * running in an untrusted environment with JNLP */ try { resolve_dns=Boolean.valueOf(System.getProperty("resolve.dns","false")); } catch (SecurityException ex){ resolve_dns=false; } f=NumberFormat.getNumberInstance(); f.setGroupingUsed(false); // f.setMinimumFractionDigits(2); f.setMaximumFractionDigits(2); PRIMITIVE_TYPES.put(Boolean.class, TYPE_BOOLEAN); PRIMITIVE_TYPES.put(Byte.class, TYPE_BYTE); PRIMITIVE_TYPES.put(Character.class, TYPE_CHAR); PRIMITIVE_TYPES.put(Double.class, TYPE_DOUBLE); PRIMITIVE_TYPES.put(Float.class, TYPE_FLOAT); PRIMITIVE_TYPES.put(Integer.class, TYPE_INT); PRIMITIVE_TYPES.put(Long.class, TYPE_LONG); PRIMITIVE_TYPES.put(Short.class, TYPE_SHORT); PRIMITIVE_TYPES.put(String.class, TYPE_STRING); PRIMITIVE_TYPES.put(byte[].class, TYPE_BYTEARRAY); if(ip_stack_type == StackType.Unknown) ip_stack_type=StackType.IPv6; try { String cchm_initial_capacity=System.getProperty(Global.CCHM_INITIAL_CAPACITY); if(cchm_initial_capacity != null) CCHM_INITIAL_CAPACITY=Integer.valueOf(cchm_initial_capacity); } catch(SecurityException ex) {} try { String cchm_load_factor=System.getProperty(Global.CCHM_LOAD_FACTOR); if(cchm_load_factor != null) CCHM_LOAD_FACTOR=Float.valueOf(cchm_load_factor); } catch(SecurityException ex) {} try { String cchm_concurrency_level=System.getProperty(Global.CCHM_CONCURRENCY_LEVEL); if(cchm_concurrency_level != null) CCHM_CONCURRENCY_LEVEL=Integer.valueOf(cchm_concurrency_level); } catch(SecurityException ex) {} try { String tmp=System.getProperty(Global.MAX_LIST_PRINT_SIZE); if(tmp != null) MAX_LIST_PRINT_SIZE=Integer.valueOf(tmp); } catch(SecurityException ex) { } } public static void assertTrue(boolean condition) { assert condition; } public static void assertTrue(String message, boolean condition) { if(message != null) assert condition : message; else assert condition; } public static void assertFalse(boolean condition) { assertFalse(null, condition); } public static void assertFalse(String message, boolean condition) { if(message != null) assert !condition : message; else assert !condition; } public static void assertEquals(String message, Object val1, Object val2) { if(message != null) { assert val1.equals(val2) : message; } else { assert val1.equals(val2); } } public static void assertEquals(Object val1, Object val2) { assertEquals(null, val1, val2); } public static void assertNotNull(String message, Object val) { if(message != null) assert val != null : message; else assert val != null; } public static void assertNotNull(Object val) { assertNotNull(null, val); } public static void assertNull(String message, Object val) { if(message != null) assert val == null : message; else assert val == null; } public static String bold(String msg) { StringBuilder sb=new StringBuilder("\033[1m"); sb.append(msg).append("\033[0m"); return sb.toString(); } public static String getMessage(String key) { return key != null? resource_bundle.getString(key) : null; } public static String getMessage(String key, Object ... args) { String msg=getMessage(key); return msg != null? MessageFormat.format(msg, args) : null; } /** * Blocks until all channels have the same view * @param timeout How long to wait (max in ms) * @param interval Check every interval ms * @param channels The channels which should form the view. The expected view size is channels.length. * Must be non-null */ public static void waitUntilAllChannelsHaveSameSize(long timeout, long interval, Channel... channels) throws TimeoutException { int size=channels.length; if(interval >= timeout || timeout <= 0) throw new IllegalArgumentException("interval needs to be smaller than timeout or timeout needs to be > 0"); long target_time=System.currentTimeMillis() + timeout; while(System.currentTimeMillis() <= target_time) { boolean all_channels_have_correct_size=true; for(Channel ch: channels) { View view=ch.getView(); if(view == null || view.size() != size) { all_channels_have_correct_size=false; break; } } if(all_channels_have_correct_size) return; Util.sleep(interval); } View[] views=new View[channels.length]; StringBuilder sb=new StringBuilder(); for(int i=0; i < channels.length; i++) { views[i]=channels[i].getView(); sb.append(channels[i].getName()).append(": ").append(views[i]).append("\n"); } for(View view: views) if(view == null || view.size() != size) throw new TimeoutException("Timeout " + timeout + " kicked in, views are:\n" + sb); } public static void addFlush(Channel ch, FLUSH flush) { if(ch == null || flush == null) throw new IllegalArgumentException("ch and flush have to be non-null"); ProtocolStack stack=ch.getProtocolStack(); stack.insertProtocolAtTop(flush); } public static void setScope(Message msg, short scope) { SCOPE.ScopeHeader hdr=SCOPE.ScopeHeader.createMessageHeader(scope); msg.putHeader(Global.SCOPE_ID, hdr); msg.setFlag(Message.SCOPED); } public static short getScope(Message msg) { SCOPE.ScopeHeader hdr=(SCOPE.ScopeHeader)msg.getHeader(Global.SCOPE_ID); return hdr != null? hdr.getScope() : 0; } public static byte[] createAuthenticationDigest(String passcode, long t1, double q1) throws IOException, NoSuchAlgorithmException { ByteArrayOutputStream baos = new ByteArrayOutputStream(128); DataOutputStream out = new DataOutputStream(baos); byte[] digest = createDigest(passcode, t1, q1); out.writeLong(t1); out.writeDouble(q1); out.writeInt(digest.length); out.write(digest); out.flush(); return baos.toByteArray(); } public static byte[] createDigest(String passcode, long t1, double q1) throws IOException, NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("SHA"); md.update(passcode.getBytes()); ByteBuffer bb = ByteBuffer.allocate(16); //8 bytes for long and double each bb.putLong(t1); bb.putDouble(q1); md.update(bb); return md.digest(); } /** * Utility method. If the dest address is IPv6, convert scoped link-local addrs into unscoped ones * @param sock * @param dest * @param sock_conn_timeout * @throws IOException */ public static void connect(Socket sock, SocketAddress dest, int sock_conn_timeout) throws IOException { if(dest instanceof InetSocketAddress) { InetAddress addr=((InetSocketAddress)dest).getAddress(); if(addr instanceof Inet6Address) { Inet6Address tmp=(Inet6Address)addr; if(tmp.getScopeId() != 0) { dest=new InetSocketAddress(InetAddress.getByAddress(tmp.getAddress()), ((InetSocketAddress)dest).getPort()); } } } sock.connect(dest, sock_conn_timeout); } public static void close(InputStream inp) { if(inp != null) try {inp.close();} catch(IOException e) {} } public static void close(OutputStream out) { if(out != null) { try {out.close();} catch(IOException e) {} } } public static void close(Socket s) { if(s != null) { try {s.close();} catch(Exception ex) {} } } public static void close(ServerSocket s) { if(s != null) { try {s.close();} catch(Exception ex) {} } } public static void close(DatagramSocket my_sock) { if(my_sock != null) { try {my_sock.close();} catch(Throwable t) {} } } public static void close(Channel ch) { if(ch != null) { try {ch.close();} catch(Throwable t) {} } } public static void close(Channel ... channels) { if(channels != null) { for(Channel ch: channels) Util.close(ch); } } public static void close(Connection conn) { if(conn != null) { try {conn.close();} catch(Throwable t) {} } } /** Drops messages to/from other members and then closes the channel. Note that this member won't get excluded from * the view until failure detection has kicked in and the new coord installed the new view */ public static void shutdown(Channel ch) throws Exception { DISCARD discard=new DISCARD(); discard.setLocalAddress(ch.getAddress()); discard.setDiscardAll(true); ProtocolStack stack=ch.getProtocolStack(); TP transport=stack.getTransport(); stack.insertProtocol(discard, ProtocolStack.ABOVE, transport.getClass()); //abruptly shutdown FD_SOCK just as in real life when member gets killed non gracefully FD_SOCK fd = (FD_SOCK) ch.getProtocolStack().findProtocol("FD_SOCK"); if(fd != null) fd.stopServerSocket(false); View view=ch.getView(); if (view != null) { ViewId vid = view.getViewId(); List<Address> members = Arrays.asList(ch.getAddress()); ViewId new_vid = new ViewId(ch.getAddress(), vid.getId() + 1); View new_view = new View(new_vid, members); // inject view in which the shut down member is the only element GMS gms = (GMS) stack.findProtocol(GMS.class); gms.installView(new_view); } Util.close(ch); } public static byte setFlag(byte bits, byte flag) { return bits |= flag; } public static boolean isFlagSet(byte bits, byte flag) { return (bits & flag) == flag; } public static byte clearFlags(byte bits, byte flag) { return bits &= ~flag; } /** * Creates an object from a byte buffer */ public static Object objectFromByteBuffer(byte[] buffer) throws Exception { if(buffer == null) return null; return objectFromByteBuffer(buffer, 0, buffer.length); } public static Object objectFromByteBuffer(byte[] buffer, int offset, int length) throws Exception { if(buffer == null) return null; Object retval=null; byte type=buffer[offset]; switch(type) { case TYPE_NULL: return null; case TYPE_STREAMABLE: ByteArrayInputStream in_stream=new ExposedByteArrayInputStream(buffer, offset+1, length-1); InputStream in=new DataInputStream(in_stream); retval=readGenericStreamable((DataInputStream)in); break; case TYPE_SERIALIZABLE: // the object is Externalizable or Serializable in_stream=new ExposedByteArrayInputStream(buffer, offset+1, length-1); in=new ObjectInputStream(in_stream); // changed Nov 29 2004 (bela) try { retval=((ObjectInputStream)in).readObject(); } finally { Util.close(in); } break; case TYPE_BOOLEAN: return ByteBuffer.wrap(buffer, offset + 1, length - 1).get() == 1; case TYPE_BYTE: return ByteBuffer.wrap(buffer, offset + 1, length - 1).get(); case TYPE_CHAR: return ByteBuffer.wrap(buffer, offset + 1, length - 1).getChar(); case TYPE_DOUBLE: return ByteBuffer.wrap(buffer, offset + 1, length - 1).getDouble(); case TYPE_FLOAT: return ByteBuffer.wrap(buffer, offset + 1, length - 1).getFloat(); case TYPE_INT: return ByteBuffer.wrap(buffer, offset + 1, length - 1).getInt(); case TYPE_LONG: return ByteBuffer.wrap(buffer, offset + 1, length - 1).getLong(); case TYPE_SHORT: return ByteBuffer.wrap(buffer, offset + 1, length - 1).getShort(); case TYPE_STRING: byte[] tmp=new byte[length -1]; System.arraycopy(buffer, offset +1, tmp, 0, length -1); return new String(tmp); case TYPE_BYTEARRAY: tmp=new byte[length -1]; System.arraycopy(buffer, offset +1, tmp, 0, length -1); return tmp; default: throw new IllegalArgumentException("type " + type + " is invalid"); } return retval; } /** * Serializes/Streams an object into a byte buffer. * The object has to implement interface Serializable or Externalizable or Streamable. */ public static byte[] objectToByteBuffer(Object obj) throws Exception { if(obj == null) return ByteBuffer.allocate(Global.BYTE_SIZE).put(TYPE_NULL).array(); if(obj instanceof Streamable) { final ExposedByteArrayOutputStream out_stream=new ExposedByteArrayOutputStream(128); final ExposedDataOutputStream out=new ExposedDataOutputStream(out_stream); out_stream.write(TYPE_STREAMABLE); writeGenericStreamable((Streamable)obj, out); return out_stream.toByteArray(); } Byte type=PRIMITIVE_TYPES.get(obj.getClass()); if(type == null) { // will throw an exception if object is not serializable final ExposedByteArrayOutputStream out_stream=new ExposedByteArrayOutputStream(128); out_stream.write(TYPE_SERIALIZABLE); ObjectOutputStream out=new ObjectOutputStream(out_stream); out.writeObject(obj); out.close(); return out_stream.toByteArray(); } switch(type) { case TYPE_BOOLEAN: return ByteBuffer.allocate(Global.BYTE_SIZE * 2).put(TYPE_BOOLEAN) .put((Boolean)obj? (byte)1 : (byte)0).array(); case TYPE_BYTE: return ByteBuffer.allocate(Global.BYTE_SIZE *2).put(TYPE_BYTE).put((Byte)obj).array(); case TYPE_CHAR: return ByteBuffer.allocate(Global.BYTE_SIZE *3).put(TYPE_CHAR).putChar((Character)obj).array(); case TYPE_DOUBLE: return ByteBuffer.allocate(Global.BYTE_SIZE + Global.DOUBLE_SIZE).put(TYPE_DOUBLE) .putDouble((Double)obj).array(); case TYPE_FLOAT: return ByteBuffer.allocate(Global.BYTE_SIZE + Global.FLOAT_SIZE).put(TYPE_FLOAT) .putFloat((Float)obj).array(); case TYPE_INT: return ByteBuffer.allocate(Global.BYTE_SIZE + Global.INT_SIZE).put(TYPE_INT) .putInt((Integer)obj).array(); case TYPE_LONG: return ByteBuffer.allocate(Global.BYTE_SIZE + Global.LONG_SIZE).put(TYPE_LONG) .putLong((Long)obj).array(); case TYPE_SHORT: return ByteBuffer.allocate(Global.BYTE_SIZE + Global.SHORT_SIZE).put(TYPE_SHORT) .putShort((Short)obj).array(); case TYPE_STRING: String str=(String)obj; byte[] buf=new byte[str.length()]; for(int i=0; i < buf.length; i++) buf[i]=(byte)str.charAt(i); return ByteBuffer.allocate(Global.BYTE_SIZE + buf.length).put(TYPE_STRING).put(buf, 0, buf.length).array(); case TYPE_BYTEARRAY: buf=(byte[])obj; return ByteBuffer.allocate(Global.BYTE_SIZE + buf.length).put(TYPE_BYTEARRAY) .put(buf, 0, buf.length).array(); default: throw new IllegalArgumentException("type " + type + " is invalid"); } } public static void objectToStream(Object obj, DataOutput out) throws Exception { if(obj == null) { out.write(TYPE_NULL); return; } Byte type; if(obj instanceof Streamable) { // use Streamable if we can out.write(TYPE_STREAMABLE); writeGenericStreamable((Streamable)obj, out); } else if((type=PRIMITIVE_TYPES.get(obj.getClass())) != null) { out.write(type.byteValue()); switch(type.byteValue()) { case TYPE_BOOLEAN: out.writeBoolean(((Boolean)obj).booleanValue()); break; case TYPE_BYTE: out.writeByte(((Byte)obj).byteValue()); break; case TYPE_CHAR: out.writeChar(((Character)obj).charValue()); break; case TYPE_DOUBLE: out.writeDouble(((Double)obj).doubleValue()); break; case TYPE_FLOAT: out.writeFloat(((Float)obj).floatValue()); break; case TYPE_INT: out.writeInt(((Integer)obj).intValue()); break; case TYPE_LONG: out.writeLong(((Long)obj).longValue()); break; case TYPE_SHORT: out.writeShort(((Short)obj).shortValue()); break; case TYPE_STRING: String str=(String)obj; if(str.length() > Short.MAX_VALUE) { out.writeBoolean(true); ObjectOutputStream oos=new ObjectOutputStream((OutputStream)out); try { oos.writeObject(str); } finally { oos.close(); } } else { out.writeBoolean(false); out.writeUTF(str); } break; case TYPE_BYTEARRAY: byte[] buf=(byte[])obj; out.writeInt(buf.length); out.write(buf, 0, buf.length); break; default: throw new IllegalArgumentException("type " + type + " is invalid"); } } else { // will throw an exception if object is not serializable out.write(TYPE_SERIALIZABLE); ObjectOutputStream tmp=new ObjectOutputStream((OutputStream)out); tmp.writeObject(obj); } } public static Object objectFromStream(DataInput in) throws Exception { if(in == null) return null; Object retval=null; byte b=in.readByte(); switch(b) { case TYPE_NULL: return null; case TYPE_STREAMABLE: retval=readGenericStreamable(in); break; case TYPE_SERIALIZABLE: // the object is Externalizable or Serializable ObjectInputStream tmp=new ObjectInputStream((InputStream)in); retval=tmp.readObject(); break; case TYPE_BOOLEAN: retval=Boolean.valueOf(in.readBoolean()); break; case TYPE_BYTE: retval=Byte.valueOf(in.readByte()); break; case TYPE_CHAR: retval=Character.valueOf(in.readChar()); break; case TYPE_DOUBLE: retval=Double.valueOf(in.readDouble()); break; case TYPE_FLOAT: retval=Float.valueOf(in.readFloat()); break; case TYPE_INT: retval=Integer.valueOf(in.readInt()); break; case TYPE_LONG: retval=Long.valueOf(in.readLong()); break; case TYPE_SHORT: retval=Short.valueOf(in.readShort()); break; case TYPE_STRING: if(in.readBoolean()) { // large string ObjectInputStream ois=new ObjectInputStream((InputStream)in); try { retval=ois.readObject(); } finally { ois.close(); } } else { retval=in.readUTF(); } break; case TYPE_BYTEARRAY: int len=in.readInt(); byte[] tmpbuf=new byte[len]; in.readFully(tmpbuf, 0, tmpbuf.length); retval=tmpbuf; break; default: throw new IllegalArgumentException("type " + b + " is invalid"); } return retval; } public static Streamable streamableFromByteBuffer(Class<? extends Streamable> cl, byte[] buffer) throws Exception { if(buffer == null) return null; Streamable retval=null; ByteArrayInputStream in_stream=new ExposedByteArrayInputStream(buffer); DataInputStream in=new DataInputStream(in_stream); // changed Nov 29 2004 (bela) retval=cl.newInstance(); retval.readFrom(in); in.close(); return retval; } public static Streamable streamableFromByteBuffer(Class<? extends Streamable> cl, byte[] buffer, int offset, int length) throws Exception { if(buffer == null) return null; Streamable retval=null; ByteArrayInputStream in_stream=new ExposedByteArrayInputStream(buffer, offset, length); DataInputStream in=new DataInputStream(in_stream); // changed Nov 29 2004 (bela) retval=cl.newInstance(); retval.readFrom(in); in.close(); return retval; } public static byte[] streamableToByteBuffer(Streamable obj) throws Exception { byte[] result=null; final ByteArrayOutputStream out_stream=new ExposedByteArrayOutputStream(512); DataOutputStream out=new ExposedDataOutputStream(out_stream); obj.writeTo(out); result=out_stream.toByteArray(); out.close(); return result; } public static byte[] collectionToByteBuffer(Collection<Address> c) throws Exception { byte[] result=null; final ByteArrayOutputStream out_stream=new ExposedByteArrayOutputStream(512); DataOutputStream out=new ExposedDataOutputStream(out_stream); Util.writeAddresses(c, out); result=out_stream.toByteArray(); out.close(); return result; } public static void writeAuthToken(AuthToken token, DataOutput out) throws Exception{ Util.writeString(token.getName(), out); token.writeTo(out); } public static AuthToken readAuthToken(DataInput in) throws Exception { try{ String type = Util.readString(in); Object obj = Class.forName(type).newInstance(); AuthToken token = (AuthToken) obj; token.readFrom(in); return token; } catch(ClassNotFoundException cnfe) { return null; } } public static void writeView(View view, DataOutput out) throws Exception { if(view == null) { out.writeBoolean(false); return; } out.writeBoolean(true); out.writeBoolean(view instanceof MergeView); view.writeTo(out); } public static View readView(DataInput in) throws Exception { if(in.readBoolean() == false) return null; boolean isMergeView=in.readBoolean(); View view; if(isMergeView) view=new MergeView(); else view=new View(); view.readFrom(in); return view; } public static void writeViewId(ViewId vid, DataOutput out) throws Exception { if(vid == null) { out.writeBoolean(false); return; } out.writeBoolean(true); vid.writeTo(out); } public static ViewId readViewId(DataInput in) throws Exception { if(in.readBoolean() == false) return null; ViewId retval=new ViewId(); retval.readFrom(in); return retval; } public static void writeAddress(Address addr, DataOutput out) throws Exception { byte flags=0; boolean streamable_addr=true; if(addr == null) { flags=Util.setFlag(flags, Address.NULL); out.writeByte(flags); return; } if(addr instanceof UUID) { Class<? extends Address> clazz=addr.getClass(); if(clazz.equals(UUID.class)) flags=Util.setFlag(flags, Address.UUID_ADDR); else if(clazz.equals(SiteUUID.class)) flags=Util.setFlag(flags, Address.SITE_UUID); else if(clazz.equals(SiteMaster.class)) flags=Util.setFlag(flags,Address.SITE_MASTER); else streamable_addr=false; } else if(addr instanceof IpAddress) flags=Util.setFlag(flags, Address.IP_ADDR); else streamable_addr=false; out.writeByte(flags); if(streamable_addr) addr.writeTo(out); else writeOtherAddress(addr, out); } public static Address readAddress(DataInput in) throws Exception { byte flags=in.readByte(); if(Util.isFlagSet(flags, Address.NULL)) return null; Address addr; if(Util.isFlagSet(flags, Address.UUID_ADDR)) { addr=new UUID(); addr.readFrom(in); } else if(Util.isFlagSet(flags, Address.SITE_UUID)) { addr=new SiteUUID(); addr.readFrom(in); } else if(Util.isFlagSet(flags, Address.SITE_MASTER)) { addr=new SiteMaster(); addr.readFrom(in); } else if(Util.isFlagSet(flags, Address.IP_ADDR)) { addr=new IpAddress(); addr.readFrom(in); } else { addr=readOtherAddress(in); } return addr; } public static int size(Address addr) { int retval=Global.BYTE_SIZE; // flags if(addr != null) { if(addr instanceof UUID || addr instanceof IpAddress) retval+=addr.size(); else { retval+=Global.SHORT_SIZE; // magic number retval+=addr.size(); } } return retval; } public static int size(View view) { int retval=Global.BYTE_SIZE; // presence if(view != null) retval+=view.serializedSize() + Global.BYTE_SIZE; // merge view or regular view return retval; } public static int size(ViewId vid) { int retval=Global.BYTE_SIZE; // presence if(vid != null) retval+=vid.serializedSize(); return retval; } public static int size(String s) { int retval=Global.BYTE_SIZE; if(s != null) retval+=s.length() +2; return retval; } public static int size(byte[] buf) { int retval=Global.BYTE_SIZE + Global.INT_SIZE; if(buf != null) retval+=buf.length; return retval; } private static Address readOtherAddress(DataInput in) throws Exception { short magic_number=in.readShort(); Class<Address> cl=ClassConfigurator.get(magic_number); if(cl == null) throw new RuntimeException("class for magic number " + magic_number + " not found"); Address addr=cl.newInstance(); addr.readFrom(in); return addr; } private static void writeOtherAddress(Address addr, DataOutput out) throws Exception { short magic_number=ClassConfigurator.getMagicNumber(addr.getClass()); // write the class info if(magic_number == -1) throw new RuntimeException("magic number " + magic_number + " not found"); out.writeShort(magic_number); addr.writeTo(out); } /** * Writes a Vector of Addresses. Can contain 65K addresses at most * * @param v A Collection<Address> * @param out * @throws Exception */ public static void writeAddresses(Collection<? extends Address> v, DataOutput out) throws Exception { if(v == null) { out.writeShort(-1); return; } out.writeShort(v.size()); for(Address addr: v) { Util.writeAddress(addr, out); } } /** * * * @param in * @param cl The type of Collection, e.g. ArrayList.class * @return Collection of Address objects * @throws Exception */ public static Collection<? extends Address> readAddresses(DataInput in, Class cl) throws Exception { short length=in.readShort(); if(length < 0) return null; Collection<Address> retval=(Collection<Address>)cl.newInstance(); Address addr; for(int i=0; i < length; i++) { addr=Util.readAddress(in); retval.add(addr); } return retval; } /** * Returns the marshalled size of a Collection of Addresses. * <em>Assumes elements are of the same type !</em> * @param addrs Collection<Address> * @return long size */ public static long size(Collection<? extends Address> addrs) { int retval=Global.SHORT_SIZE; // number of elements if(addrs != null && !addrs.isEmpty()) { Address addr=addrs.iterator().next(); retval+=size(addr) * addrs.size(); } return retval; } public static void writeStreamable(Streamable obj, DataOutput out) throws Exception { if(obj == null) { out.writeBoolean(false); return; } out.writeBoolean(true); obj.writeTo(out); } public static Streamable readStreamable(Class clazz, DataInput in) throws Exception { Streamable retval=null; if(in.readBoolean() == false) return null; retval=(Streamable)clazz.newInstance(); retval.readFrom(in); return retval; } public static void writeGenericStreamable(Streamable obj, DataOutput out) throws Exception { short magic_number; String classname; if(obj == null) { out.write(0); return; } out.write(1); magic_number=ClassConfigurator.getMagicNumber(obj.getClass()); // write the magic number or the class name if(magic_number == -1) { out.writeBoolean(false); classname=obj.getClass().getName(); out.writeUTF(classname); } else { out.writeBoolean(true); out.writeShort(magic_number); } // write the contents obj.writeTo(out); } public static Streamable readGenericStreamable(DataInput in) throws Exception { Streamable retval=null; int b=in.readByte(); if(b == 0) return null; boolean use_magic_number=in.readBoolean(); String classname; Class clazz; if(use_magic_number) { short magic_number=in.readShort(); clazz=ClassConfigurator.get(magic_number); if (clazz==null) throw new ClassNotFoundException("Class for magic number "+magic_number+" cannot be found."); } else { classname=in.readUTF(); clazz=ClassConfigurator.get(classname); if (clazz==null) throw new ClassNotFoundException(classname); } retval=(Streamable)clazz.newInstance(); retval.readFrom(in); return retval; } public static void writeClass(Class<?> classObject, DataOutput out) throws Exception { short magic_number=ClassConfigurator.getMagicNumber(classObject); // write the magic number or the class name if(magic_number == -1) { out.writeBoolean(false); out.writeUTF(classObject.getName()); } else { out.writeBoolean(true); out.writeShort(magic_number); } } public static Class<?> readClass(DataInput in) throws Exception { Class<?> clazz; boolean use_magic_number = in.readBoolean(); if(use_magic_number) { short magic_number=in.readShort(); clazz=ClassConfigurator.get(magic_number); if(clazz == null) throw new ClassNotFoundException("Class for magic number "+magic_number+" cannot be found."); } else { String classname=in.readUTF(); clazz=ClassConfigurator.get(classname); if(clazz == null) throw new ClassNotFoundException(classname); } return clazz; } public static void writeObject(Object obj, DataOutput out) throws Exception { if(obj instanceof Streamable) { out.writeInt(-1); writeGenericStreamable((Streamable)obj, out); } else { byte[] buf=objectToByteBuffer(obj); out.writeInt(buf.length); out.write(buf, 0, buf.length); } } public static Object readObject(DataInput in) throws Exception { int len=in.readInt(); if(len == -1) return readGenericStreamable(in); byte[] buf=new byte[len]; in.readFully(buf, 0, len); return objectFromByteBuffer(buf); } public static void writeString(String s, DataOutput out) throws Exception { if(s != null) { out.write(1); out.writeUTF(s); } else { out.write(0); } } public static String readString(DataInput in) throws Exception { int b=in.readByte(); if(b == 1) return in.readUTF(); return null; } public static String readFile(String filename) throws FileNotFoundException { FileInputStream in=new FileInputStream(filename); return readContents(in); } public static String readContents(InputStream input) { StringBuilder sb=new StringBuilder(); int ch; while(true) { try { ch=input.read(); if(ch != -1) sb.append((char)ch); else break; } catch(IOException e) { break; } } return sb.toString(); } public static byte[] readFileContents(String filename) throws IOException { File file=new File(filename); if(!file.exists()) throw new FileNotFoundException(filename); long length=file.length(); byte contents[]=new byte[(int)length]; InputStream in=new BufferedInputStream(new FileInputStream(filename)); int bytes_read=0; for(;;) { int tmp=in.read(contents, bytes_read, (int)(length - bytes_read)); if(tmp == -1) break; bytes_read+=tmp; if(bytes_read == length) break; } return contents; } public static byte[] readFileContents(InputStream input) throws IOException { byte contents[]=new byte[10000], buf[]=new byte[1024]; InputStream in=new BufferedInputStream(input); int bytes_read=0; for(;;) { int tmp=in.read(buf, 0, buf.length); if(tmp == -1) break; System.arraycopy(buf, 0, contents, bytes_read, tmp); bytes_read+=tmp; } byte[] retval=new byte[bytes_read]; System.arraycopy(contents, 0, retval, 0, bytes_read); return retval; } public static String parseString(DataInput in) { StringBuilder sb=new StringBuilder(); int ch; // read white space while(true) { try { ch=in.readByte(); if(ch == -1) { return null; // eof } if(Character.isWhitespace(ch)) { if(ch == '\n') return null; } else { sb.append((char)ch); break; } } catch(EOFException eof) { return null; } catch(IOException e) { break; } } while(true) { try { ch=in.readByte(); if(ch == -1) break; if(Character.isWhitespace(ch)) break; else { sb.append((char)ch); } } catch(IOException e) { break; } } return sb.toString(); } public static String readStringFromStdin(String message) throws Exception { System.out.print(message); System.out.flush(); System.in.skip(System.in.available()); BufferedReader reader=new BufferedReader(new InputStreamReader(System.in)); return reader.readLine().trim(); } public static long readLongFromStdin(String message) throws Exception { String tmp=readStringFromStdin(message); return Long.parseLong(tmp); } public static double readDoubleFromStdin(String message) throws Exception { String tmp=readStringFromStdin(message); return Double.parseDouble(tmp); } public static int readIntFromStdin(String message) throws Exception { String tmp=readStringFromStdin(message); return Integer.parseInt(tmp); } public static void writeByteBuffer(byte[] buf, DataOutput out) throws Exception { writeByteBuffer(buf, 0, buf.length, out); } public static void writeByteBuffer(byte[] buf, int offset, int length, DataOutput out) throws Exception { if(buf != null) { out.write(1); out.writeInt(length); out.write(buf, offset, length); } else { out.write(0); } } public static byte[] readByteBuffer(DataInput in) throws Exception { int b=in.readByte(); if(b == 1) { b=in.readInt(); byte[] buf=new byte[b]; in.readFully(buf, 0, buf.length); return buf; } return null; } public static Buffer messageToByteBuffer(Message msg) throws Exception { ExposedByteArrayOutputStream output=new ExposedByteArrayOutputStream(512); DataOutputStream out=new ExposedDataOutputStream(output); out.writeBoolean(msg != null); if(msg != null) msg.writeTo(out); out.flush(); Buffer retval=new Buffer(output.getRawBuffer(), 0, output.size()); out.close(); output.close(); return retval; } public static Message byteBufferToMessage(byte[] buffer, int offset, int length) throws Exception { ByteArrayInputStream input=new ExposedByteArrayInputStream(buffer, offset, length); DataInputStream in=new DataInputStream(input); if(!in.readBoolean()) return null; Message msg=new Message(false); // don't create headers, readFrom() will do this msg.readFrom(in); return msg; } /** * Marshalls a list of messages. * @param xmit_list LinkedList<Message> * @return Buffer * @throws Exception */ public static Buffer msgListToByteBuffer(List<Message> xmit_list) throws Exception { ExposedByteArrayOutputStream output=new ExposedByteArrayOutputStream(512); DataOutputStream out=new ExposedDataOutputStream(output); Buffer retval=null; out.writeInt(xmit_list.size()); for(Message msg: xmit_list) { msg.writeTo(out); } out.flush(); retval=new Buffer(output.getRawBuffer(), 0, output.size()); out.close(); output.close(); return retval; } public static boolean match(Object obj1, Object obj2) { if(obj1 == null && obj2 == null) return true; if(obj1 != null) return obj1.equals(obj2); else return obj2.equals(obj1); } public static boolean match(long[] a1, long[] a2) { if(a1 == null && a2 == null) return true; if(a1 == null || a2 == null) return false; if(a1.hashCode() == a2.hashCode()) // identity return true; // at this point, a1 != null and a2 != null if(a1.length != a2.length) return false; for(int i=0; i < a1.length; i++) { if(a1[i] != a2[i]) return false; } return true; } /** Sleep for timeout msecs. Returns when timeout has elapsed or thread was interrupted */ public static void sleep(long timeout) { try { Thread.sleep(timeout); } catch(InterruptedException e) { Thread.currentThread().interrupt(); } } public static void sleep(long timeout, int nanos) { try { Thread.sleep(timeout,nanos); } catch(InterruptedException e) { Thread.currentThread().interrupt(); } } /** * On most UNIX systems, the minimum sleep time is 10-20ms. Even if we specify sleep(1), the thread will * sleep for at least 10-20ms. On Windows, sleep() seems to be implemented as a busy sleep, that is the * thread never relinquishes control and therefore the sleep(x) is exactly x ms long. */ public static void sleep(long msecs, boolean busy_sleep) { if(!busy_sleep) { sleep(msecs); return; } long start=System.currentTimeMillis(); long stop=start + msecs; while(stop > start) { start=System.currentTimeMillis(); } } public static int keyPress(String msg) { System.out.println(msg); try { int ret=System.in.read(); System.in.skip(System.in.available()); return ret; } catch(IOException e) { return 0; } } /** Returns a random value in the range [1 - range] */ public static long random(long range) { return (long)((Math.random() * range) % range) + 1; } /** Sleeps between floor and ceiling milliseconds, chosen randomly */ public static void sleepRandom(long floor, long ceiling) { if(ceiling - floor<= 0) { return; } long diff = ceiling - floor; long r=(int)((Math.random() * 100000) % diff) + floor; sleep(r); } /** Tosses a coin weighted with probability and returns true or false. Example: if probability=0.8, chances are that in 80% of all cases, true will be returned and false in 20%. */ public static boolean tossWeightedCoin(double probability) { long r=random(100); long cutoff=(long)(probability * 100); return r < cutoff; } public static String dumpThreads() { StringBuilder sb=new StringBuilder(); ThreadMXBean bean=ManagementFactory.getThreadMXBean(); long[] ids=bean.getAllThreadIds(); _printThreads(bean, ids, sb); long[] deadlocks=bean.findDeadlockedThreads(); if(deadlocks != null && deadlocks.length > 0) { sb.append("deadlocked threads:\n"); _printThreads(bean, deadlocks, sb); } deadlocks=bean.findMonitorDeadlockedThreads(); if(deadlocks != null && deadlocks.length > 0) { sb.append("monitor deadlocked threads:\n"); _printThreads(bean, deadlocks, sb); } return sb.toString(); } protected static void _printThreads(ThreadMXBean bean, long[] ids, StringBuilder sb) { ThreadInfo[] threads=bean.getThreadInfo(ids, 20); for(int i=0; i < threads.length; i++) { ThreadInfo info=threads[i]; if(info == null) continue; sb.append(info.getThreadName()).append(":\n"); StackTraceElement[] stack_trace=info.getStackTrace(); for(int j=0; j < stack_trace.length; j++) { StackTraceElement el=stack_trace[j]; sb.append(" at ").append(el.getClassName()).append(".").append(el.getMethodName()); sb.append("(").append(el.getFileName()).append(":").append(el.getLineNumber()).append(")"); sb.append("\n"); } sb.append("\n\n"); } } public static boolean interruptAndWaitToDie(Thread t) { return interruptAndWaitToDie(t, Global.THREAD_SHUTDOWN_WAIT_TIME); } public static boolean interruptAndWaitToDie(Thread t, long timeout) { if(t == null) throw new IllegalArgumentException("Thread can not be null"); t.interrupt(); // interrupts the sleep() try { t.join(timeout); } catch(InterruptedException e){ Thread.currentThread().interrupt(); // set interrupt flag again } return t.isAlive(); } /** * Debugging method used to dump the content of a protocol queue in a * condensed form. Useful to follow the evolution of the queue's content in * time. */ public static String dumpQueue(Queue q) { StringBuilder sb=new StringBuilder(); LinkedList values=q.values(); if(values.isEmpty()) { sb.append("empty"); } else { for(Object o: values) { String s=null; if(o instanceof Event) { Event event=(Event)o; int type=event.getType(); s=Event.type2String(type); if(type == Event.VIEW_CHANGE) s+=" " + event.getArg(); if(type == Event.MSG) s+=" " + event.getArg(); if(type == Event.MSG) { s+="["; Message m=(Message)event.getArg(); Map<Short,Header> headers=new HashMap<Short,Header>(m.getHeaders()); for(Map.Entry<Short,Header> entry: headers.entrySet()) { short id=entry.getKey(); Header value=entry.getValue(); String headerToString=null; if(value instanceof FD.FdHeader) { headerToString=value.toString(); } else if(value instanceof PingHeader) { headerToString=ClassConfigurator.getProtocol(id) + "-"; if(((PingHeader)value).type == PingHeader.GET_MBRS_REQ) { headerToString+="GMREQ"; } else if(((PingHeader)value).type == PingHeader.GET_MBRS_RSP) { headerToString+="GMRSP"; } else { headerToString+="UNKNOWN"; } } else { headerToString=ClassConfigurator.getProtocol(id) + "-" + (value == null ? "null" : value.toString()); } s+=headerToString; s+=" "; } s+="]"; } } else { s=o.toString(); } sb.append(s).append("\n"); } } return sb.toString(); } /** * Use with caution: lots of overhead */ public static String printStackTrace(Throwable t) { StringWriter s=new StringWriter(); PrintWriter p=new PrintWriter(s); t.printStackTrace(p); return s.toString(); } public static String getStackTrace(Throwable t) { return printStackTrace(t); } public static String print(Throwable t) { return printStackTrace(t); } public static void crash() { System.exit(-1); } public static String printEvent(Event evt) { Message msg; if(evt.getType() == Event.MSG) { msg=(Message)evt.getArg(); if(msg != null) { if(msg.getLength() > 0) return printMessage(msg); else return msg.printObjectHeaders(); } } return evt.toString(); } /** Tries to read an object from the message's buffer and prints it */ public static String printMessage(Message msg) { if(msg == null) return ""; if(msg.getLength() == 0) return null; try { return msg.getObject().toString(); } catch(Exception e) { // it is not an object return ""; } } public static String mapToString(Map<? extends Object,? extends Object> map) { if(map == null) return "null"; StringBuilder sb=new StringBuilder(); for(Map.Entry<? extends Object,? extends Object> entry: map.entrySet()) { Object key=entry.getKey(); Object val=entry.getValue(); sb.append(key).append("="); if(val == null) sb.append("null"); else sb.append(val); sb.append("\n"); } return sb.toString(); } public static void printThreads() { Thread threads[]=new Thread[Thread.activeCount()]; Thread.enumerate(threads); System.out.println("------- Threads -------"); for(int i=0; i < threads.length; i++) { System.out.println("#" + i + ": " + threads[i]); } System.out.println("------- Threads -------\n"); } public static String activeThreads() { StringBuilder sb=new StringBuilder(); Thread threads[]=new Thread[Thread.activeCount()]; Thread.enumerate(threads); sb.append("------- Threads -------\n"); for(int i=0; i < threads.length; i++) { sb.append("#").append(i).append(": ").append(threads[i]).append('\n'); } sb.append("------- Threads -------\n"); return sb.toString(); } /** * MByte nowadays doesn't mean 1024 * 1024 bytes, but 1 million bytes, see http://en.wikipedia.org/wiki/Megabyte * @param bytes * @return */ public static String printBytes(long bytes) { double tmp; if(bytes < 1000) return bytes + "b"; if(bytes < 1000000) { tmp=bytes / 1000.0; return f.format(tmp) + "KB"; } if(bytes < 1000000000) { tmp=bytes / 1000000.0; return f.format(tmp) + "MB"; } else { tmp=bytes / 1000000000.0; return f.format(tmp) + "GB"; } } public static String printTime(long time, TimeUnit unit) { long ns=TimeUnit.NANOSECONDS.convert(time, unit); long us=TimeUnit.MICROSECONDS.convert(time, unit); long ms=TimeUnit.MILLISECONDS.convert(time, unit); long secs=TimeUnit.SECONDS.convert(time, unit); if(secs > 0) return secs + "s"; if(ms > 0) return ms + "ms"; if(us > 0) return us + " us"; return ns + "ns"; } public static String format(double value) { return f.format(value); } public static long readBytesLong(String input) { Tuple<String,Long> tuple=readBytes(input); double num=Double.parseDouble(tuple.getVal1()); return (long)(num * tuple.getVal2()); } public static int readBytesInteger(String input) { Tuple<String,Long> tuple=readBytes(input); double num=Double.parseDouble(tuple.getVal1()); return (int)(num * tuple.getVal2()); } public static double readBytesDouble(String input) { Tuple<String,Long> tuple=readBytes(input); double num=Double.parseDouble(tuple.getVal1()); return num * tuple.getVal2(); } private static Tuple<String,Long> readBytes(String input) { input=input.trim().toLowerCase(); int index=-1; long factor=1; if((index=input.indexOf("k")) != -1) factor=1000; else if((index=input.indexOf("kb")) != -1) factor=1000; else if((index=input.indexOf("m")) != -1) factor=1000000; else if((index=input.indexOf("mb")) != -1) factor=1000000; else if((index=input.indexOf("g")) != -1) factor=1000000000; else if((index=input.indexOf("gb")) != -1) factor=1000000000; String str=index != -1? input.substring(0, index) : input; return new Tuple<String,Long>(str, factor); } public static String printBytes(double bytes) { double tmp; if(bytes < 1000) return bytes + "b"; if(bytes < 1000000) { tmp=bytes / 1000.0; return f.format(tmp) + "KB"; } if(bytes < 1000000000) { tmp=bytes / 1000000.0; return f.format(tmp) + "MB"; } else { tmp=bytes / 1000000000.0; return f.format(tmp) + "GB"; } } public static List<String> split(String input, int separator) { List<String> retval=new ArrayList<String>(); if(input == null) return retval; int index=0, end; while(true) { index=input.indexOf(separator, index); if(index == -1) break; index++; end=input.indexOf(separator, index); if(end == -1) retval.add(input.substring(index)); else retval.add(input.substring(index, end)); } return retval; } /* public static String[] commands(String path, String separator) { if(path == null || path.length() == 0) return null; String[] tmp=path.split(separator + "+"); // multiple separators could be present if(tmp == null) return null; if(tmp.length == 0) return null; if(tmp[0].length() == 0) { tmp[0]=separator; if(tmp.length > 1) { String[] retval=new String[tmp.length -1]; retval[0]=tmp[0] + tmp[1]; System.arraycopy(tmp, 2, retval, 1, tmp.length-2); return retval; } return tmp; } return tmp; }*/ public static String[] components(String path, String separator) { if(path == null || path.length() == 0) return null; String[] tmp=path.split(separator + "+"); // multiple separators could be present if(tmp == null) return null; if(tmp.length == 0) return null; if(tmp[0].length() == 0) tmp[0]=separator; return tmp; } /** Fragments a byte buffer into smaller fragments of (max.) frag_size. Example: a byte buffer of 1024 bytes and a frag_size of 248 gives 4 fragments of 248 bytes each and 1 fragment of 32 bytes. @return An array of byte buffers (<code>byte[]</code>). */ public static byte[][] fragmentBuffer(byte[] buf, int frag_size, final int length) { byte[] retval[]; int accumulated_size=0; byte[] fragment; int tmp_size=0; int num_frags; int index=0; num_frags=length % frag_size == 0 ? length / frag_size : length / frag_size + 1; retval=new byte[num_frags][]; while(accumulated_size < length) { if(accumulated_size + frag_size <= length) tmp_size=frag_size; else tmp_size=length - accumulated_size; fragment=new byte[tmp_size]; System.arraycopy(buf, accumulated_size, fragment, 0, tmp_size); retval[index++]=fragment; accumulated_size+=tmp_size; } return retval; } public static byte[][] fragmentBuffer(byte[] buf, int frag_size) { return fragmentBuffer(buf, frag_size, buf.length); } /** * Given a buffer and a fragmentation size, compute a list of fragmentation offset/length pairs, and * return them in a list. Example:<br/> * Buffer is 10 bytes, frag_size is 4 bytes. Return value will be ({0,4}, {4,4}, {8,2}). * This is a total of 3 fragments: the first fragment starts at 0, and has a length of 4 bytes, the second fragment * starts at offset 4 and has a length of 4 bytes, and the last fragment starts at offset 8 and has a length * of 2 bytes. * @param frag_size * @return List. A List<Range> of offset/length pairs */ public static List<Range> computeFragOffsets(int offset, int length, int frag_size) { List<Range> retval=new ArrayList<Range>(); long total_size=length + offset; int index=offset; int tmp_size=0; Range r; while(index < total_size) { if(index + frag_size <= total_size) tmp_size=frag_size; else tmp_size=(int)(total_size - index); r=new Range(index, tmp_size); retval.add(r); index+=tmp_size; } return retval; } public static List<Range> computeFragOffsets(byte[] buf, int frag_size) { return computeFragOffsets(0, buf.length, frag_size); } /** Concatenates smaller fragments into entire buffers. @param fragments An array of byte buffers (<code>byte[]</code>) @return A byte buffer */ public static byte[] defragmentBuffer(byte[] fragments[]) { int total_length=0; byte[] ret; int index=0; if(fragments == null) return null; for(int i=0; i < fragments.length; i++) { if(fragments[i] == null) continue; total_length+=fragments[i].length; } ret=new byte[total_length]; for(int i=0; i < fragments.length; i++) { if(fragments[i] == null) continue; System.arraycopy(fragments[i], 0, ret, index, fragments[i].length); index+=fragments[i].length; } return ret; } public static void printFragments(byte[] frags[]) { for(int i=0; i < frags.length; i++) System.out.println('\'' + new String(frags[i]) + '\''); } public static byte[] encode(long num) { if(num == 0) return new byte[]{0}; byte bytes_needed=numberOfBytesRequiredForLong(num); byte[] buf=new byte[bytes_needed + 1]; buf[0]=bytes_needed; int index=1; for(int i=0; i < bytes_needed; i++) buf[index++]=getByteAt(num, i); return buf; } static protected byte getByteAt(long num, int index) { return (byte)((num >> (index * 8))); } public static long decode(byte[] buf) { if(buf[0] == 0) return 0; byte length=buf[0]; return makeLong(buf, 1, length); } public static void writeLong(long num, DataOutput out) throws Exception { byte[] buf=encode(num); out.write(buf, 0, buf.length); } public static long readLong(DataInput in) throws Exception { byte len=in.readByte(); if(len == 0) return 0; byte[] buf=new byte[len]; in.readFully(buf, 0, len); return makeLong(buf, 0, len); } static long makeLong(byte[] buf, int offset, int len) { long retval=0; for(int i=0; i < len; i++) { byte b=buf[offset + i]; retval |= ((long)b & 0xff) << (i * 8); } return retval; } /** * Encode the highest delivered and received seqnos. The assumption is that the latter is always >= the former, and * highest received is not much higher than highest delivered. * @param highest_delivered * @param highest_received * @return */ public static byte[] encodeLongSequence(long highest_delivered, long highest_received) { if(highest_received < highest_delivered) throw new IllegalArgumentException("highest_received (" + highest_received + ") has to be >= highest_delivered (" + highest_delivered + ")"); if(highest_delivered == 0 &&highest_received == 0) return new byte[]{0}; long delta=highest_received - highest_delivered; // encode highest_delivered followed by delta byte num_bytes_for_hd=numberOfBytesRequiredForLong(highest_delivered), num_bytes_for_delta=numberOfBytesRequiredForLong(delta); byte[] buf=new byte[num_bytes_for_hd + num_bytes_for_delta + 1]; buf[0]=encodeLength(num_bytes_for_hd, num_bytes_for_delta); int index=1; for(int i=0; i < num_bytes_for_hd; i++) buf[index++]=getByteAt(highest_delivered, i); for(int i=0; i < num_bytes_for_delta; i++) buf[index++]=getByteAt(delta, i); return buf; } private static byte numberOfBytesRequiredForLong(long number) { if(number >> 56 != 0) return 8; if(number >> 48 != 0) return 7; if(number >> 40 != 0) return 6; if(number >> 32 != 0) return 5; if(number >> 24 != 0) return 4; if(number >> 16 != 0) return 3; if(number >> 8 != 0) return 2; if(number != 0) return 1; return 1; } public static byte size(long number) { return (byte)(number == 0? 1 : numberOfBytesRequiredForLong(number) +1); } /** * Writes 2 longs, where the second long needs to be >= the first (we only write the delta !) * @param hd * @param hr * @return */ public static byte size(long hd, long hr) { if(hd == 0 && hr == 0) return 1; byte num_bytes_for_hd=numberOfBytesRequiredForLong(hd), num_bytes_for_delta=numberOfBytesRequiredForLong(hr - hd); return (byte)(num_bytes_for_hd + num_bytes_for_delta + 1); } public static long[] decodeLongSequence(byte[] buf) { if(buf[0] == 0) return new long[]{0,0}; byte[] lengths=decodeLength(buf[0]); long[] seqnos=new long[2]; seqnos[0]=makeLong(buf, 1, lengths[0]); seqnos[1]=makeLong(buf, 1 + lengths[0], lengths[1]) + seqnos[0]; return seqnos; } public static void writeLongSequence(long highest_delivered, long highest_received, DataOutput out) throws Exception { byte[] buf=encodeLongSequence(highest_delivered, highest_received); out.write(buf, 0, buf.length); } public static long[] readLongSequence(DataInput in) throws Exception { byte len=in.readByte(); if(len == 0) return new long[]{0,0}; byte[] lengths=decodeLength(len); long[] seqnos=new long[2]; byte[] buf=new byte[lengths[0] + lengths[1]]; in.readFully(buf, 0, buf.length); seqnos[0]=makeLong(buf, 0, lengths[0]); seqnos[1]=makeLong(buf, lengths[0], lengths[1]) + seqnos[0]; return seqnos; } /** * Encodes the number of bytes needed into a single byte. The first number is encoded in the first nibble (the * first 4 bits), the second number in the second nibble * @param len1 The number of bytes needed to store a long. Must be between 0 and 8 * @param len2 The number of bytes needed to store a long. Must be between 0 and 8 * @return The byte storing the 2 numbers len1 and len2 */ public static byte encodeLength(byte len1, byte len2) { byte retval=len2; retval |= (len1 << 4); return retval; } public static byte[] decodeLength(byte len) { byte[] retval={(byte)0,(byte)0}; retval[0]=(byte)((len & 0xff) >> 4); retval[1]=(byte)(len & ~0xf0); // 0xff is the first nibble set (11110000) // retval[1]=(byte)(len << 4); // retval[1]=(byte)((retval[1] & 0xff) >> 4); return retval; } public static <T> String printListWithDelimiter(Collection<T> list, String delimiter) { return printListWithDelimiter(list, delimiter, MAX_LIST_PRINT_SIZE); } public static <T> String printListWithDelimiter(Collection<T> list, String delimiter, int limit) { boolean first=true; StringBuilder sb=new StringBuilder(); int count=0, size=list.size(); for(T el: list) { if(first) { first=false; } else { sb.append(delimiter); } sb.append(el); if(limit > 0 && ++count >= limit) { if(size > count) sb.append(" ..."); break; } } return sb.toString(); } public static <T> String printMapWithDelimiter(Map<T,T> map, String delimiter) { boolean first=true; StringBuilder sb=new StringBuilder(); for(Map.Entry<T,T> entry: map.entrySet()) { if(first) first=false; else sb.append(delimiter); sb.append(entry.getKey()).append("=").append(entry.getValue()); } return sb.toString(); } public static String array2String(long[] array) { StringBuilder ret=new StringBuilder("["); if(array != null) { for(int i=0; i < array.length; i++) ret.append(array[i]).append(" "); } ret.append(']'); return ret.toString(); } public static String array2String(short[] array) { StringBuilder ret=new StringBuilder("["); if(array != null) { for(int i=0; i < array.length; i++) ret.append(array[i]).append(" "); } ret.append(']'); return ret.toString(); } public static String array2String(int[] array) { StringBuilder ret=new StringBuilder("["); if(array != null) { for(int i=0; i < array.length; i++) ret.append(array[i]).append(" "); } ret.append(']'); return ret.toString(); } public static String array2String(boolean[] array) { StringBuilder ret=new StringBuilder("["); if(array != null) { for(int i=0; i < array.length; i++) ret.append(array[i]).append(" "); } ret.append(']'); return ret.toString(); } public static String array2String(Object[] array) { return Arrays.toString(array); } /** Returns true if all elements of c match obj */ public static boolean all(Collection c, Object obj) { for(Iterator iterator=c.iterator(); iterator.hasNext();) { Object o=iterator.next(); if(!o.equals(obj)) return false; } return true; } /** * Returns a list of members which left from view one to two * @param one * @param two * @return */ public static List<Address> leftMembers(View one, View two) { if(one == null || two == null) return null; List<Address> retval=new ArrayList<Address>(one.getMembers()); retval.removeAll(two.getMembers()); return retval; } public static List<Address> leftMembers(Collection<Address> old_list, Collection<Address> new_list) { if(old_list == null || new_list == null) return null; List<Address> retval=new ArrayList<Address>(old_list); retval.removeAll(new_list); return retval; } public static List<Address> newMembers(List<Address> old_list, List<Address> new_list) { if(old_list == null || new_list == null) return null; List<Address> retval=new ArrayList<Address>(new_list); retval.removeAll(old_list); return retval; } public static <T> List<T> newElements(List<T> old_list, List<T> new_list) { if(new_list == null) return new ArrayList<T>(); List<T> retval=new ArrayList<T>(new_list); if(old_list != null) retval.removeAll(old_list); return retval; } /** * Selects a random subset of members according to subset_percentage and returns them. * Picks no member twice from the same membership. If the percentage is smaller than 1 -> picks 1 member. */ public static List<Address> pickSubset(List<Address> members, double subset_percentage) { List<Address> ret=new ArrayList<Address>(), tmp_mbrs; int num_mbrs=members.size(), subset_size, index; if(num_mbrs == 0) return ret; subset_size=(int)Math.ceil(num_mbrs * subset_percentage); tmp_mbrs=new ArrayList<Address>(members); for(int i=subset_size; i > 0 && !tmp_mbrs.isEmpty(); i--) { index=(int)((Math.random() * num_mbrs) % tmp_mbrs.size()); ret.add(tmp_mbrs.get(index)); tmp_mbrs.remove(index); } return ret; } public static boolean containsViewId(Collection<View> views, ViewId vid) { for(View view: views) { ViewId tmp=view.getVid(); if(tmp.equals(vid)) return true; } return false; } public static List<View> detectDifferentViews(Map<Address,View> map) { final List<View> ret=new ArrayList<View>(); for(View view: map.values()) { if(view == null) continue; ViewId vid=view.getVid(); if(!Util.containsViewId(ret, vid)) ret.add(view); } return ret; } /** * Determines the members which take part in a merge. The resulting list consists of all merge coordinators * plus members outside a merge partition, e.g. for views A={B,A,C}, B={B,C} and C={B,C}, the merge coordinator * is B, but the merge participants are B and A. * @param map * @return */ public static Collection<Address> determineMergeParticipants(Map<Address,View> map) { Set<Address> coords=new HashSet<Address>(); Set<Address> all_addrs=new HashSet<Address>(); if(map == null) return Collections.emptyList(); for(View view: map.values()) all_addrs.addAll(view.getMembers()); for(View view: map.values()) { Address coord=view.getCreator(); if(coord != null) coords.add(coord); } for(Address coord: coords) { View view=map.get(coord); Collection<Address> mbrs=view != null? view.getMembers() : null; if(mbrs != null) all_addrs.removeAll(mbrs); } coords.addAll(all_addrs); return coords; } /** * This is the same or a subset of {@link #determineMergeParticipants(java.util.Map)} and contains only members * which are currently sub-partition coordinators. * @param map * @return */ public static Collection<Address> determineMergeCoords(Map<Address,View> map) { Set<Address> retval=new HashSet<Address>(); if(map != null) { for(View view: map.values()) { Address coord=view.getCreator(); if(coord != null) retval.add(coord); } } return retval; } /** * Similar to {@link #determineMergeCoords(java.util.Map)} but only actual coordinators are counted: an actual * coord is when the sender of a view is the first member of that view * @param map * @return */ public static Collection<Address> determineActualMergeCoords(Map<Address,View> map) { Set<Address> retval=new HashSet<Address>(); if(map != null) { for(Map.Entry<Address,View> entry: map.entrySet()) { Address sender=entry.getKey(); List<Address> members=entry.getValue().getMembers(); Address actual_coord=members.isEmpty() ? null : members.get(0); if(sender.equals(actual_coord)) retval.add(sender); } } return retval; } /** * Returns the rank of a member in a given view * @param view The view * @param addr The address of a member * @return A value between 1 and view.size(). The first member has rank 1, the second 2 and so on. If the * member is not found, 0 is returned */ public static int getRank(View view, Address addr) { if(view == null || addr == null) return 0; List<Address> members=view.getMembers(); for(int i=0; i < members.size(); i++) { Address mbr=members.get(i); if(mbr.equals(addr)) return i+1; } return 0; } public static int getRank(Collection<Address> members, Address addr) { if(members == null || addr == null) return -1; int index=0; for(Iterator<Address> it=members.iterator(); it.hasNext();) { Address mbr=it.next(); if(mbr.equals(addr)) return index+1; index++; } return -1; } public static Object pickRandomElement(List list) { if(list == null) return null; int size=list.size(); int index=(int)((Math.random() * size * 10) % size); return list.get(index); } public static Object pickRandomElement(Object[] array) { if(array == null) return null; int size=array.length; int index=(int)((Math.random() * size * 10) % size); return array[index]; } /** * Returns the object next to element in list * @param list * @param obj * @param <T> * @return */ public static <T> T pickNext(List<T> list, T obj) { if(list == null || obj == null) return null; Object[] array=list.toArray(); for(int i=0; i < array.length; i++) { T tmp=(T)array[i]; if(tmp != null && tmp.equals(obj)) return (T)array[(i+1) % array.length]; } return null; } /** Returns the next min(N,list.size()) elements after obj */ public static <T> List<T> pickNext(List<T> list, T obj, int num) { List<T> retval=new ArrayList<T>(); if(list == null || list.size() < 2) return retval; int index=list.indexOf(obj); if(index != -1) { for(int i=1; i <= num && i < list.size(); i++) { T tmp=list.get((index +i) % list.size()); if(!retval.contains(tmp)) retval.add(tmp); } } return retval; } public static View createView(Address coord, long id, Address ... members) { List<Address> mbrs=new ArrayList<Address>(); mbrs.addAll(Arrays.asList(members)); return new View(coord, id, mbrs); } public static JChannel createChannel(Protocol... prots) throws Exception { JChannel ch=new JChannel(false); ProtocolStack stack=new ProtocolStack(); ch.setProtocolStack(stack); for(Protocol prot: prots) { stack.addProtocol(prot); prot.setProtocolStack(stack); } stack.init(); return ch; } public static Address createRandomAddress() { return createRandomAddress(generateLocalName()); } public static Address createRandomAddress(String name) { UUID retval=UUID.randomUUID(); UUID.add(retval, name); return retval; } public static Object[][] createTimer() { return new Object[][] { {new DefaultTimeScheduler(5)}, {new TimeScheduler2()}, {new HashedTimingWheel(5)} }; } /** * Returns all members that left between 2 views. All members that are element of old_mbrs but not element of * new_mbrs are returned. */ public static List<Address> determineLeftMembers(List<Address> old_mbrs, List<Address> new_mbrs) { List<Address> retval=new ArrayList<Address>(); if(old_mbrs == null || new_mbrs == null) return retval; for(int i=0; i < old_mbrs.size(); i++) { Address mbr=old_mbrs.get(i); if(!new_mbrs.contains(mbr)) retval.add(mbr); } return retval; } public static String printViews(Collection<View> views) { StringBuilder sb=new StringBuilder(); boolean first=true; for(View view: views) { if(first) first=false; else sb.append(", "); sb.append(view.getVid()); } return sb.toString(); } public static <T> String print(Collection<T> objs) { StringBuilder sb=new StringBuilder(); boolean first=true; for(T obj: objs) { if(first) first=false; else sb.append(", "); sb.append(obj); } return sb.toString(); } public static <T> String print(Map<T,T> map) { StringBuilder sb=new StringBuilder(); boolean first=true; for(Map.Entry<T,T> entry: map.entrySet()) { if(first) first=false; else sb.append(", "); sb.append(entry.getKey()).append("=").append(entry.getValue()); } return sb.toString(); } public static String printPingData(List<PingData> rsps) { StringBuilder sb=new StringBuilder(); if(rsps != null) { int total=rsps.size(); int servers=0, clients=0, coords=0; for(PingData rsp: rsps) { if(rsp.isCoord()) coords++; if(rsp.isServer()) servers++; else clients++; } sb.append(total + " total (" + servers + " servers (" + coords + " coord), " + clients + " clients)"); } return sb.toString(); } /** * if we were to register for OP_WRITE and send the remaining data on * readyOps for this channel we have to either block the caller thread or * queue the message buffers that may arrive while waiting for OP_WRITE. * Instead of the above approach this method will continuously write to the * channel until the buffer sent fully. */ public static void writeFully(ByteBuffer buf, WritableByteChannel out) throws Exception { int written = 0; int toWrite = buf.limit(); while (written < toWrite) { written += out.write(buf); } } public static long sizeOf(String classname) { Object inst; byte[] data; try { inst=Util.loadClass(classname, null).newInstance(); data=Util.objectToByteBuffer(inst); return data.length; } catch(Exception ex) { return -1; } } public static long sizeOf(Object inst) { byte[] data; try { data=Util.objectToByteBuffer(inst); return data.length; } catch(Exception ex) { return -1; } } public static int sizeOf(Streamable inst) { try { ByteArrayOutputStream output=new ExposedByteArrayOutputStream(); DataOutputStream out=new ExposedDataOutputStream(output); inst.writeTo(out); out.flush(); byte[] data=output.toByteArray(); return data.length; } catch(Exception ex) { return -1; } } /** * Tries to load the class from the current thread's context class loader. If * not successful, tries to load the class from the current instance. * @param classname Desired class. * @param clazz Class object used to obtain a class loader * if no context class loader is available. * @return Class, or null on failure. */ public static Class loadClass(String classname, Class clazz) throws ClassNotFoundException { ClassLoader loader; try { loader=Thread.currentThread().getContextClassLoader(); if(loader != null) { return loader.loadClass(classname); } } catch(Throwable t) { } if(clazz != null) { try { loader=clazz.getClassLoader(); if(loader != null) { return loader.loadClass(classname); } } catch(Throwable t) { } } try { loader=ClassLoader.getSystemClassLoader(); if(loader != null) { return loader.loadClass(classname); } } catch(Throwable t) { } throw new ClassNotFoundException(classname); } public static Field[] getAllDeclaredFields(final Class clazz) { return getAllDeclaredFieldsWithAnnotations(clazz); } public static Field[] getAllDeclaredFieldsWithAnnotations(final Class clazz, Class<? extends Annotation> ... annotations) { List<Field> list=new ArrayList<Field>(30); for(Class curr=clazz; curr != null; curr=curr.getSuperclass()) { Field[] fields=curr.getDeclaredFields(); if(fields != null) { for(Field field: fields) { if(annotations != null && annotations.length > 0) { for(Class<? extends Annotation> annotation: annotations) { if(field.isAnnotationPresent(annotation)) list.add(field); } } else list.add(field); } } } Field[] retval=new Field[list.size()]; for(int i=0; i < list.size(); i++) retval[i]=list.get(i); return retval; } public static Method[] getAllDeclaredMethods(final Class clazz) { return getAllDeclaredMethodsWithAnnotations(clazz); } public static Method[] getAllDeclaredMethodsWithAnnotations(final Class clazz, Class<? extends Annotation> ... annotations) { List<Method> list=new ArrayList<Method>(30); for(Class curr=clazz; curr != null; curr=curr.getSuperclass()) { Method[] methods=curr.getDeclaredMethods(); if(methods != null) { for(Method method: methods) { if(annotations != null && annotations.length > 0) { for(Class<? extends Annotation> annotation: annotations) { if(method.isAnnotationPresent(annotation)) list.add(method); } } else list.add(method); } } } Method[] retval=new Method[list.size()]; for(int i=0; i < list.size(); i++) retval[i]=list.get(i); return retval; } public static Field getField(final Class clazz, String field_name) { if(clazz == null || field_name == null) return null; Field field=null; for(Class curr=clazz; curr != null; curr=curr.getSuperclass()) { try { return curr.getDeclaredField(field_name); } catch(NoSuchFieldException e) { } } return field; } public static void setField(Field field, Object target, Object value) { if(!Modifier.isPublic(field.getModifiers())) { field.setAccessible(true); } try { field.set(target, value); } catch(IllegalAccessException iae) { throw new IllegalArgumentException("Could not set field " + field, iae); } } public static Object getField(Field field, Object target) { if(!Modifier.isPublic(field.getModifiers())) { field.setAccessible(true); } try { return field.get(target); } catch(IllegalAccessException iae) { throw new IllegalArgumentException("Could not get field " + field, iae); } } public static <T> Set<Class<T>> findClassesAssignableFrom(String packageName, Class<T> assignableFrom) throws IOException, ClassNotFoundException { ClassLoader loader = Thread.currentThread().getContextClassLoader(); Set<Class<T>> classes = new HashSet<Class<T>>(); String path = packageName.replace('.', '/'); URL resource = loader.getResource(path); if (resource != null) { String filePath = resource.getFile(); if (filePath != null && new File(filePath).isDirectory()) { for (String file : new File(filePath).list()) { if (file.endsWith(".class")) { String name = packageName + '.' + file.substring(0, file.indexOf(".class")); Class<T> clazz =(Class<T>)Class.forName(name); if (assignableFrom.isAssignableFrom(clazz)) classes.add(clazz); } } } } return classes; } public static List<Class<?>> findClassesAnnotatedWith(String packageName, Class<? extends Annotation> a) throws IOException, ClassNotFoundException { List<Class<?>> classes = new ArrayList<Class<?>>(); recurse(classes, packageName, a); return classes; } private static void recurse(List<Class<?>> classes, String packageName, Class<? extends Annotation> a) throws ClassNotFoundException { ClassLoader loader = Thread.currentThread().getContextClassLoader(); String path = packageName.replace('.', '/'); URL resource = loader.getResource(path); if (resource != null) { String filePath = resource.getFile(); if (filePath != null && new File(filePath).isDirectory()) { for (String file : new File(filePath).list()) { if (file.endsWith(".class")) { String name = packageName + '.' + file.substring(0, file.indexOf(".class")); Class<?> clazz = Class.forName(name); if (clazz.isAnnotationPresent(a)) classes.add(clazz); } else if (new File(filePath,file).isDirectory()) { recurse(classes, packageName + "." + file, a); } } } } } public static InputStream getResourceAsStream(String name, Class clazz) { ClassLoader loader; InputStream retval=null; try { loader=Thread.currentThread().getContextClassLoader(); if(loader != null) { retval=loader.getResourceAsStream(name); if(retval != null) return retval; } } catch(Throwable t) { } if(clazz != null) { try { loader=clazz.getClassLoader(); if(loader != null) { retval=loader.getResourceAsStream(name); if(retval != null) return retval; } } catch(Throwable t) { } } try { loader=ClassLoader.getSystemClassLoader(); if(loader != null) { return loader.getResourceAsStream(name); } } catch(Throwable t) { } return retval; } /** Checks whether 2 Addresses are on the same host */ public static boolean sameHost(Address one, Address two) { InetAddress a, b; String host_a, host_b; if(one == null || two == null) return false; if(!(one instanceof IpAddress) || !(two instanceof IpAddress)) { return false; } a=((IpAddress)one).getIpAddress(); b=((IpAddress)two).getIpAddress(); if(a == null || b == null) return false; host_a=a.getHostAddress(); host_b=b.getHostAddress(); // System.out.println("host_a=" + host_a + ", host_b=" + host_b); return host_a.equals(host_b); } public static boolean fileExists(String fname) { return (new File(fname)).exists(); } public static void verifyRejectionPolicy(String str) throws Exception{ if(!(str.equalsIgnoreCase("run") || str.equalsIgnoreCase("abort")|| str.equalsIgnoreCase("discard")|| str.equalsIgnoreCase("discardoldest"))) { throw new Exception("Unknown rejection policy " + str); } } public static RejectedExecutionHandler parseRejectionPolicy(String rejection_policy) { if(rejection_policy == null) throw new IllegalArgumentException("rejection policy is null"); if(rejection_policy.equalsIgnoreCase("abort")) return new ThreadPoolExecutor.AbortPolicy(); if(rejection_policy.equalsIgnoreCase("discard")) return new ThreadPoolExecutor.DiscardPolicy(); if(rejection_policy.equalsIgnoreCase("discardoldest")) return new ThreadPoolExecutor.DiscardOldestPolicy(); if(rejection_policy.equalsIgnoreCase("run")) return new ThreadPoolExecutor.CallerRunsPolicy(); throw new IllegalArgumentException("rejection policy \"" + rejection_policy + "\" not known"); } /** * Parses comma-delimited longs; e.g., 2000,4000,8000. * Returns array of long, or null. */ public static int[] parseCommaDelimitedInts(String s) { StringTokenizer tok; List<Integer> v=new ArrayList<Integer>(); Integer l; int[] retval=null; if(s == null) return null; tok=new StringTokenizer(s, ","); while(tok.hasMoreTokens()) { l=new Integer(tok.nextToken()); v.add(l); } if(v.isEmpty()) return null; retval=new int[v.size()]; for(int i=0; i < v.size(); i++) retval[i]=v.get(i).intValue(); return retval; } /** * Parses comma-delimited longs; e.g., 2000,4000,8000. * Returns array of long, or null. */ public static long[] parseCommaDelimitedLongs(String s) { StringTokenizer tok; List<Long> v=new ArrayList<Long>(); Long l; long[] retval=null; if(s == null) return null; tok=new StringTokenizer(s, ","); while(tok.hasMoreTokens()) { l=new Long(tok.nextToken()); v.add(l); } if(v.isEmpty()) return null; retval=new long[v.size()]; for(int i=0; i < v.size(); i++) retval[i]=v.get(i).longValue(); return retval; } /** e.g. "bela,jeannette,michelle" --> List{"bela", "jeannette", "michelle"} */ public static List<String> parseCommaDelimitedStrings(String l) { return parseStringList(l, ","); } /** * Input is "daddy[8880],sindhu[8880],camille[5555]. Returns a list of IpAddresses */ public static List<IpAddress> parseCommaDelimitedHosts(String hosts, int port_range) throws UnknownHostException { StringTokenizer tok=new StringTokenizer(hosts, ","); String t; IpAddress addr; Set<IpAddress> retval=new HashSet<IpAddress>(); while(tok.hasMoreTokens()) { t=tok.nextToken().trim(); String host=t.substring(0, t.indexOf('[')); host=host.trim(); int port=Integer.parseInt(t.substring(t.indexOf('[') + 1, t.indexOf(']'))); for(int i=port;i <= port + port_range;i++) { addr=new IpAddress(host, i); retval.add(addr); } } return new LinkedList<IpAddress>(retval); } /** * Input is "daddy[8880],sindhu[8880],camille[5555]. Return List of * InetSocketAddress */ public static List<InetSocketAddress> parseCommaDelimitedHosts2(String hosts, int port_range) { StringTokenizer tok=new StringTokenizer(hosts, ","); String t; InetSocketAddress addr; Set<InetSocketAddress> retval=new HashSet<InetSocketAddress>(); while(tok.hasMoreTokens()) { t=tok.nextToken().trim(); String host=t.substring(0, t.indexOf('[')); host=host.trim(); int port=Integer.parseInt(t.substring(t.indexOf('[') + 1, t.indexOf(']'))); for(int i=port;i < port + port_range;i++) { addr=new InetSocketAddress(host, i); retval.add(addr); } } return new LinkedList<InetSocketAddress>(retval); } public static List<String> parseStringList(String l, String separator) { List<String> tmp=new LinkedList<String>(); StringTokenizer tok=new StringTokenizer(l, separator); String t; while(tok.hasMoreTokens()) { t=tok.nextToken(); tmp.add(t.trim()); } return tmp; } public static String parseString(ByteBuffer buf) { return parseString(buf, true); } public static String parseString(ByteBuffer buf, boolean discard_whitespace) { StringBuilder sb=new StringBuilder(); char ch; // read white space while(buf.remaining() > 0) { ch=(char)buf.get(); if(!Character.isWhitespace(ch)) { buf.position(buf.position() -1); break; } } if(buf.remaining() == 0) return null; while(buf.remaining() > 0) { ch=(char)buf.get(); if(!Character.isWhitespace(ch)) { sb.append(ch); } else break; } // read white space if(discard_whitespace) { while(buf.remaining() > 0) { ch=(char)buf.get(); if(!Character.isWhitespace(ch)) { buf.position(buf.position() -1); break; } } } return sb.toString(); } public static int readNewLine(ByteBuffer buf) { char ch; int num=0; while(buf.remaining() > 0) { ch=(char)buf.get(); num++; if(ch == '\n') break; } return num; } /** * Reads and discards all characters from the input stream until a \r\n or EOF is encountered * @param in * @return */ public static int discardUntilNewLine(InputStream in) { int ch; int num=0; while(true) { try { ch=in.read(); if(ch == -1) break; num++; if(ch == '\n') break; } catch(IOException e) { break; } } return num; } /** * Reads a line of text. A line is considered to be terminated by any one * of a line feed ('\n'), a carriage return ('\r'), or a carriage return * followed immediately by a linefeed. * * @return A String containing the contents of the line, not including * any line-termination characters, or null if the end of the * stream has been reached * * @exception IOException If an I/O error occurs */ public static String readLine(InputStream in) throws IOException { StringBuilder sb=new StringBuilder(35); int ch; while(true) { ch=in.read(); if(ch == -1) return null; if(ch == '\r') { ; } else { if(ch == '\n') break; else { sb.append((char)ch); } } } return sb.toString(); } public static void writeString(ByteBuffer buf, String s) { for(int i=0; i < s.length(); i++) buf.put((byte)s.charAt(i)); } /** * * @param s * @return List<NetworkInterface> */ public static List<NetworkInterface> parseInterfaceList(String s) throws Exception { List<NetworkInterface> interfaces=new ArrayList<NetworkInterface>(10); if(s == null) return null; StringTokenizer tok=new StringTokenizer(s, ","); String interface_name; NetworkInterface intf; while(tok.hasMoreTokens()) { interface_name=tok.nextToken(); // try by name first (e.g. (eth0") intf=NetworkInterface.getByName(interface_name); // next try by IP address or symbolic name if(intf == null) intf=NetworkInterface.getByInetAddress(InetAddress.getByName(interface_name)); if(intf == null) throw new Exception("interface " + interface_name + " not found"); if(!interfaces.contains(intf)) { interfaces.add(intf); } } return interfaces; } public static String print(List<NetworkInterface> interfaces) { StringBuilder sb=new StringBuilder(); boolean first=true; for(NetworkInterface intf: interfaces) { if(first) { first=false; } else { sb.append(", "); } sb.append(intf.getName()); } return sb.toString(); } public static String shortName(String hostname) { if(hostname == null) return null; int index=hostname.indexOf('.'); if(index > 0 && !Character.isDigit(hostname.charAt(0))) return hostname.substring(0, index); else return hostname; } public static boolean startFlush(Channel c, List<Address> flushParticipants, int numberOfAttempts, long randomSleepTimeoutFloor, long randomSleepTimeoutCeiling) { int attemptCount = 0; while (attemptCount < numberOfAttempts) { try { c.startFlush(flushParticipants, false); return true; } catch (Exception e) { Util.sleepRandom(randomSleepTimeoutFloor, randomSleepTimeoutCeiling); attemptCount++; } } return false; } public static boolean startFlush(Channel c, List<Address> flushParticipants) { return startFlush(c,flushParticipants,4,1000,5000); } public static boolean startFlush(Channel c, int numberOfAttempts, long randomSleepTimeoutFloor,long randomSleepTimeoutCeiling) { int attemptCount = 0; while(attemptCount < numberOfAttempts){ try{ c.startFlush(false); return true; } catch(Exception e) { Util.sleepRandom(randomSleepTimeoutFloor,randomSleepTimeoutCeiling); attemptCount++; } } return false; } public static boolean startFlush(Channel c) { return startFlush(c,4,1000,5000); } public static String shortName(InetAddress hostname) { if(hostname == null) return null; StringBuilder sb=new StringBuilder(); if(resolve_dns) sb.append(hostname.getHostName()); else sb.append(hostname.getHostAddress()); return sb.toString(); } public static String generateLocalName() { String retval=null; try { retval=shortName(InetAddress.getLocalHost().getHostName()); } catch(Throwable e) { } if(retval == null) { try { retval=shortName(InetAddress.getByName(null).getHostName()); } catch(Throwable e) { retval="localhost"; } } long counter=Util.random(Short.MAX_VALUE *2); return retval + "-" + counter; } public synchronized static short incrCounter() { short retval=COUNTER++; if(COUNTER >= Short.MAX_VALUE) COUNTER=1; return retval; } public static <K,V> ConcurrentMap<K,V> createConcurrentMap(int initial_capacity, float load_factor, int concurrency_level) { return new ConcurrentHashMap<K,V>(initial_capacity, load_factor, concurrency_level); } public static <K,V> ConcurrentMap<K,V> createConcurrentMap(int initial_capacity) { return new ConcurrentHashMap<K,V>(initial_capacity); } public static <K,V> ConcurrentMap<K,V> createConcurrentMap() { return new ConcurrentHashMap<K,V>(CCHM_INITIAL_CAPACITY, CCHM_LOAD_FACTOR, CCHM_CONCURRENCY_LEVEL); } public static <K,V> Map<K,V> createHashMap() { return new HashMap<K,V>(CCHM_INITIAL_CAPACITY, CCHM_LOAD_FACTOR); } public static ServerSocket createServerSocket(SocketFactory factory, String service_name, InetAddress bind_addr, int start_port) { ServerSocket ret=null; while(true) { try { ret=factory.createServerSocket(service_name, start_port, 50, bind_addr); } catch(BindException bind_ex) { start_port++; continue; } catch(IOException io_ex) { } break; } return ret; } /** * Finds first available port starting at start_port and returns server * socket. Will not bind to port >end_port. Sets srv_port */ public static ServerSocket createServerSocket(SocketFactory factory, String service_name, InetAddress bind_addr, int start_port, int end_port) throws Exception { ServerSocket ret=null; int original_start_port=start_port; while(true) { try { if(bind_addr == null) ret=factory.createServerSocket(service_name, start_port); else { // changed (bela Sept 7 2007): we accept connections on all NICs ret=factory.createServerSocket(service_name, start_port, 50, bind_addr); } } catch(SocketException bind_ex) { if(start_port == end_port) throw new BindException("No available port to bind to in range [" + original_start_port + " .. " + end_port + "]"); if(bind_addr != null && !bind_addr.isLoopbackAddress()) { NetworkInterface nic=NetworkInterface.getByInetAddress(bind_addr); if(nic == null) throw new BindException("bind_addr " + bind_addr + " is not a valid interface: " + bind_ex); } start_port++; continue; } break; } return ret; } /** * Creates a DatagramSocket bound to addr. If addr is null, socket won't be bound. If address is already in use, * start_port will be incremented until a socket can be created. * @param addr The InetAddress to which the socket should be bound. If null, the socket will not be bound. * @param port The port which the socket should use. If 0, a random port will be used. If > 0, but port is already * in use, it will be incremented until an unused port is found, or until MAX_PORT is reached. */ public static DatagramSocket createDatagramSocket(SocketFactory factory, String service_name, InetAddress addr, int port) throws Exception { DatagramSocket sock=null; if(addr == null) { if(port == 0) { return factory.createDatagramSocket(service_name); } else { while(port < MAX_PORT) { try { return factory.createDatagramSocket(service_name, port); } catch(BindException bind_ex) { // port already used port++; } } } } else { if(port == 0) port=1024; while(port < MAX_PORT) { try { return factory.createDatagramSocket(service_name, port, addr); } catch(BindException bind_ex) { // port already used port++; } } } return sock; // will never be reached, but the stupid compiler didn't figure it out... } public static MulticastSocket createMulticastSocket(SocketFactory factory, String service_name, InetAddress mcast_addr, int port, Log log) throws IOException { if(mcast_addr != null && !mcast_addr.isMulticastAddress()) throw new IllegalArgumentException("mcast_addr (" + mcast_addr + ") is not a valid multicast address"); SocketAddress saddr=new InetSocketAddress(mcast_addr, port); MulticastSocket retval=null; try { retval=factory.createMulticastSocket(service_name, saddr); } catch(IOException ex) { if(log != null && log.isWarnEnabled()) { StringBuilder sb=new StringBuilder(); String type=mcast_addr != null ? mcast_addr instanceof Inet4Address? "IPv4" : "IPv6" : "n/a"; sb.append("could not bind to " + mcast_addr + " (" + type + " address)"); sb.append("; make sure your mcast_addr is of the same type as the preferred IP stack (IPv4 or IPv6)"); sb.append(" by checking the value of the system properties java.net.preferIPv4Stack and java.net.preferIPv6Addresses."); sb.append("\nWill ignore mcast_addr, but this may lead to cross talking " + "(see http://www.jboss.org/community/docs/DOC-9469 for details). "); sb.append("\nException was: " + ex); log.warn(sb.toString()); } } if(retval == null) retval=factory.createMulticastSocket(service_name, port); return retval; } /** * Returns the address of the interface to use defined by bind_addr and bind_interface * @param props * @return * @throws UnknownHostException * @throws SocketException */ public static InetAddress getBindAddress(Properties props) throws UnknownHostException, SocketException { // determine the desired values for bind_addr_str and bind_interface_str boolean ignore_systemprops=Util.isBindAddressPropertyIgnored(); String bind_addr_str =Util.getProperty(new String[]{Global.BIND_ADDR}, props, "bind_addr", ignore_systemprops, null); String bind_interface_str =Util.getProperty(new String[]{Global.BIND_INTERFACE, null}, props, "bind_interface", ignore_systemprops, null); InetAddress bind_addr=null; NetworkInterface bind_intf=null; StackType ip_version=Util.getIpStackType(); // 1. if bind_addr_str specified, get bind_addr and check version if(bind_addr_str != null) { bind_addr=InetAddress.getByName(bind_addr_str); // check that bind_addr_host has correct IP version boolean hasCorrectVersion = ((bind_addr instanceof Inet4Address && ip_version == StackType.IPv4) || (bind_addr instanceof Inet6Address && ip_version == StackType.IPv6)) ; if (!hasCorrectVersion) throw new IllegalArgumentException("bind_addr " + bind_addr_str + " has incorrect IP version") ; } // 2. if bind_interface_str specified, get interface and check that it has correct version if(bind_interface_str != null) { bind_intf=NetworkInterface.getByName(bind_interface_str); if(bind_intf != null) { // check that the interface supports the IP version boolean supportsVersion = interfaceHasIPAddresses(bind_intf, ip_version) ; if (!supportsVersion) throw new IllegalArgumentException("bind_interface " + bind_interface_str + " has incorrect IP version") ; } else { // (bind_intf == null) throw new UnknownHostException("network interface " + bind_interface_str + " not found"); } } // 3. intf and bind_addr are both are specified, bind_addr needs to be on intf if (bind_intf != null && bind_addr != null) { boolean hasAddress = false ; // get all the InetAddresses defined on the interface Enumeration addresses = bind_intf.getInetAddresses() ; while (addresses != null && addresses.hasMoreElements()) { // get the next InetAddress for the current interface InetAddress address = (InetAddress) addresses.nextElement() ; // check if address is on interface if (bind_addr.equals(address)) { hasAddress = true ; break ; } } if (!hasAddress) { throw new IllegalArgumentException("network interface " + bind_interface_str + " does not contain address " + bind_addr_str); } } // 4. if only interface is specified, get first non-loopback address on that interface, else if (bind_intf != null) { bind_addr = getAddress(bind_intf, AddressScope.NON_LOOPBACK) ; } // 5. if neither bind address nor bind interface is specified, get the first non-loopback // address on any interface else if (bind_addr == null) { bind_addr = getNonLoopbackAddress() ; } // if we reach here, if bind_addr == null, we have tried to obtain a bind_addr but were not successful // in such a case, using a loopback address of the correct version is our only option boolean localhost = false; if (bind_addr == null) { bind_addr = getLocalhost(ip_version); localhost = true; } //http://jira.jboss.org/jira/browse/JGRP-739 //check all bind_address against NetworkInterface.getByInetAddress() to see if it exists on the machine //in some Linux setups NetworkInterface.getByInetAddress(InetAddress.getLocalHost()) returns null, so skip //the check in that case if(!localhost && NetworkInterface.getByInetAddress(bind_addr) == null) { throw new UnknownHostException("Invalid bind address " + bind_addr); } if(props != null) { props.remove("bind_addr"); props.remove("bind_interface"); } return bind_addr; } /** * Method used by PropertyConverters.BindInterface to check that a bind_address is * consistent with a specified interface * * Idea: * 1. We are passed a bind_addr, which may be null * 2. If non-null, check that bind_addr is on bind_interface - if not, throw exception, * otherwise, return the original bind_addr * 3. If null, get first non-loopback address on bind_interface, using stack preference to * get the IP version. If no non-loopback address, then just return null (i.e. the * bind_interface did not influence the decision). * */ public static InetAddress validateBindAddressFromInterface(InetAddress bind_addr, String bind_interface_str) throws UnknownHostException, SocketException { NetworkInterface bind_intf=null; if(bind_addr != null && bind_addr.isLoopbackAddress()) return bind_addr; // 1. if bind_interface_str is null, or empty, no constraint on bind_addr if (bind_interface_str == null || bind_interface_str.trim().length() == 0) return bind_addr; // 2. get the preferred IP version for the JVM - it will be IPv4 or IPv6 StackType ip_version = getIpStackType(); // 3. if bind_interface_str specified, get interface and check that it has correct version bind_intf=NetworkInterface.getByName(bind_interface_str); if(bind_intf != null) { // check that the interface supports the IP version boolean supportsVersion = interfaceHasIPAddresses(bind_intf, ip_version) ; if (!supportsVersion) throw new IllegalArgumentException("bind_interface " + bind_interface_str + " has incorrect IP version") ; } else { // (bind_intf == null) throw new UnknownHostException("network interface " + bind_interface_str + " not found"); } // 3. intf and bind_addr are both are specified, bind_addr needs to be on intf if (bind_addr != null) { boolean hasAddress = false ; // get all the InetAddresses defined on the interface Enumeration addresses = bind_intf.getInetAddresses() ; while (addresses != null && addresses.hasMoreElements()) { // get the next InetAddress for the current interface InetAddress address = (InetAddress) addresses.nextElement() ; // check if address is on interface if (bind_addr.equals(address)) { hasAddress = true ; break ; } } if (!hasAddress) { String bind_addr_str = bind_addr.getHostAddress(); throw new IllegalArgumentException("network interface " + bind_interface_str + " does not contain address " + bind_addr_str); } } // 4. if only interface is specified, get first non-loopback address on that interface, else { bind_addr = getAddress(bind_intf, AddressScope.NON_LOOPBACK) ; } //http://jira.jboss.org/jira/browse/JGRP-739 //check all bind_address against NetworkInterface.getByInetAddress() to see if it exists on the machine //in some Linux setups NetworkInterface.getByInetAddress(InetAddress.getLocalHost()) returns null, so skip //the check in that case if(bind_addr != null && NetworkInterface.getByInetAddress(bind_addr) == null) { throw new UnknownHostException("Invalid bind address " + bind_addr); } // if bind_addr == null, we have tried to obtain a bind_addr but were not successful // in such a case, return the original value of null so the default will be applied return bind_addr; } public static boolean checkForLinux() { return checkForPresence("os.name", "linux"); } public static boolean checkForHp() { return checkForPresence("os.name", "hp"); } public static boolean checkForSolaris() { return checkForPresence("os.name", "sun"); } public static boolean checkForWindows() { return checkForPresence("os.name", "win"); } public static boolean checkForMac() { return checkForPresence("os.name", "mac"); } private static boolean checkForPresence(String key, String value) { try { String tmp=System.getProperty(key); return tmp != null && tmp.trim().toLowerCase().startsWith(value); } catch(Throwable t) { return false; } } public static void prompt(String s) { System.out.println(s); System.out.flush(); try { while(System.in.available() > 0) System.in.read(); System.in.read(); } catch(IOException e) { e.printStackTrace(); } } /** IP related utilities */ public static InetAddress getLocalhost(StackType ip_version) throws UnknownHostException { if (ip_version == StackType.IPv4) return InetAddress.getByName("127.0.0.1") ; else return InetAddress.getByName("::1") ; } /** * Returns the first non-loopback address on any interface on the current host. */ public static InetAddress getNonLoopbackAddress() throws SocketException { return getAddress(AddressScope.NON_LOOPBACK); } /** * Returns the first address on any interface of the current host, which satisfies scope */ public static InetAddress getAddress(AddressScope scope) throws SocketException { InetAddress address=null ; Enumeration intfs=NetworkInterface.getNetworkInterfaces(); while(intfs.hasMoreElements()) { NetworkInterface intf=(NetworkInterface)intfs.nextElement(); try { if(intf.isUp()) { address=getAddress(intf, scope) ; if(address != null) return address; } } catch (SocketException e) { } } return null ; } /** * Returns the first address on the given interface on the current host, which satisfies scope * * @param intf the interface to be checked */ public static InetAddress getAddress(NetworkInterface intf, AddressScope scope) { StackType ip_version=Util.getIpStackType(); for(Enumeration addresses=intf.getInetAddresses(); addresses.hasMoreElements();) { InetAddress addr=(InetAddress)addresses.nextElement(); boolean match; switch(scope) { case GLOBAL: match=!addr.isLoopbackAddress() && !addr.isLinkLocalAddress() && !addr.isSiteLocalAddress(); break; case SITE_LOCAL: match=addr.isSiteLocalAddress(); break; case LINK_LOCAL: match=addr.isLinkLocalAddress(); break; case LOOPBACK: match=addr.isLoopbackAddress(); break; case NON_LOOPBACK: match=!addr.isLoopbackAddress(); break; default: throw new IllegalArgumentException("scope " + scope + " is unknown"); } if(match) { if((addr instanceof Inet4Address && ip_version == StackType.IPv4) || (addr instanceof Inet6Address && ip_version == StackType.IPv6)) return addr; } } return null ; } /** * A function to check if an interface supports an IP version (i.e has addresses * defined for that IP version). * * @param intf * @return */ public static boolean interfaceHasIPAddresses(NetworkInterface intf, StackType ip_version) throws UnknownHostException { boolean supportsVersion = false ; if (intf != null) { // get all the InetAddresses defined on the interface Enumeration addresses = intf.getInetAddresses() ; while (addresses != null && addresses.hasMoreElements()) { // get the next InetAddress for the current interface InetAddress address = (InetAddress) addresses.nextElement() ; // check if we find an address of correct version if ((address instanceof Inet4Address && (ip_version == StackType.IPv4)) || (address instanceof Inet6Address && (ip_version == StackType.IPv6))) { supportsVersion = true ; break ; } } } else { throw new UnknownHostException("network interface " + intf + " not found") ; } return supportsVersion ; } public static StackType getIpStackType() { return ip_stack_type; } /** * Tries to determine the type of IP stack from the available interfaces and their addresses and from the * system properties (java.net.preferIPv4Stack and java.net.preferIPv6Addresses) * @return StackType.IPv4 for an IPv4 only stack, StackYTypeIPv6 for an IPv6 only stack, and StackType.Unknown * if the type cannot be detected */ private static StackType _getIpStackType() { boolean isIPv4StackAvailable = isStackAvailable(true) ; boolean isIPv6StackAvailable = isStackAvailable(false) ; // if only IPv4 stack available if (isIPv4StackAvailable && !isIPv6StackAvailable) { return StackType.IPv4; } // if only IPv6 stack available else if (isIPv6StackAvailable && !isIPv4StackAvailable) { return StackType.IPv6; } // if dual stack else if (isIPv4StackAvailable && isIPv6StackAvailable) { // get the System property which records user preference for a stack on a dual stack machine if(Boolean.getBoolean(Global.IPv4)) // has preference over java.net.preferIPv6Addresses return StackType.IPv4; if(Boolean.getBoolean(Global.IPv6)) return StackType.IPv6; return StackType.IPv6; } return StackType.Unknown; } public static boolean isStackAvailable(boolean ipv4) { Collection<InetAddress> all_addrs=getAllAvailableAddresses(); for(InetAddress addr: all_addrs) if(ipv4 && addr instanceof Inet4Address || (!ipv4 && addr instanceof Inet6Address)) return true; return false; } public static List<NetworkInterface> getAllAvailableInterfaces() throws SocketException { List<NetworkInterface> retval=new ArrayList<NetworkInterface>(10); NetworkInterface intf; for(Enumeration en=NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) { intf=(NetworkInterface)en.nextElement(); retval.add(intf); } return retval; } public static Collection<InetAddress> getAllAvailableAddresses() { Set<InetAddress> retval=new HashSet<InetAddress>(); Enumeration en; try { en=NetworkInterface.getNetworkInterfaces(); if(en == null) return retval; while(en.hasMoreElements()) { NetworkInterface intf=(NetworkInterface)en.nextElement(); Enumeration<InetAddress> addrs=intf.getInetAddresses(); while(addrs.hasMoreElements()) retval.add(addrs.nextElement()); } } catch(SocketException e) { e.printStackTrace(); } return retval; } public static void checkIfValidAddress(InetAddress bind_addr, String prot_name) throws Exception { if(bind_addr.isAnyLocalAddress() || bind_addr.isLoopbackAddress()) return; Collection<InetAddress> addrs=getAllAvailableAddresses(); for(InetAddress addr: addrs) { if(addr.equals(bind_addr)) return; } throw new BindException("[" + prot_name + "] " + bind_addr + " is not a valid address on any local network interface"); } /** * Returns a value associated wither with one or more system properties, or found in the props map * @param system_props * @param props List of properties read from the configuration file * @param prop_name The name of the property, will be removed from props if found * @param ignore_sysprops If true, system properties are not used and the values will only be retrieved from * props (not system_props) * @param default_value Used to return a default value if the properties or system properties didn't have the value * @return The value, or null if not found */ public static String getProperty(String[] system_props, Properties props, String prop_name, boolean ignore_sysprops, String default_value) { String retval=null; if(props != null && prop_name != null) { retval=props.getProperty(prop_name); props.remove(prop_name); } if(!ignore_sysprops) { String tmp, prop; if(system_props != null) { for(int i=0; i < system_props.length; i++) { prop=system_props[i]; if(prop != null) { try { tmp=System.getProperty(prop); if(tmp != null) return tmp; // system properties override config file definitions } catch(SecurityException ex) {} } } } } if(retval == null) return default_value; return retval; } public static boolean isBindAddressPropertyIgnored() { try { String tmp=System.getProperty(Global.IGNORE_BIND_ADDRESS_PROPERTY); if(tmp == null) return false; tmp=tmp.trim().toLowerCase(); return !(tmp.equals("false") || tmp.equals("no") || tmp.equals("off")) && (tmp.equals("true") || tmp.equals("yes") || tmp.equals("on")); } catch(SecurityException ex) { return false; } } public static boolean isCoordinator(JChannel ch) { return isCoordinator(ch.getView(), ch.getAddress()); } public static boolean isCoordinator(View view, Address local_addr) { if(view == null || local_addr == null) return false; List<Address> mbrs=view.getMembers(); return !(mbrs == null || mbrs.isEmpty()) && local_addr.equals(mbrs.iterator().next()); } public static Address getCoordinator(View view) { if(view == null) return null; List<Address> mbrs=view.getMembers(); return !mbrs.isEmpty()? mbrs.get(0) : null; } public static MBeanServer getMBeanServer() { ArrayList servers = MBeanServerFactory.findMBeanServer(null); if (servers != null && !servers.isEmpty()) { // return 'jboss' server if available for (int i = 0; i < servers.size(); i++) { MBeanServer srv = (MBeanServer) servers.get(i); if ("jboss".equalsIgnoreCase(srv.getDefaultDomain())) return srv; } // return first available server return (MBeanServer) servers.get(0); } else { //if it all fails, create a default return MBeanServerFactory.createMBeanServer(); } } public static void registerChannel(JChannel channel, String name) { MBeanServer server=Util.getMBeanServer(); if(server != null) { try { JmxConfigurator.registerChannel(channel, server, (name != null? name : "jgroups"), channel.getClusterName(), true); } catch(Exception e) { e.printStackTrace(); } } } public static String generateList(Collection c, String separator) { if(c == null) return null; StringBuilder sb=new StringBuilder(); boolean first=true; for(Iterator it=c.iterator(); it.hasNext();) { if(first) { first=false; } else { sb.append(separator); } sb.append(it.next()); } return sb.toString(); } /** * Go through the input string and replace any occurance of ${p} with the * props.getProperty(p) value. If there is no such property p defined, then * the ${p} reference will remain unchanged. * * If the property reference is of the form ${p:v} and there is no such * property p, then the default value v will be returned. * * If the property reference is of the form ${p1,p2} or ${p1,p2:v} then the * primary and the secondary properties will be tried in turn, before * returning either the unchanged input, or the default value. * * The property ${/} is replaced with System.getProperty("file.separator") * value and the property ${:} is replaced with * System.getProperty("path.separator"). * * @param string - * the string with possible ${} references * @param props - * the source for ${x} property ref values, null means use * System.getProperty() * @return the input string with all property references replaced if any. If * there are no valid references the input string will be returned. * @throws {@link java.security.AccessControlException} * when not authorised to retrieved system properties */ public static String replaceProperties(final String string, final Properties props) { /** File separator value */ final String FILE_SEPARATOR=File.separator; /** Path separator value */ final String PATH_SEPARATOR=File.pathSeparator; /** File separator alias */ final String FILE_SEPARATOR_ALIAS="/"; /** Path separator alias */ final String PATH_SEPARATOR_ALIAS=":"; // States used in property parsing final int NORMAL=0; final int SEEN_DOLLAR=1; final int IN_BRACKET=2; final char[] chars=string.toCharArray(); StringBuilder buffer=new StringBuilder(); boolean properties=false; int state=NORMAL; int start=0; for(int i=0;i < chars.length;++i) { char c=chars[i]; // Dollar sign outside brackets if(c == '$' && state != IN_BRACKET) state=SEEN_DOLLAR; // Open bracket immediatley after dollar else if(c == '{' && state == SEEN_DOLLAR) { buffer.append(string.substring(start, i - 1)); state=IN_BRACKET; start=i - 1; } // No open bracket after dollar else if(state == SEEN_DOLLAR) state=NORMAL; // Closed bracket after open bracket else if(c == '}' && state == IN_BRACKET) { // No content if(start + 2 == i) { buffer.append("${}"); // REVIEW: Correct? } else // Collect the system property { String value=null; String key=string.substring(start + 2, i); // check for alias if(FILE_SEPARATOR_ALIAS.equals(key)) { value=FILE_SEPARATOR; } else if(PATH_SEPARATOR_ALIAS.equals(key)) { value=PATH_SEPARATOR; } else { // check from the properties if(props != null) value=props.getProperty(key); else value=System.getProperty(key); if(value == null) { // Check for a default value ${key:default} int colon=key.indexOf(':'); if(colon > 0) { String realKey=key.substring(0, colon); if(props != null) value=props.getProperty(realKey); else value=System.getProperty(realKey); if(value == null) { // Check for a composite key, "key1,key2" value=resolveCompositeKey(realKey, props); // Not a composite key either, use the specified default if(value == null) value=key.substring(colon + 1); } } else { // No default, check for a composite key, "key1,key2" value=resolveCompositeKey(key, props); } } } if(value != null) { properties=true; buffer.append(value); } } start=i + 1; state=NORMAL; } } // No properties if(properties == false) return string; // Collect the trailing characters if(start != chars.length) buffer.append(string.substring(start, chars.length)); // Done return buffer.toString(); } /** * Try to resolve a "key" from the provided properties by checking if it is * actually a "key1,key2", in which case try first "key1", then "key2". If * all fails, return null. * * It also accepts "key1," and ",key2". * * @param key * the key to resolve * @param props * the properties to use * @return the resolved key or null */ private static String resolveCompositeKey(String key, Properties props) { String value=null; // Look for the comma int comma=key.indexOf(','); if(comma > -1) { // If we have a first part, try resolve it if(comma > 0) { // Check the first part String key1=key.substring(0, comma); if(props != null) value=props.getProperty(key1); else value=System.getProperty(key1); } // Check the second part, if there is one and first lookup failed if(value == null && comma < key.length() - 1) { String key2=key.substring(comma + 1); if(props != null) value=props.getProperty(key2); else value=System.getProperty(key2); } } // Return whatever we've found or null return value; } // /** // * Replaces variables with values from system properties. If a system property is not found, the property is // * removed from the output string // * @param input // * @return // */ // public static String substituteVariables(String input) throws Exception { // Collection<Configurator.ProtocolConfiguration> configs=Configurator.parseConfigurations(input); // for(Configurator.ProtocolConfiguration config: configs) { // for(Iterator<Map.Entry<String,String>> it=config.getProperties().entrySet().iterator(); it.hasNext();) { // Map.Entry<String,String> entry=it.next(); // // // } // } // // // return null; // } /** * Replaces variables of ${var:default} with System.getProperty(var, default). If no variables are found, returns * the same string, otherwise a copy of the string with variables substituted * @param val * @return A string with vars replaced, or the same string if no vars found */ public static String substituteVariable(String val) { if(val == null) return val; String retval=val, prev; while(retval.contains("${")) { // handle multiple variables in val prev=retval; retval=_substituteVar(retval); if(retval.equals(prev)) break; } return retval; } private static String _substituteVar(String val) { int start_index, end_index; start_index=val.indexOf("${"); if(start_index == -1) return val; end_index=val.indexOf("}", start_index+2); if(end_index == -1) throw new IllegalArgumentException("missing \"}\" in " + val); String tmp=getProperty(val.substring(start_index +2, end_index)); if(tmp == null) return val; StringBuilder sb=new StringBuilder(); sb.append(val.substring(0, start_index)); sb.append(tmp); sb.append(val.substring(end_index+1)); return sb.toString(); } public static String getProperty(String s) { String var, default_val, retval=null; int index=s.indexOf(":"); if(index >= 0) { var=s.substring(0, index); default_val=s.substring(index+1); if(default_val != null && default_val.length() > 0) default_val=default_val.trim(); // retval=System.getProperty(var, default_val); retval=_getProperty(var, default_val); } else { var=s; // retval=System.getProperty(var); retval=_getProperty(var, null); } return retval; } /** * Parses a var which might be comma delimited, e.g. bla,foo:1000: if 'bla' is set, return its value. Else, * if 'foo' is set, return its value, else return "1000" * @param var * @param default_value * @return */ private static String _getProperty(String var, String default_value) { if(var == null) return null; List<String> list=parseCommaDelimitedStrings(var); if(list == null || list.isEmpty()) { list=new ArrayList<String>(1); list.add(var); } String retval=null; for(String prop: list) { try { retval=System.getProperty(prop); if(retval != null) return retval; } catch(Throwable e) { } } return default_value; } /** * Used to convert a byte array in to a java.lang.String object * @param bytes the bytes to be converted * @return the String representation */ private static String getString(byte[] bytes) { StringBuilder sb=new StringBuilder(); for (int i = 0; i < bytes.length; i++) { byte b = bytes[i]; sb.append(0x00FF & b); if (i + 1 < bytes.length) { sb.append("-"); } } return sb.toString(); } /** * Converts a java.lang.String in to a MD5 hashed String * @param source the source String * @return the MD5 hashed version of the string */ public static String md5(String source) { try { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] bytes = md.digest(source.getBytes()); return getString(bytes); } catch (Exception e) { return null; } } /** * Converts a java.lang.String in to a SHA hashed String * @param source the source String * @return the MD5 hashed version of the string */ public static String sha(String source) { try { MessageDigest md = MessageDigest.getInstance("SHA"); byte[] bytes = md.digest(source.getBytes()); return getString(bytes); } catch (Exception e) { e.printStackTrace(); return null; } } public static String methodNameToAttributeName(String methodName) { methodName=methodName.startsWith("get") || methodName.startsWith("set")? methodName.substring(3): methodName; methodName=methodName.startsWith("is")? methodName.substring(2) : methodName; // Pattern p=Pattern.compile("[A-Z]+"); Matcher m=METHOD_NAME_TO_ATTR_NAME_PATTERN.matcher(methodName); StringBuffer sb=new StringBuffer(); while(m.find()) { int start=m.start(), end=m.end(); String str=methodName.substring(start, end).toLowerCase(); if(str.length() > 1) { String tmp1=str.substring(0, str.length() -1); String tmp2=str.substring(str.length() -1); str=tmp1 + "_" + tmp2; } if(start == 0) { m.appendReplacement(sb, str); } else m.appendReplacement(sb, "_" + str); } m.appendTail(sb); return sb.toString(); } public static String attributeNameToMethodName(String attr_name) { if(attr_name.contains("_")) { // Pattern p=Pattern.compile("_."); Matcher m=ATTR_NAME_TO_METHOD_NAME_PATTERN.matcher(attr_name); StringBuffer sb=new StringBuffer(); while(m.find()) { m.appendReplacement(sb, attr_name.substring(m.end() - 1, m.end()).toUpperCase()); } m.appendTail(sb); char first=sb.charAt(0); if(Character.isLowerCase(first)) { sb.setCharAt(0, Character.toUpperCase(first)); } return sb.toString(); } else { if(Character.isLowerCase(attr_name.charAt(0))) { return attr_name.substring(0, 1).toUpperCase() + attr_name.substring(1); } else { return attr_name; } } } /** * Runs a task on a separate thread * @param task * @param factory * @param group * @param thread_name */ public static void runAsync(Runnable task, ThreadFactory factory, String thread_name) { Thread thread=factory.newThread(task, thread_name); thread.start(); } }