jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From thom...@apache.org
Subject svn commit: r594470 - in /jackrabbit/trunk/jackrabbit-jcr-commons/src: main/java/org/apache/jackrabbit/uuid/ test/java/org/apache/jackrabbit/util/
Date Tue, 13 Nov 2007 10:26:18 GMT
Author: thomasm
Date: Tue Nov 13 02:26:18 2007
New Revision: 594470

URL: http://svn.apache.org/viewvc?rev=594470&view=rev
Log:
JCR-1206: Use SecureRandom to generate UUIDs by default. Also includes a workaround for systems
where SecureRandom initialization is very slow.

Added:
    jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/util/UUIDTest.java
  (with props)
Modified:
    jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/uuid/UUID.java
    jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/uuid/VersionFourGenerator.java
    jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/util/TestAll.java

Modified: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/uuid/UUID.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/uuid/UUID.java?rev=594470&r1=594469&r2=594470&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/uuid/UUID.java
(original)
+++ jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/uuid/UUID.java
Tue Nov 13 02:26:18 2007
@@ -35,12 +35,12 @@
     static final long serialVersionUID = 2526142433736157231L;
 
     /**
-     * the least siginificant 64 bits of the uuid (bytes 8-15)
+     * the least significant 64 bits of the uuid (bytes 8-15)
      */
     private final long lsb;
 
     /**
-     * the most siginificant 64 bits of the uuid (bytes 0-7)
+     * the most significant 64 bits of the uuid (bytes 0-7)
      */
     private final long msb;
 
@@ -59,7 +59,7 @@
     public UUID(byte[] b) throws IllegalArgumentException {
         if (b.length != UUID_BYTE_LENGTH) {
             throw new IllegalArgumentException(
-                    "UUID must be contructed using a 16 byte array.");
+                    "UUID must be constructed using a 16 byte array.");
         }
         msb = ((((long) b[7]) & 0xFF)
                 + ((((long) b[6]) & 0xFF) << 8)
@@ -248,38 +248,38 @@
     public byte[] getRawBytes() {
         byte[] b = new byte[UUID_BYTE_LENGTH];
         long n = msb;
-        b[7] = (byte) (n);
+        b[7] = (byte) n;
         n >>>= 8;
-        b[6] = (byte) (n);
+        b[6] = (byte) n;
         n >>>= 8;
-        b[5] = (byte) (n);
+        b[5] = (byte) n;
         n >>>= 8;
-        b[4] = (byte) (n);
+        b[4] = (byte) n;
         n >>>= 8;
-        b[3] = (byte) (n);
+        b[3] = (byte) n;
         n >>>= 8;
-        b[2] = (byte) (n);
+        b[2] = (byte) n;
         n >>>= 8;
-        b[1] = (byte) (n);
+        b[1] = (byte) n;
         n >>>= 8;
-        b[0] = (byte) (n);
+        b[0] = (byte) n;
 
         n = lsb;
-        b[15] = (byte) (n);
+        b[15] = (byte) n;
         n >>>= 8;
-        b[14] = (byte) (n);
+        b[14] = (byte) n;
         n >>>= 8;
-        b[13] = (byte) (n);
+        b[13] = (byte) n;
         n >>>= 8;
-        b[12] = (byte) (n);
+        b[12] = (byte) n;
         n >>>= 8;
-        b[11] = (byte) (n);
+        b[11] = (byte) n;
         n >>>= 8;
-        b[10] = (byte) (n);
+        b[10] = (byte) n;
         n >>>= 8;
-        b[9] = (byte) (n);
+        b[9] = (byte) n;
         n >>>= 8;
-        b[8] = (byte) (n);
+        b[8] = (byte) n;
 
         return b;
     }
@@ -290,6 +290,6 @@
      * @return a new version 4 UUID, based upon Random bits.
      */
     public static UUID randomUUID() {
-        return (UUID) versionFourGenereator.nextIdentifier();
+        return versionFourGenereator.nextIdentifier();
     }
 }

