Source code: org/apache/axis/components/uuid/FastUUIDGen.java
1 /*
2 * Copyright 2001-2004 The Apache Software Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.axis.components.uuid;
17
18 import java.util.Random;
19 import java.security.SecureRandom;
20
21 /**
22 * Creates time-based UUID's. See the <a href="http://www.ietf.org/internet-drafts/draft-mealling-uuid-urn-03.txt">UUID Internet Draft</a> for details.
23 *
24 * @author Jarek Gawor (gawor@apache.org)
25 */
26 public class FastUUIDGen implements UUIDGen {
27
28 private static Random secureRandom;
29
30 private static String nodeStr;
31 private static int clockSequence;
32
33 private long lastTime = 0;
34
35 static {
36 // problem: the node should be the IEEE 802 ethernet address, but can not
37 // be retrieved in Java yet.
38 // see bug ID 4173528
39 // workaround (also suggested in bug ID 4173528)
40 // If a system wants to generate UUIDs but has no IEE 802 compliant
41 // network card or other source of IEEE 802 addresses, then this section
42 // describes how to generate one.
43 // The ideal solution is to obtain a 47 bit cryptographic quality random
44 // number, and use it as the low 47 bits of the node ID, with the most
45 // significant bit of the first octet of the node ID set to 1. This bit
46 // is the unicast/multicast bit, which will never be set in IEEE 802
47 // addresses obtained from network cards; hence, there can never be a
48 // conflict between UUIDs generated by machines with and without network
49 // cards.
50 try {
51 secureRandom = SecureRandom.getInstance("SHA1PRNG", "SUN");
52 } catch (Exception e) {
53 secureRandom = new Random();
54 }
55
56 nodeStr = getNodeHexValue();
57 clockSequence = getClockSequence();
58 }
59
60 private static String getNodeHexValue() {
61 long node = 0;
62 long nodeValue = 0;
63 while ( (node = getBitsValue(nodeValue, 47, 47)) == 0 ) {
64 nodeValue = secureRandom.nextLong();
65 }
66 node = node | 0x800000000000L;
67 return leftZeroPadString(Long.toHexString(node), 12);
68 }
69
70 private static int getClockSequence() {
71 return secureRandom.nextInt(16384);
72 }
73
74 public String nextUUID() {
75 long time = System.currentTimeMillis();
76
77 long timestamp = time * 10000;
78 timestamp += 0x01b21dd2L << 32;
79 timestamp += 0x13814000;
80
81 synchronized(this) {
82 if (time - lastTime <= 0) {
83 clockSequence = ((clockSequence + 1) & 16383);
84 }
85 lastTime = time;
86 }
87
88 long timeLow = getBitsValue(timestamp, 32, 32);
89 long timeMid = getBitsValue(timestamp, 48, 16);
90 long timeHi = getBitsValue(timestamp, 64, 16) | 0x1000;
91
92 long clockSeqLow = getBitsValue(clockSequence, 8, 8);
93 long clockSeqHi = getBitsValue(clockSequence, 16, 8) | 0x80;
94
95 String timeLowStr = leftZeroPadString(Long.toHexString(timeLow), 8);
96 String timeMidStr = leftZeroPadString(Long.toHexString(timeMid), 4);
97 String timeHiStr = leftZeroPadString(Long.toHexString(timeHi), 4);
98
99 String clockSeqHiStr = leftZeroPadString(Long.toHexString(clockSeqHi), 2);
100 String clockSeqLowStr = leftZeroPadString(Long.toHexString(clockSeqLow), 2);
101
102 StringBuffer result = new StringBuffer(36);
103 result.append(timeLowStr).append("-");
104 result.append(timeMidStr).append("-");
105 result.append(timeHiStr).append("-");
106 result.append(clockSeqHiStr).append(clockSeqLowStr);
107 result.append("-").append(nodeStr);
108
109 return result.toString();
110 }
111
112 private static long getBitsValue(long value, int startBit, int bitLen) {
113 return ((value << (64-startBit)) >>> (64-bitLen));
114 }
115
116 private static final String leftZeroPadString(String bitString, int len) {
117 if (bitString.length() < len) {
118 int nbExtraZeros = len - bitString.length();
119 StringBuffer extraZeros = new StringBuffer();
120 for (int i = 0; i < nbExtraZeros; i++) {
121 extraZeros.append("0");
122 }
123 extraZeros.append(bitString);
124 bitString = extraZeros.toString();
125 }
126 return bitString;
127 }
128
129 }