You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ws.apache.org by ve...@apache.org on 2011/06/23 20:21:15 UTC
svn commit: r1139027 - in
/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util:
UIDGenerator.java UIDGeneratorImpl.java
Author: veithen
Date: Thu Jun 23 18:21:15 2011
New Revision: 1139027
URL: http://svn.apache.org/viewvc?rev=1139027&view=rev
Log:
AXIOM-354: Refactored UIDGenerator to avoid a class loader leak.
Removed:
webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/UIDGeneratorImpl.java
Modified:
webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/UIDGenerator.java
Modified: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/UIDGenerator.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/UIDGenerator.java?rev=1139027&r1=1139026&r2=1139027&view=diff
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/UIDGenerator.java (original)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/util/UIDGenerator.java Thu Jun 23 18:21:15 2011
@@ -21,20 +21,97 @@ package org.apache.axiom.util;
import java.net.URI;
import java.net.URISyntaxException;
+import java.util.Random;
import java.util.UUID;
/**
* Contains utility methods to generate unique IDs of various kinds.
+ * <p>
+ * Depending on the requested type of ID, this class will either use
+ * {@link UUID#randomUUID()} or its own unique ID generator. This implementation
+ * generates unique IDs based on the assumption that the following triplet is
+ * unique:
+ * <ol>
+ * <li>The thread ID.
+ * <li>The timestamp in milliseconds when the first UID is requested by the
+ * thread.
+ * <li>A per thread sequence number that is incremented each time a UID is
+ * requested by the thread.
+ * </ol>
+ * <p>
+ * Considering that these three numbers are represented as <code>long</code>
+ * values, these assumptions are correct because:
+ * <ul>
+ * <li>The probability that two different threads with the same ID exist in the
+ * same millisecond interval is negligibly small.
+ * <li>One can expect that no thread will ever request more than 2^64 UIDs
+ * during its lifetime.
+ * </ul>
+ * <p>
+ * Before building an ID from this triplet, the implementation will XOR the
+ * three values with random values calculated once when the class is loaded.
+ * This transformation preserves the uniqueness of the calculated triplet and
+ * serves several purposes:
+ * <ul>
+ * <li>It reduces the probability that the same ID is produces by two different
+ * systems, i.e. it increases global uniqueness.
+ * <li>It adds entropy, i.e. it makes an individual ID appear as random. Indeed,
+ * without the XOR transformation, a hexadecimal representation of the triplet
+ * would in general contain several sequences of '0'.
+ * <li>It prevents the implementation from leaking information about the system
+ * state.
+ * </ul>
*/
public final class UIDGenerator {
- private static final ThreadLocal impl = new ThreadLocal() {
+ private static final long startTimeXorOperand;
+ private static final long threadIdXorOperand;
+ private static final long seqXorOperand;
+
+ static {
+ Random rand = new Random();
+ threadIdXorOperand = rand.nextLong();
+ startTimeXorOperand = rand.nextLong();
+ seqXorOperand = rand.nextLong();
+ }
+
+ /**
+ * Thread local that holds the triplet described in the Javadoc of this
+ * class. Note that we use a simple array here (instead of our own class)
+ * to avoid class loader leaks (see AXIOM-354).
+ */
+ private static final ThreadLocal/*<long[]>*/ triplet = new ThreadLocal() {
protected Object initialValue() {
- return new UIDGeneratorImpl();
+ long[] values = new long[3];
+ values[0] = Thread.currentThread().getId() ^ threadIdXorOperand;
+ values[1] = System.currentTimeMillis() ^ startTimeXorOperand;
+ return values;
}
};
private UIDGenerator() {}
+ private static void writeReverseLongHex(long value, StringBuilder buffer) {
+ for (int i=0; i<16; i++) {
+ int n = (int)(value >> (4*i)) & 0xF;
+ buffer.append((char)(n < 10 ? '0' + n : 'a' + n - 10));
+ }
+ }
+
+ /**
+ * Generate a unique ID as hex value and add it to the given buffer. Note
+ * that with respect to the triplet, the order of nibbles is reversed, i.e.
+ * the least significant nibble of the sequence is written first. This makes
+ * comparing two IDs for equality more efficient.
+ *
+ * @param buffer
+ */
+ private static void generateHex(StringBuilder buffer) {
+ long[] values = (long[])triplet.get();
+ writeReverseLongHex(values[2]++ ^ seqXorOperand, buffer);
+ writeReverseLongHex(values[1], buffer);
+ writeReverseLongHex(values[0], buffer);
+ }
+
/**
* Generates a unique ID suitable for usage as a MIME content ID.
* <p>
@@ -65,7 +142,7 @@ public final class UIDGenerator {
*/
public static String generateContentId() {
StringBuilder buffer = new StringBuilder();
- ((UIDGeneratorImpl)impl.get()).generateHex(buffer);
+ generateHex(buffer);
buffer.append("@apache.org");
return buffer.toString();
}
@@ -99,7 +176,7 @@ public final class UIDGenerator {
*/
public static String generateMimeBoundary() {
StringBuilder buffer = new StringBuilder("MIMEBoundary_");
- ((UIDGeneratorImpl)impl.get()).generateHex(buffer);
+ generateHex(buffer);
return buffer.toString();
}
@@ -113,7 +190,7 @@ public final class UIDGenerator {
*/
public static String generateUID() {
StringBuilder buffer = new StringBuilder(48);
- ((UIDGeneratorImpl)impl.get()).generateHex(buffer);
+ generateHex(buffer);
return buffer.toString();
}