Modified: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/uuid/VersionFourGenerator.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/uuid/VersionFourGenerator.java?rev=594470&r1=594469&r2=594470&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/uuid/VersionFourGenerator.java
(original)
+++ jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/uuid/VersionFourGenerator.java
Tue Nov 13 02:26:18 2007
@@ -16,8 +16,6 @@
  */
 package org.apache.jackrabbit.uuid;
 
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
 import java.security.SecureRandom;
 import java.util.Random;
 
@@ -30,7 +28,7 @@
  * specification. This class attempts to use a java.security.SecureRandom with
  * the following instantiation
  * <code>SecureRandom.getInstance("SHA1PRNG", "SUN")</code>. If neither secure
- * random implementation is avialable or an Exception is raised a java.util.Random
+ * random implementation is available or an Exception is raised a java.util.Random
  * is used.</p>
  * <p>Note: Instantiation of SecureRandom is an expensive operation. The
  * constructor therefore creates a static member to hold the SecureRandom.
@@ -54,12 +52,22 @@
     /**
      * Random used to generate UUID's
      */
-    private static final Random regularRandom = new Random();
+    private static Random regularRandom = new Random();
 
     /**
      * SecureRandom used to generate UUID's
      */
-    private static Random secureRandom;
+    private static SecureRandom secureRandom;
+    
+    /**
+     * Flag to indicate if the secureRandom instance was initialized
+     */
+    private static volatile boolean secureRandomSeeded;
+    
+    /**
+     * The maximum number of milliseconds to wait for the the initialization
+     */
+    private static final int MAX_SEED_TIME = 1000;
 
     /**
      * The pseudo-random number generator to use
@@ -79,12 +87,17 @@
     }
 
     /**
-     * <p>Returns a new version four UUID.</p>
+     * Returns a new version four UUID.
+     * A cryptographically secure pseudorandom number generator 
+     * is used to generate the values (because otherwise the probability 
+     * of duplicates may be significantly higher).
+     * See also: https://issues.apache.org/jira/browse/JCR-1206
+     * and http://en.wikipedia.org/wiki/UUID
      *
      * @return Object a new version 4 UUID.
      */
