org.aries.util.UUIDGeneratorFromJBoss.java Source code

Java tutorial

Introduction

Here is the source code for org.aries.util.UUIDGeneratorFromJBoss.java

Source

/* JUG Java Uuid Generator
 *
 * Copyright (c) 2002- Tatu Saloranta, tatu.saloranta@iki.fi
 *
 * Licensed under the License specified in the file licenses/LICENSE.txt which is
 * included with the source code.
 * You may not use this file except in compliance with the License.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.aries.util;

import java.lang.reflect.Method;
import java.net.NetworkInterface;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Random;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public final class UUIDGeneratorFromJBoss {

    private final static UUIDGeneratorFromJBoss sSingleton = new UUIDGeneratorFromJBoss();

    private static final Log log = LogFactory.getLog(UUIDGenerator.class);

    // Windows has some fake adapters that will return the same HARDWARE ADDRESS on any computer. We need to ignore those
    private static final byte[][] BLACK_LIST = new byte[][] { { 2, 0, 84, 85, 78, 1 } };

    /**
     * Random-generator, used by various UUID-generation methods:
     */
    private Random mRnd = null;

    private final Object mTimerLock = new Object();

    private UUIDTimer mTimer = null;

    private byte[] address;

    /**
     * Constructor is private to enforce singleton access.
     */
    private UUIDGeneratorFromJBoss() {
    }

    /**
     * Method used for accessing the singleton generator instance.
     */
    public static UUIDGeneratorFromJBoss getInstance() {
        return UUIDGeneratorFromJBoss.sSingleton;
    }

    /*
     * ///////////////////////////////////////////////////// // Configuration
     * /////////////////////////////////////////////////////
     */

    /**
     * Method for getting the shared random number generator used for generating
     * the UUIDs. This way the initialization cost is only taken once; access
     * need not be synchronized (or in cases where it has to, SecureRandom takes
     * care of it); it might even be good for getting really 'random' stuff to
     * get shared access...
     */
    public final Random getRandomNumberGenerator() {
        /*
         * Could be synchronized, but since side effects are trivial (ie.
         * possibility of generating more than one SecureRandom, of which all but
         * one are dumped) let's not add synchronization overhead:
         */
        if (mRnd == null) {
            mRnd = new SecureRandom();
        }
        return mRnd;
    }

    public final UUID generateTimeBasedUUID(final byte[] byteAddr) {
        byte[] contents = new byte[16];
        int pos = 10;
        for (int i = 0; i < 6; ++i) {
            contents[pos + i] = byteAddr[i];
        }

        synchronized (mTimerLock) {
            if (mTimer == null) {
                mTimer = new UUIDTimer(getRandomNumberGenerator());
            }

            mTimer.getTimestamp(contents);
        }

        return new UUID(UUID.TYPE_TIME_BASED, contents);
    }

    public final byte[] generateDummyAddress() {
        Random rnd = getRandomNumberGenerator();
        byte[] dummy = new byte[6];
        rnd.nextBytes(dummy);
        /* Need to set the broadcast bit to indicate it's not a real
         * address.
         */
        dummy[0] |= (byte) 0x01;

        if (UUIDGeneratorFromJBoss.log.isDebugEnabled()) {
            UUIDGeneratorFromJBoss.log.debug("using dummy address " + UUIDGeneratorFromJBoss.asString(dummy));
        }
        return dummy;
    }

    /**
     * If running java 6 or above, returns {@link NetworkInterface#getHardwareAddress()}, else return <code>null</code>.
     * The first hardware address is returned when iterating all the NetworkInterfaces
     */
    public final static byte[] getHardwareAddress() {
        Method getHardwareAddressMethod;
        Method isUpMethod;
        Method isLoopbackMethod;
        Method isVirtualMethod;
        try {
            getHardwareAddressMethod = NetworkInterface.class.getMethod("getHardwareAddress");
            isUpMethod = NetworkInterface.class.getMethod("isUp");
            isLoopbackMethod = NetworkInterface.class.getMethod("isLoopback");
            isVirtualMethod = NetworkInterface.class.getMethod("isVirtual");
        } catch (Throwable t) {
            // not on Java 6 or not enough security permission
            return null;
        }

        try {
            Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
            while (networkInterfaces.hasMoreElements()) {
                NetworkInterface networkInterface = networkInterfaces.nextElement();
                boolean up = (Boolean) isUpMethod.invoke(networkInterface);
                boolean loopback = (Boolean) isLoopbackMethod.invoke(networkInterface);
                boolean virtual = (Boolean) isVirtualMethod.invoke(networkInterface);

                if (loopback || virtual || !up) {
                    continue;
                }

                Object res = getHardwareAddressMethod.invoke(networkInterface);
                if (res != null && res instanceof byte[]) {
                    byte[] address = (byte[]) res;
                    byte[] paddedAddress = UUIDGeneratorFromJBoss.getZeroPaddedSixBytes(address);

                    if (UUIDGeneratorFromJBoss.isBlackList(address)) {
                        continue;
                    }

                    if (paddedAddress != null) {
                        if (UUIDGeneratorFromJBoss.log.isDebugEnabled()) {
                            UUIDGeneratorFromJBoss.log.debug(
                                    "using hardware address " + UUIDGeneratorFromJBoss.asString(paddedAddress));
                        }
                        return paddedAddress;
                    }
                }
            }
        } catch (Throwable t) {
        }

        return null;
    }

    public final SimpleString generateSimpleStringUUID() {
        return new SimpleString(generateStringUUID());
    }

    public final UUID generateUUID() {
        byte[] address = getAddressBytes();

        UUID uid = generateTimeBasedUUID(address);

        return uid;
    }

    public final String generateStringUUID() {
        byte[] address = getAddressBytes();

        if (address == null) {
            return java.util.UUID.randomUUID().toString();
        } else {
            return generateTimeBasedUUID(address).toString();
        }
    }

    public final static byte[] getZeroPaddedSixBytes(final byte[] bytes) {
        if (bytes == null) {
            return null;
        }
        if (bytes.length > 0 && bytes.length <= 6) {
            if (bytes.length == 6) {
                return bytes;
            } else {
                // pad with zeroes to have a 6-byte array
                byte[] paddedAddress = new byte[6];
                System.arraycopy(bytes, 0, paddedAddress, 0, bytes.length);
                for (int i = bytes.length; i < 6; i++) {
                    paddedAddress[i] = 0;
                }
                return paddedAddress;
            }
        }
        return null;
    }

    // Private -------------------------------------------------------

    private static final boolean isBlackList(final byte[] address) {
        for (byte[] blackList : UUIDGeneratorFromJBoss.BLACK_LIST) {
            if (Arrays.equals(address, blackList)) {
                return true;
            }
        }
        return false;
    }

    private final byte[] getAddressBytes() {
        if (address == null) {
            address = UUIDGeneratorFromJBoss.getHardwareAddress();
            if (address == null) {
                address = generateDummyAddress();
            }
        }

        return address;
    }

    private static final String asString(final byte[] bytes) {
        if (bytes == null) {
            return null;
        }

        String s = "";
        for (int i = 0; i < bytes.length - 1; i++) {
            s += Integer.toHexString(bytes[i]) + ":";
        }
        s += bytes[bytes.length - 1];
        return s;
    }
}