commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Adkins Kendall <Kendall.Adk...@HCAhealthcare.com>
Subject RE: [id] UUID update
Date Thu, 04 Mar 2004 04:22:56 GMT
Hmm. I guess I can't send attachments.  Is there a better way to share
source code?  Here is the code:

package com.hca.portal.util;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Random;

/**
 * The class will generate GUIDs.
 * 
 * @author Kendall Adkins
 */
public class UIDGenerator {

    //the hex string rep of the node ip address
    private final static String hexInetAddress = getHexInetAddress();
    
    //the object used to ensure uniqueness across vm's
    //note: this does not quite work with 64 bit addressing
    private final static Object hashCodeObject = new Object();
    private final static String hexHashCode = getHexHashCode();
    
    //the seeded random number generator used to pad the GUID to a length of
32
    private final static Random seededRandom = getSeededRandomInstance();
    
    /**
     * Constructor for GUIDFactory.
     */
    private UIDGenerator() {
    }

    /**
     * Gets the next GUID.
     */
    public static void main(String args[]) throws UnknownHostException {
    	//test();
        System.out.println("New GUID: " + makeGUID());
    }

    /**
     * Test to see how many unique GUID's can be generated in 
     * a second. The number generated should equal the number
     * of unique GUIDs.
     */
    public static void test() throws UnknownHostException {

        long stopTime = System.currentTimeMillis() + 1000;
        int i = 1;
        HashMap hmap = new HashMap();
        String guid = null;
        while(System.currentTimeMillis() <= stopTime) {
            guid = makeGUID();
            hmap.put(guid,guid);
            System.out.println("New GUID(" + i++ + "): " + guid);
        }
        System.out.println("Number of unique GUIDs: " + hmap.size());
    }
    
    /**
     * Gets the next GUID.
     */
    public static String makeGUID() {
        StringBuffer guid = new StringBuffer();
        guid.append(hexInetAddress);
        guid.append(hexHashCode);
        guid.append(getHexSystemTime());
        randomPadTo32(guid);
        return guid.toString();
    }
    
    /**
     * Pad the passed string buffer with a random number to
     * ensure the length is 32.
     */
    private static void randomPadTo32(StringBuffer guid) {
        int padSize = (32 - guid.length()) / 2;
        if(padSize > 0) { 
            byte[] padBytes = new byte[padSize];
            seededRandom.nextBytes(padBytes);
            guid.append(byteArrayToHexString(padBytes));
        }
    }

    /**
     * Get the current system time and return a hexadecimal
     * string representation.  This method will return a unique 
     * hex time string.
     */
    private final static String getHexSystemTime() {
        
        //Get least significant 32 bits of the system time and make sure 
        //the significant bit is set
        int time = (int)System.currentTimeMillis() & -1;
        
        //Convert the time to a hex string
        String hexTime = Integer.toHexString(time);
        
        //Make sure we get 8 hex digits
        hexTime = hexTime.length() % 2 != 1 ? hexTime : "0" + hexTime;
        
        return hexTime;        
    }

    /**
     * Returns a hexadecimal string of the 
     * hosts ip address.  If the host ip address cannot
     * be found then a random number is generated.
     */
    private static String getHexInetAddress() {

        InetAddress inet = null;
        byte[] byteAddress = null;
        
        //Get the ip address byte array
        try {
            inet = InetAddress.getLocalHost();
            byteAddress = inet.getAddress();
            
        //Generate a random byte array when the ip address is unknown
        } catch(UnknownHostException e) {
            byteAddress = new byte[4];
            new Random().nextBytes(byteAddress);
        }

        //Convert to a hex string and return
        return byteArrayToHexString(byteAddress);
    }

    /**
     * Returns a hexadecimal string of a new objects
     * hashcode
     */
    private static String getHexHashCode() {
        return Integer.toHexString(hashCodeObject.hashCode());
    }

