All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.restcomm.cluster.UUIDGenerator Maven / Gradle / Ivy

/*
 * Copyright 2022-2023, Mobius Software LTD. and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This program is free software: you can redistribute it and/or modify
 * under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation; either version 3 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see 
 */

package org.restcomm.cluster;

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;

/**
 * 
 * @author yulian.oifa
 * 
 */
public class UUIDGenerator implements IDGenerator 
{
	private static byte[] DefaultNodeBytes=new byte[6];
    private static long gregorianCalendarStart=-12219292800000L;
    private Random random=new Random();    
    private AtomicLong currValue=new AtomicLong(0);
    
    public static transient ThreadLocal buffers = new ThreadLocal() {
        @Override protected byte[] initialValue() {
        	byte[] localValue=new byte[16];  
        	return localValue;
        }
    };
    
    public UUIDGenerator() {
    	InetAddress localAddress=null;
    	InetAddress publicAddress=null;
    	    	
    	Enumeration enumNetworkInterfaces = null;
    	try {
    		enumNetworkInterfaces=NetworkInterface.getNetworkInterfaces();
    	}
    	catch(SocketException ex) {
    		
    	}
    	
    	if(enumNetworkInterfaces!=null) {
	        while (enumNetworkInterfaces.hasMoreElements()) {
	
	            NetworkInterface networkInterface = enumNetworkInterfaces.nextElement();
	            Enumeration enumInetAddress = networkInterface.getInetAddresses();
	
	            while (enumInetAddress.hasMoreElements()) {
	                InetAddress inetAddress = enumInetAddress.nextElement();
	
	                if (!inetAddress.isAnyLocalAddress() && !inetAddress.isMulticastAddress()) {
	                    if(inetAddress.isLoopbackAddress())
	                    	localAddress=inetAddress;
	                    else
	                    	publicAddress=inetAddress;
	                }
	            }
	        }
    	}
        
        InetAddress realAddress=null;
        if(publicAddress!=null)
        	realAddress=publicAddress;
        else if(localAddress!=null)
        	realAddress=localAddress;
        else
        	realAddress=InetAddress.getLoopbackAddress();
                
        currValue.set(random.nextInt());
    	if(realAddress instanceof Inet4Address)
        {
        	byte[] realNodeBytes=new byte[6];
        	System.arraycopy(realAddress.getAddress(),0,realNodeBytes,0,4);
        	byte[] randomSeed=new byte[2];
        	random.nextBytes(randomSeed);
        	System.arraycopy(randomSeed, 0, realNodeBytes, 4, 2);
        	DefaultNodeBytes=realNodeBytes;
        }
        else
        {
        	byte[] realNodeBytes=new byte[6];
        	System.arraycopy(realAddress.getAddress(),0,realNodeBytes,0,6); 
        	DefaultNodeBytes=realNodeBytes;
        }            	
    }
    
    public UUIDGenerator(byte[] serverKey) throws Exception
    {
    	currValue.set(random.nextInt());
        
        if(serverKey.length==6)
        	DefaultNodeBytes=serverKey;
        else
        	throw new Exception("can not initiate node bytes");
    }
    
    public void DefaultClockSequence(byte[] data,int index)
    {
    	long value=currValue.incrementAndGet();    	
    	data[index]=(byte)((value>>8) & 0x00FF);
    	data[index+1]=(byte)(value & 0x00FF);    	
    }
    
    public static byte[] uuidToBytes(UUID value)
    {
    	byte[] data=UUIDGenerator.buffers.get();
    	ByteBuf bb = Unpooled.wrappedBuffer(data);
    	bb.resetWriterIndex();
    	bb.writeLong(value.getMostSignificantBits());
    	bb.writeLong(value.getLeastSignificantBits());
    	return data;
    }
	
    public static UUID bytesToUUID(ByteBuf value)
    {
    	return new UUID(value.readLong(),value.readLong());    	
    }
	
    public static long getTimestamp(UUID uuid)
    {
    	return uuid.timestamp()/10000L + gregorianCalendarStart;
    }  
    
    public static short getClockSequence(UUID uuid)
    {
    	byte[] data=uuidToBytes(uuid);
    	short result=getClockSequence(data);
    	return result;
    }
    
    public static short getClockSequence(byte[] uuidBytes)
    {
    	return (short)(((uuidBytes[8] & 0x7F)<<8) | (uuidBytes[9]&0x0FF));
    }
    
	public byte[] GenerateTimeBasedGuidBytes(long time)
    {
    	long ticks = (time - gregorianCalendarStart)*10000L;
        
        byte[] guid = UUIDGenerator.buffers.get();
        ByteBuf buffer=Unpooled.wrappedBuffer(guid);
        buffer.resetWriterIndex();
        buffer.writeLong(ticks);
        
        byte tempBuffer;
        for(int i=0;i<4;i++)
        {
        	tempBuffer=guid[i];
        	guid[i]=guid[7-i];
        	guid[7-i]=tempBuffer;
        }
        
        // copy node
        System.arraycopy(DefaultNodeBytes, 0, guid, 10, 6);
        
        // copy clock sequence
        DefaultClockSequence(guid,8);
        
        guid[8] &= (byte)0x3f;
        guid[8] |= (byte)0x80;

        // set the version
        guid[7] &= (byte)0x0f;
        guid[7] |= (byte)((byte)0x01 << 4);
        
        //now lets reverse data
        tempBuffer=guid[0];
        guid[0]=guid[3];
        guid[3]=tempBuffer;
        
        tempBuffer=guid[1];
        guid[1]=guid[2];
        guid[2]=tempBuffer;
        
        tempBuffer=guid[4];
        guid[4]=guid[5];
        guid[5]=tempBuffer;
        
        tempBuffer=guid[6];
        guid[6]=guid[7];
        guid[7]=tempBuffer;
        
        return guid;
    }
	
	@Override
	public ClusteredID generateID() 
	{
		byte[] data=GenerateTimeBasedGuidBytes(System.currentTimeMillis());
		ClusteredUUID result = new ClusteredUUID(bytesToUUID(Unpooled.wrappedBuffer(data)));
		return result;
	}

	@Override
	public ClusteredID fromString(String value) 
	{		
		return new ClusteredUUID(UUID.fromString(value));
	}

	@Override
	public ClusteredID fromBytes(byte[] data) 
	{
		return new ClusteredUUID(bytesToUUID(Unpooled.wrappedBuffer(data)));
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy