jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ju...@apache.org
Subject svn commit: r793180 - in /jackrabbit/trunk/jackrabbit-core/src: main/java/org/apache/jackrabbit/core/id/ test/java/org/apache/jackrabbit/core/id/
Date Sat, 11 Jul 2009 15:17:01 GMT
Author: jukka
Date: Sat Jul 11 15:17:01 2009
New Revision: 793180

URL: http://svn.apache.org/viewvc?rev=793180&view=rev
Log:
JCR-1232: Merge UUID to NodeId

Merged all remaining UUID functionality to NodeId.

Added:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/id/SeededSecureRandom.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/id/
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/id/NodeIdTest.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/id/TestAll.java
Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/id/NodeId.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/id/NodeId.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/id/NodeId.java?rev=793180&r1=793179&r2=793180&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/id/NodeId.java
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/id/NodeId.java
Sat Jul 11 15:17:01 2009
@@ -16,85 +16,224 @@
  */
 package org.apache.jackrabbit.core.id;
 
-import org.apache.jackrabbit.uuid.UUID;
+import java.util.Random;
+import java.util.UUID;
 
 /**
- * Node identifier. An instance of this class identifies a node using its UUID.
- * Once created a node identifier instance is immutable.
+ * Node identifier, i.e. an immutable 128 bit UUID.
  */