-    public Object nextIdentifier() {
-        return nextUUID(false);
+    public UUID nextIdentifier() {
+        return nextUUID(true);
     }
 
     /**
@@ -96,12 +109,63 @@
      * @param secure indicates whether or not to use <code>SecureRandom</code>
in generating the random bits.
      * @return a new version four UUID that was generated by either a <code>Random</code>
or <code>SecureRandom</code>.
      */
-    public Object nextIdentifier(boolean secure) {
+    public UUID nextIdentifier(boolean secure) {
         if (secure) {
             return nextUUID(true);
         }
         return nextUUID(false);
     }
+    
+    /**
+     * Initialize the secure random and seed it.
+     */
+    private static synchronized void initSecureRandom() {
+        if (secureRandom != null) {
+            return;
+        }
+        try {
+            if (usePRNGPackage != null) {
+                secureRandom = SecureRandom.getInstance(usePRNG, usePRNGPackage);
+            } else {
+                secureRandom = SecureRandom.getInstance(usePRNG);
+            }
+        } catch (Exception e) {
+            // Fall back to default SecureRandom
+            secureRandom = new SecureRandom();
+        }
+        // Can not do that in a static initializer block, because
+        // threads are not started after the initializer block exits
+        Thread t = new Thread() {
+            public void run() {
+                // Seed it with 32 bytes. May be slow on some systems,
+                // see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6202721
+                byte[] seed = secureRandom.generateSeed(32);
+                secureRandom.setSeed(seed);
+                secureRandomSeeded = true;
+            }
+        };
+        secureRandomSeeded = false;
+        t.start();
+        try {
+            t.join(MAX_SEED_TIME);
+        } catch (InterruptedException e) {
+            // ignore
+        }
+        if (!secureRandomSeeded) {
+            // Alternative seed algorithm if the default is very slow
+            secureRandom.setSeed(System.currentTimeMillis());
+            // Thread timing (a second thread is already running)
+            for (int j = 0; j < 16; j++) {
+                int i = 0;
+                long start = System.currentTimeMillis();
+                while (start == System.currentTimeMillis()) {
+                    i++;
+                }
+                // Supplement the existing seed
+                secureRandom.setSeed(i);
+            }
+        }
+    }
 
     /**
      * <p>Returns a new version four UUID using either <code>SecureRandom</code>
or <code>Random</code>.</p>
@@ -112,24 +176,9 @@
     private UUID nextUUID(boolean secure) {
         byte[] raw = new byte[UUID_BYTE_LENGTH];
         if (secure) {
-            //Initialize the secure random if null.
-            if (secureRandom == null) {
-                try {
-                    if (usePRNGPackage != null) {
-                        secureRandom = SecureRandom.getInstance(usePRNG, usePRNGPackage);
-                    } else {
-                        secureRandom = SecureRandom.getInstance(usePRNG);
-                    }
-                } catch (NoSuchAlgorithmException nsae) {
-                    secure = false; //Fail back to default PRNG/Random
-                } catch (NoSuchProviderException nspe) {
-                    secure = false; //Fail back to default PRNG/Random
-                }
-                secureRandom.nextBytes(raw);
-            }
-        }
-
-        if (!secure) {
+            initSecureRandom();
+            secureRandom.nextBytes(raw);
+        } else {
             regularRandom.nextBytes(raw);
         }
 

Modified: jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/util/TestAll.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/util/TestAll.java?rev=594470&r1=594469&r2=594470&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/util/TestAll.java
(original)
+++ jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/util/TestAll.java
Tue Nov 13 02:26:18 2007
@@ -37,6 +37,7 @@
 
         suite.addTestSuite(ISO9075Test.class);
         suite.addTestSuite(TextTest.class);
+        suite.addTestSuite(UUIDTest.class);
 
         return suite;
     }

Added: jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/util/UUIDTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/util/UUIDTest.java?rev=594470&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/util/UUIDTest.java
(added)
+++ jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/util/UUIDTest.java
Tue Nov 13 02:26:18 2007
@@ -0,0 +1,47 @@
+package org.apache.jackrabbit.util;
+
+import org.apache.jackrabbit.uuid.UUID;
+import org.apache.jackrabbit.uuid.VersionFourGenerator;
+
+import junit.framework.TestCase;
+
+/**
+ * Test the Version 4 (random), Leach-Salz UUID generation.
+ * 
+ * @author Thomas Mueller
+ */
+public class UUIDTest extends TestCase {
+    
+    public void testUUID() {
+        UUID uuid1 = UUID.randomUUID();
+        checkUUIDFormat(uuid1);
+        long maxHigh = 0, maxLow = 0, minHigh = -1L, minLow = -1L;
+        for (int i = 0; i < 100; i++) {
+            UUID uuid = UUID.randomUUID();
+            maxHigh |= uuid.getMostSignificantBits();
+            maxLow |= uuid.getLeastSignificantBits();
+            minHigh &= uuid.getMostSignificantBits();
+            minLow &= uuid.getLeastSignificantBits();
+        }
+        UUID max = new UUID(maxHigh, maxLow);
+        assertEquals(max.toString(), "ffffffff-ffff-4fff-bfff-ffffffffffff");
+        UUID min = new UUID(minHigh, minLow);
+        assertEquals(min.toString(), "00000000-0000-4000-8000-000000000000");
+        
+        // test with a wrong provider
+        // must fall back to the default
+        VersionFourGenerator.setPRNGProvider("wrong", "wrong");
+        UUID uuid2 = UUID.randomUUID();
+        checkUUIDFormat(uuid2);
+    }
+    
+    private void checkUUIDFormat(UUID uuid) {
+        long high = uuid.getMostSignificantBits();
+        long low = uuid.getLeastSignificantBits();
+        long high2 = (high & (~0xf000L)) | 0x4000L; // version 4 (random)
+        assertEquals(high, high2);
+        long low2 = (low & 0x3fffffffffffffffL) | 0x8000000000000000L; // variant (Leach-Salz)
+        assertEquals(low, low2);
+    }
+
+}

Propchange: jackrabbit/trunk/jackrabbit-jcr-commons/src/test/java/org/apache/jackrabbit/util/UUIDTest.java
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message