/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * 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 net.jini.id; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.security.SecureRandom; /** * Provides static methods for creating {@link Uuid} instances. * * <p>Included are methods to create a <code>Uuid</code> with a given * 128-bit value or a string representation of such a value, to * generate new <code>Uuid</code> values, and to read a binary * representation of a <code>Uuid</code> from a stream. * * @author Sun Microsystems, Inc. * @since 2.0 **/ public final class UuidFactory { /** guards secureRandom */ private static final Object lock = new Object(); /** source of cryptographically strong random bits, lazily created */ private static SecureRandom secureRandom; /** * Creates a new <code>Uuid</code> with the specified 128-bit * value. * * <p>This method can be used to create a <code>Uuid</code> with a * value that has been previously generated, perhaps by an * external mechanism. * * @param bits0 the most significant 64 bits of the 128-bit value * * @param bits1 the least significant 64 bits of the 128-bit value * * @return a <code>Uuid</code> with the given value **/ public static Uuid create(long bits0, long bits1) { return new Impl(bits0, bits1); } /** * Creates a new <code>Uuid</code> with the 128-bit value * represented by the specified string. * * <p>The supplied string representation must be in the format * defined by {@link Uuid#toString Uuid.toString} except that * uppercase hexadecimal digits are allowed. * * @param s the string representation to create the * <code>Uuid</code> with * * @return a <code>Uuid</code> with the value represented by the * given string * * @throws IllegalArgumentException if the supplied string * representation does not conform to the specified format * * @throws NullPointerException if <code>s</code> is * <code>null</code> **/ public static Uuid create(String s) { if (s.length() != 36 || s.charAt(8) != '-' || s.charAt(13) != '-' || s.charAt(18) != '-' || s.charAt(23) != '-') { throw new IllegalArgumentException( "invalid string representation: \"" + s + "\""); } long time_low; long time_mid; long time_hi_and_version; long clock_seq_and_variant; long node; try { time_low = Long.parseLong(s.substring(0, 8), 16); time_mid = Long.parseLong(s.substring(9, 13), 16); time_hi_and_version = Long.parseLong(s.substring(14, 18), 16); clock_seq_and_variant = Long.parseLong(s.substring(19, 23), 16); node = Long.parseLong(s.substring(24, 36), 16); } catch (NumberFormatException e) { IllegalArgumentException iae = new IllegalArgumentException( "invalid string representation: \"" + s + "\""); iae.initCause(e); throw iae; } if (time_low < 0 || time_mid < 0 || time_hi_and_version < 0 || clock_seq_and_variant < 0 || node < 0) { throw new IllegalArgumentException( "invalid string representation: \"" + s + "\""); } long bits0 = time_low << 32 | time_mid << 16 | time_hi_and_version; long bits1 = clock_seq_and_variant << 48 | node; return create(bits0, bits1); } /** * Generates a new <code>Uuid</code> with 122 bits of its value * produced from a cryptographically strong random sequence. * * <p>The value of a <code>Uuid</code> returned by this method is * computationally difficult to guess and is highly likely to be * unique with respect to all other <code>Uuid</code> values * returned by this method over space and time. * * <p>Specifically, this method creates a new <code>Uuid</code> * with the a <code>variant</code> field of <code>0x2</code>, a * <code>version</code> field of <code>0x4</code>, and the * remaining 122 bits of its value produced from a * cryptographically strong random sequence. * * @return a newly generated <code>Uuid</code> * * @see SecureRandom **/ public static Uuid generate() { synchronized (lock) { if (secureRandom == null) { secureRandom = new SecureRandom(); } } long bits0 = secureRandom.nextLong(); long bits1 = secureRandom.nextLong(); // set "version" field to 0x4 bits0 &= 0xFFFFFFFFFFFF0FFFL; bits0 |= 0x0000000000004000L; // set "variant" field to 0x2 bits1 &= 0x3FFFFFFFFFFFFFFFL; bits1 |= 0x8000000000000000L; return create(bits0, bits1); } /** * Creates a new <code>Uuid</code> with the 128-bit value obtained * by unmarshalling a binary representation from the supplied * <code>InputStream</code>. * * <p>Specifically, this method reads 16 bytes from the stream, * and then it creates a new <code>Uuid</code> with the 128-bit * value represented by those bytes interpreted in network * (big-endian) byte order. * * @param in the <code>InputStream</code> to read the * <code>Uuid</code> from * * @return a <code>Uuid</code> with the value unmarshalled from * the stream * * @throws IOException if an I/O exception occurs while performing * this operation * * @throws NullPointerException if <code>in</code> is * <code>null</code> **/ public static Uuid read(InputStream in) throws IOException { long bits0 = readLong(in); long bits1 = readLong(in); return create(bits0, bits1); } /** * Read a long value from an InputStream in big-endian byte order. **/ private static long readLong(InputStream in) throws IOException { int b0 = in.read(); int b1 = in.read(); int b2 = in.read(); int b3 = in.read(); if ((b0 | b1 | b2 | b3) == -1) { throw new EOFException(); } int upper = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; b0 = in.read(); b1 = in.read(); b2 = in.read(); b3 = in.read(); if ((b0 | b1 | b2 | b3) == -1) { throw new EOFException(); } int lower = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; return ((long) upper << 32) | (lower & 0xFFFFFFFFL); } /** Prevents instantiation. */ private UuidFactory() { throw new AssertionError(); } /** * Extends <code>Uuid</code> trivially, in order to be a preferred * class and retain the original codebase annotation. **/ private static class Impl extends Uuid { private static final long serialVersionUID = 1089722863511468966L; Impl(long bits0, long bits1) { super(bits0, bits1); } } }