-public class NodeId extends UUID implements ItemId {
+public class NodeId implements ItemId, Comparable<NodeId> {
 
     /**
      * The serial version UID.
      */
-    private static final long serialVersionUID = 7348217305215708805L;
+    private static final long serialVersionUID = 5773949574212570258L;
 
     /**
-     * Creates a new randomly generated node identifier.
+     * Returns a node identifier that is represented by the given UUID string.
+     *
+     * @param uuid the UUID string
+     * @return the node identifier
+     * @throws IllegalArgumentException if the given string is <code>null</code>
+     *                                  or not a valid UUID
+     */
+    public static NodeId valueOf(String uuid) throws IllegalArgumentException {
+        if (uuid != null) {
+            return new NodeId(uuid);
+        } else {
+            throw new IllegalArgumentException("NodeId.valueOf(null)");
+        }
+    }
+
+    /**
+     * The most significant 64 bits (bytes 0-7) of the UUID.
      */
-    public NodeId() {
-        this(UUID.randomUUID());
+    private final long msb;
+
+    /**
+     * The least significant 64 bits (bytes 8-15) of the UUID.
+     */
+    private final long lsb;
+
+    /**
+     * Creates a node identifier from the given 128 bits.
+     *
+     * @param msb most significant 64 bits
+     * @param lsb least significant 64 bits
+     */
+    public NodeId(long msb, long lsb) {
+        this.msb = msb;
+        this.lsb = lsb;
     }
 
-    private NodeId(UUID uuid) {
-        super(uuid.getMostSignificantBits(), uuid.getLeastSignificantBits());
+    /**
+     * Creates a node identifier from the given 16 bytes.
+     *
+     * @param bytes array of 16 bytes
+     * @throws NullPointerException if the given array is <code>null</code>
+     * @throws ArrayIndexOutOfBoundsException
+     *             if the given array is less than 16 bytes long
+     */
+    public NodeId(byte[] bytes)
+            throws NullPointerException, ArrayIndexOutOfBoundsException {
+        this(   // Most significant 64 bits
+                ((((long) bytes[0]) & 0xFF) << 56)
+                + ((((long) bytes[1]) & 0xFF) << 48)
+                + ((((long) bytes[2]) & 0xFF) << 40)
+                + ((((long) bytes[3]) & 0xFF) << 32)
+                + ((((long) bytes[4]) & 0xFF) << 24)
+                + ((((long) bytes[5]) & 0xFF) << 16)
+                + ((((long) bytes[6]) & 0xFF) << 8)
+                + ((((long) bytes[7]) & 0xFF)),
+                // Least significant 64 bits
+                ((((long) bytes[8]) & 0xFF) << 56)
+                + ((((long) bytes[9]) & 0xFF) << 48)
+                + ((((long) bytes[10]) & 0xFF) << 40)
+                + ((((long) bytes[11]) & 0xFF) << 32)
+                + ((((long) bytes[12]) & 0xFF) << 24)
+                + ((((long) bytes[13]) & 0xFF) << 16)
+                + ((((long) bytes[14]) & 0xFF) << 8)
+                + ((((long) bytes[15]) & 0xFF)));
+    }
+
+    /**
+     * Creates a node identifier from the given UUID.
+     *
+     * @param uuid UUID
+     */
+    public NodeId(UUID uuid) {
+        this(uuid.getMostSignificantBits(), uuid.getLeastSignificantBits());
     }
 
     /**
      * Creates a node identifier from the given UUID string.
      *
+     * @see UUID#fromString(String)
      * @param uuid UUID string
      * @throws IllegalArgumentException if the UUID string is invalid
      */
     public NodeId(String uuid) throws IllegalArgumentException {
-        super(uuid);
+        this(UUID.fromString(uuid));
     }
 
-    public NodeId(byte[] bytes) {
-        super(bytes);
+    /**
+     * Creates a node identifier using the given random number generator.
+     *
+     * @param random random number generator
+     */
+    public NodeId(Random random) {
+        this(   // Most significant 64 bits, with version field set to 4
+                random.nextLong() & 0xFfffFfffFfff0fffL | 0x0000000000004000L,
+                // Least significant 64 bits, with variant field set to IETF
+                random.nextLong() & 0x3fffFfffFfffFfffL | 0x8000000000000000L);
     }
 
-    public NodeId(long msb, long lsb) {
-        super(msb, lsb);
+    /**
+     * Creates a random node identifier using a secure random number generator.
+     */
+    public NodeId() {
+        this(SeededSecureRandom.getInstance());
     }
 
     /**
-     * Returns <code>true</code> as this class represents a node identifier,
-     * not a property identifier.
+     * Returns the 64 most significant bits of this identifier.
+     *
+     * @return 64 most significant bits
+     */
+    public long getMostSignificantBits() {
+        return msb;
+    }
+
+    /**
+     * Returns the 64 least significant bits of this identifier.
+     *
+     * @return 64 least significant bits
+     */
+    public long getLeastSignificantBits() {
+        return lsb;
+    }
+
+    /**
+     * Returns the 16 bytes of this identifier.
+     *
+     * @return newly allocated array of 16 bytes
+     */
+    public byte[] getRawBytes() {
+        return new byte[] {
+            (byte) (msb >> 56), (byte) (msb >> 48), (byte) (msb >> 40),
+            (byte) (msb >> 32), (byte) (msb >> 24), (byte) (msb >> 16),
+            (byte) (msb >> 8), (byte) msb,
+            (byte) (lsb >> 56), (byte) (lsb >> 48), (byte) (lsb >> 40),
+            (byte) (lsb >> 32), (byte) (lsb >> 24), (byte) (lsb >> 16),
+            (byte) (lsb >> 8), (byte) lsb
+        };
+    }
+
+    //--------------------------------------------------------------< ItemId >
+
+    /**
+     * Returns <code>true</code> to indicate that this is a node identifier.
      *
      * @return always <code>true</code>
-     * @see ItemId#denotesNode()
      */
     public boolean denotesNode() {
         return true;
     }
 
+    //----------------------------------------------------------< Comparable >
+
+    /**
+     * Compares this identifier to the given other one.
+     *
+     * @param that other identifier
+     * @return -1, 0 or +1 if this identifier is less than, equal to,
+     *         or greater than the given other identifier
+     */
+    public int compareTo(NodeId that) {
+        // This is not a 128 bit integer comparison! See also JCR-687.
+        if (msb < that.msb) {
+            return -1;
+        } else if (msb > that.msb) {
+            return 1;
+        } else if (lsb < that.lsb) {
+            return -1;
+        } else if (lsb > that.lsb) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    //--------------------------------------------------------------< Object >
+
     /**
-     * Returns the UUID of the identified node.
+     * Returns the UUID string representation of this identifier.
      *
-     * @return node UUID
+     * @see UUID#toString()
+     * @return UUID string
      */
-    public UUID getUUID() {
-        return this;
+    public String toString() {
+        return new UUID(msb, lsb).toString();
     }
 
     /**
-     * Returns a <code>NodeId</code> holding the value of the specified
-     * string. The string must be in the format returned by the
-     * <code>NodeId.toString()</code> method.
+     * Compares two UUID for equality.
      *
-     * @param s a <code>String</code> containing the <code>NodeId</code>
-     *          representation to be parsed.
-     * @return the <code>NodeId</code> represented by the argument
-     * @throws IllegalArgumentException if the specified string can not be parsed
-     *                                  as a <code>NodeId</code>.
-     * @see #toString()
+     * @see Object#equals(Object)
      */
-    public static NodeId valueOf(String s) throws IllegalArgumentException {
-        if (s == null) {
-            throw new IllegalArgumentException("invalid NodeId literal");
-        }
-        return new NodeId(s);
+    public boolean equals(Object that) {
+        return that instanceof NodeId
+            && msb == ((NodeId) that).msb
+            && lsb == ((NodeId) that).lsb;
+    }
+
+    /**
+     * Returns a hash code of this identifier.
+     *
+     * @return hash code
+     */
+    public int hashCode() {
+        return (int) ((msb >>> 32) ^ msb ^ (lsb >>> 32) ^ lsb);
     }
 
 }

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/id/SeededSecureRandom.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/id/SeededSecureRandom.java?rev=793180&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/id/SeededSecureRandom.java
(added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/id/SeededSecureRandom.java
Sat Jul 11 15:17:01 2009
@@ -0,0 +1,98 @@
+/*
+ * 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 org.apache.jackrabbit.core.id;
+
+import java.security.SecureRandom;
+import java.util.Random;
+
+/**
+ * Automatically seeded singleton secure random number generator.
+ *
+ * @see <a href="https://issues.apache.org/jira/browse/JCR-1206">JCR-1206</a>:
+ *      UUID generation: SecureRandom should be used by default
+ */
+class SeededSecureRandom extends SecureRandom implements Runnable {
+
+    /**
+     * Maximum number of milliseconds to wait for the seeding.
+     */
+    private static final int MAX_SEED_TIME = 1000;
+
+    /**
+     * Singleton instance of this class. Initialized when first accessed.
+     */
+    private static volatile Random instance = null;
+
+    /**
+     * Returns the singleton instance of this class. The instance is
+     * created and seeded when this method is first called.
+     *
+     * @return seeded secure random number generator
+     */
+    public static Random getInstance() {
+        if (instance == null) {
+            instance = new SeededSecureRandom();
+        }
+        return instance;
+    }
+
+    /**
+     * Flag to indicate whether seeding is complete.
+     */
+    private volatile boolean seeded = false;
+
+    /**
+     * Creates and seeds a secure random number generator.
+     */
+    private SeededSecureRandom() {
+        // Can not do that in a static initializer block, because
+        // threads are not started after the initializer block exits
+        Thread thread = new Thread(this, "SeededSecureRandom");
+        thread.start();
+        try {
+            thread.join(MAX_SEED_TIME);
+        } catch (InterruptedException e) {
+            // ignore
+        }
+
+        if (!seeded) {
+            // Alternative seed algorithm if the default is very slow
+            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
+                setSeed(i);
+            }
+        }
+    }
+
+    /**
+     * Seeds this random number generator with 32 bytes of random data.
+     * Run in an initializer thread as this may be slow on some systems, see
+     * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6202721.
+     */
+    public void run() {
+        setSeed(generateSeed(32));
+        seeded = true;
+    }
+
+}

Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/id/NodeIdTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/id/NodeIdTest.java?rev=793180&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/id/NodeIdTest.java
(added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/id/NodeIdTest.java
Sat Jul 11 15:17:01 2009
@@ -0,0 +1,81 @@
+/*
+ * 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 org.apache.jackrabbit.core.id;
+
+import junit.framework.TestCase;
+
+public class NodeIdTest extends TestCase {
+
+    private static final NodeId[] ids = {
+        new NodeId(), // random id
+        new NodeId(0, 0),
+        new NodeId(-1, -1),
+        new NodeId("cafebabe-cafe-babe-cafe-babecafebabe")
+    };
+
+    public void testDenotesNode() {
+        for (NodeId id : ids) {
+            assertTrue(id.denotesNode());
+        }
+    }
+
+    public void testGetMostAndLeastSignificantBits() {
+        for (NodeId id : ids) {
+            long msb = id.getMostSignificantBits();
+            long lsb = id.getLeastSignificantBits();
+            assertEquals(id, new NodeId(msb, lsb));
+        }
+    }
+
+    public void testGetRawBytes() {
+        for (NodeId id : ids) {
+            assertEquals(id, new NodeId(id.getRawBytes()));
+        }
+    }
+
+    public void testToString() {
+        for (NodeId id : ids) {
+            assertEquals(id, new NodeId(id.toString()));
+        }
+    }
+
+    public void testCompareTo() {
+        for (NodeId id : ids) {
+            assertEquals(0, id.compareTo(id));
+        }
+
+        NodeId[] ordered = {
+                new NodeId(-1, -1),
+                new NodeId(-1, 0),
+                new NodeId(0, -1),
+                new NodeId(0, 0),
+                new NodeId(0, 1),
+                new NodeId(1, 0),
+                new NodeId(1, 1)
+        };
+        for (int i = 0; i < ordered.length; i++) {
+            for (int j = 0; j < i; j++) {
+                assertEquals(1, ordered[i].compareTo(ordered[j]));
+            }
+            assertEquals(0, ordered[i].compareTo(ordered[i]));
+            for (int j = i + 1; j < ordered.length; j++) {
+                assertEquals(-1, ordered[i].compareTo(ordered[j]));
+            }
+        }
+    }
+
+}

Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/id/TestAll.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/id/TestAll.java?rev=793180&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/id/TestAll.java
(added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/id/TestAll.java
Sat Jul 11 15:17:01 2009
@@ -0,0 +1,38 @@
+/*
+ * 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 org.apache.jackrabbit.core.id;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * Test suite that includes all test cases for the id module.
+ */
+public class TestAll extends TestCase {
+
+    /**
+     * Returns a test suite that executes all tests inside this package.
+     *
+     * @return a test suite that executes all tests inside this package
+     */
+    public static Test suite() {
+        TestSuite suite = new TestSuite("Identifier tests");
+        suite.addTestSuite(NodeIdTest.class);
+        return suite;
+    }
+}



Mime
View raw message