    /**
     * Returns a new instance of Random seeded with a random 64 bit
     * seed.
     */
    private final static Random getSeededRandomInstance() {
        SecureRandom secureRand = new SecureRandom();
        long secureInitializer = secureRand.nextLong();
        return new Random(secureInitializer);
    }

    /**
     * Convert the passed byte array to a hex string.
     */
    private static String byteArrayToHexString(byte bytes[]) {
        StringBuffer hex_string = new StringBuffer(bytes.length * 2);
        if (bytes != null) {
            for (int i = 0; i < bytes.length; i++) {
                int byte_val = bytes[i];
                if (byte_val < 0) {
                    byte_val += 256;
                }
                String hex_code = Integer.toHexString(byte_val);
                if (hex_code.length() % 2 == 1) {
                    hex_code = "0" + hex_code;
                }
                hex_string.append(hex_code);
            }

        }
        return hex_string.toString();
    }

}

-----Original Message-----
From: Adkins Kendall [mailto:Kendall.Adkins@HCAhealthcare.com]
Sent: Wednesday, March 03, 2004 10:20 PM
To: 'Jakarta Commons Developers List'
Subject: RE: [id] UUID update


Here is a UID Generator we are using.  Part of the UID contains the hash of
a final static object instance.  In this way, while a JVM is up you are
assured no other objects can occupy the same memory address.  We have had no
difficulty with it under heavy load across 4 servers each with three JVMs.



-----Original Message-----
From: Phil Steitz [mailto:phil@steitz.com]
Sent: Wednesday, March 03, 2004 9:56 PM
To: Jakarta Commons Developers List
Subject: Re: [id] UUID update


Tim Reilly wrote:
>>I will look at this stuff carefully this weekend, but one thing that
>>jumped out at me from your post above was that the "global lock" issue
>>might be avoidable by putting more into the node identifier, i.e., build
>>in a jvm identifier.  IIRC, this is essentially what tomcat when
>>generating session ids to avoid collisions across jvms on the same host.
>>Just something to think about.
>>
>>Phil
>>
> 
> 
> I'm back. I'm thinking about this suggestion... My original concern is
both
> with physical machines that run multiple jvm versions, as well as multiple
> instances of the same jvm (such as in an application server that is
> vertically clustered.)
> 
> I don't know of an identifier that I can get that uniquely identifies a
jvm
> instance, but there may be something (I'll dig around the tomcat code.)
> Coincidently, I do iterate the System properties and then create an MD5 of
> those concatenated with a random and a (new Object().hashCode()) to
generate
> an artificial node id in StateHelper (used in the InMemoryStateImpl). Keep
> in mind, that *ideally* the Node.id is always the MAC address(s) though.

I investigated the tomcat code and concluded that my suggestion above is 
no better/different really than what you are doing and has the 
disadvantage of making the node id nonstandard (bad). AFAIK, there is no 
magical way to generate a guaranteed unique jvm identifier.

> I think I submitted quite a bit to digest in the zip file. Something that
> may make things easier all around might be if I start on creating patches
> just for the VersionFour uuid generator (random uuid)? We can workout
> naming, package structure, and how best to tie in the factory and
> IdentifierUtils.
> Afterwards, we can look at the decisions about the more
complex/troublesome
> version 1 generator.
> If this sounds good to everyone I'll start a new thread around that?
> 
> 
I went ahead and committed the changes in the zip, with no changes other 
than updating the Apache license to 2.0. This is a good start. We need to 
get a better feel for stability / performance and some more eyeballs on 
this code, so I thought it best to get it into CVS now, even if we decide 
to refactor / repackage down the road. Thanks for the contribution.

Some minimial xdocs, or more complete package documentation describing the 
implementation choices made would be a good thing to add about now.  Most 
of this is in the code or mail archives, but it would be good to get it 
into the package docs or xdocs.

If you have not been following all of the commons-dev build stuff, you may 
have missed that you now need to co jakarta-commons-sandbox/sandbox-build 
to get the maven build to work.

Phil

> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
> 




---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Mime
View raw message