View Javadoc

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.juddi.uuidgen;
17  
18  import java.math.BigInteger;
19  import java.util.Random;
20  
21  /***
22   * Used to create new universally unique identifiers or UUID's (sometimes called
23   * GUID's).  UDDI UUID's are allways formmated according to DCE UUID conventions.
24   *
25   * @author Maarten Coene
26   * @author Steve Viens (sviens@apache.org)
27   */
28  public class DefaultUUIDGen implements UUIDGen
29  {
30    private static final BigInteger COUNT_START = new BigInteger("-12219292800000");  // 15 October 1582
31    private static final int CLOCK_SEQUENCE = (new Random()).nextInt(16384);
32    
33    private Random random;
34  
35    /***
36     *
37     */
38    public DefaultUUIDGen()
39    {
40      try {
41        random = new Random();
42        random.setSeed(System.currentTimeMillis());
43      } catch (Exception e) {
44        random = new Random();
45      }
46    }
47  
48    /***
49     *
50     */
51    public String uuidgen()
52    {
53      return nextUUID();
54    }
55  
56    /***
57     *
58     */
59    public String[] uuidgen(int nmbr)
60    {
61      String[] uuids = new String[nmbr];
62  
63      for (int i=0; i<uuids.length; i++)
64        uuids[i] = nextUUID();
65  
66      return uuids;
67    }
68  
69    /***
70     * Creates a new UUID. The algorithm used is described by The Open Group.
71     * See <a href="http://www.opengroup.org/onlinepubs/009629399/apdxa.htm">
72     * Universal Unique Identifier</a> for more details.
73     *
74     * Due to a lack of functionality in Java, a part of the UUID is a secure
75     * random. This results in a long processing time when this method is called
76     * for the first time.
77     */
78    private String nextUUID()
79    {
80      // the number of milliseconds since 1 January 1970
81      BigInteger current = BigInteger.valueOf(System.currentTimeMillis());
82  
83      // the number of milliseconds since 15 October 1582
84      BigInteger countMillis = current.subtract(COUNT_START);
85  
86      // the count of 100-nanosecond intervals since 00:00:00.00 15 October 1582
87      BigInteger count = countMillis.multiply(BigInteger.valueOf(10000));
88  
89      String bitString = count.toString(2);
90      if (bitString.length() < 60)
91      {
92        int nbExtraZeros  = 60 - bitString.length();
93        String extraZeros = new String();
94        for (int i=0; i<nbExtraZeros; i++)
95          extraZeros = extraZeros.concat("0");
96  
97        bitString = extraZeros.concat(bitString);
98      }
99  
100     byte[] bits = bitString.getBytes();
101 
102     // the time_low field
103     byte[] time_low = new byte[32];
104     for (int i=0; i<32; i++)
105       time_low[i] = bits[bits.length - i - 1];
106 
107     // the time_mid field
108     byte[] time_mid = new byte[16];
109     for (int i=0; i<16; i++)
110       time_mid[i] = bits[bits.length - 32 - i - 1];
111 
112     // the time_hi_and_version field
113     byte[] time_hi_and_version = new byte[16];
114     for (int i=0; i<12; i++)
115       time_hi_and_version[i] = bits[bits.length - 48 - i - 1];
116 
117     time_hi_and_version[12] = ((new String("1")).getBytes())[0];
118     time_hi_and_version[13] = ((new String("0")).getBytes())[0];
119     time_hi_and_version[14] = ((new String("0")).getBytes())[0];
120     time_hi_and_version[15] = ((new String("0")).getBytes())[0];
121 
122     // the clock_seq_low field
123     BigInteger clockSequence = BigInteger.valueOf(CLOCK_SEQUENCE);
124     String clockString = clockSequence.toString(2);
125     if (clockString.length() < 14)
126     {
127       int nbExtraZeros  = 14 - bitString.length();
128       String extraZeros = new String();
129       for (int i=0; i<nbExtraZeros; i++)
130         extraZeros = extraZeros.concat("0");
131 
132       clockString = extraZeros.concat(bitString);
133     }
134 
135     byte[] clock_bits = clockString.getBytes();
136     byte[] clock_seq_low = new byte[8];
137     for (int i=0; i<8; i++)
138       clock_seq_low[i] = clock_bits[clock_bits.length - i - 1];
139 
140     // the clock_seq_hi_and_reserved
141     byte[] clock_seq_hi_and_reserved = new byte[8];
142     for (int i=0; i<6; i++)
143       clock_seq_hi_and_reserved[i] = clock_bits[clock_bits.length - 8 - i - 1];
144 
145     clock_seq_hi_and_reserved[6] = ((new String("0")).getBytes())[0];
146     clock_seq_hi_and_reserved[7] = ((new String("1")).getBytes())[0];
147 
148     String timeLow = Long.toHexString((new BigInteger(new String(reverseArray(time_low)), 2)).longValue());
149     if (timeLow.length() < 8)
150     {
151       int nbExtraZeros = 8 - timeLow.length();
152       String extraZeros = new String();
153       for (int i=0; i<nbExtraZeros; i++)
154         extraZeros = extraZeros.concat("0");
155 
156       timeLow = extraZeros.concat(timeLow);
157     }
158 
159     String timeMid = Long.toHexString((new BigInteger(new String(reverseArray(time_mid)), 2)).longValue());
160     if (timeMid.length() < 4)
161     {
162       int nbExtraZeros = 4 - timeMid.length();
163       String extraZeros = new String();
164       for (int i=0; i<nbExtraZeros; i++)
165         extraZeros = extraZeros.concat("0");
166 
167       timeMid = extraZeros.concat(timeMid);
168     }
169 
170     String timeHiAndVersion = Long.toHexString((new BigInteger(new String(reverseArray(time_hi_and_version)), 2)).longValue());
171     if (timeHiAndVersion.length() < 4)
172     {
173       int nbExtraZeros = 4 - timeHiAndVersion.length();
174       String extraZeros = new String();
175       for (int i=0; i<nbExtraZeros; i++)
176         extraZeros = extraZeros.concat("0");
177 
178       timeHiAndVersion = extraZeros.concat(timeHiAndVersion);
179     }
180 
181     String clockSeqHiAndReserved = Long.toHexString((new BigInteger(new String(reverseArray(clock_seq_hi_and_reserved)), 2)).longValue());
182     if (clockSeqHiAndReserved.length() < 2)
183     {
184       int nbExtraZeros = 2 - clockSeqHiAndReserved.length();
185       String extraZeros = new String();
186       for (int i=0; i<nbExtraZeros; i++)
187         extraZeros = extraZeros.concat("0");
188 
189       clockSeqHiAndReserved = extraZeros.concat(clockSeqHiAndReserved);
190     }
191 
192     String clockSeqLow = Long.toHexString((new BigInteger(new String(reverseArray(clock_seq_low)), 2)).longValue());
193     if (clockSeqLow.length() < 2)
194     {
195       int nbExtraZeros = 2 - clockSeqLow.length();
196       String extraZeros = new String();
197       for (int i=0; i<nbExtraZeros; i++)
198         extraZeros = extraZeros.concat("0");
199 
200       clockSeqLow = extraZeros.concat(clockSeqLow);
201     }
202 
203     // problem: the node should be the IEEE 802 ethernet address, but can not
204     // be retrieved in Java yet.
205     // see bug ID 4173528
206     // workaround (also suggested in bug ID 4173528)
207     // If a system wants to generate UUIDs but has no IEE 802 compliant
208     // network card or other source of IEEE 802 addresses, then this section
209     // describes how to generate one.
210     // The ideal solution is to obtain a 47 bit cryptographic quality random
211     // number, and use it as the low 47 bits of the node ID, with the most
212     // significant bit of the first octet of the node ID set to 1. This bit
213     // is the unicast/multicast bit, which will never be set in IEEE 802
214     // addresses obtained from network cards; hence, there can never be a
215     // conflict between UUIDs generated by machines with and without network
216     // cards.
217 
218     long nodeValue = random.nextLong();
219     nodeValue = Math.abs(nodeValue);
220     while (nodeValue > 140737488355328L)
221     {
222       nodeValue = random.nextLong();
223       nodeValue = Math.abs(nodeValue);
224     }
225 
226     BigInteger nodeInt = BigInteger.valueOf(nodeValue);
227     String nodeString = nodeInt.toString(2);
228     if (nodeString.length() < 47)
229     {
230       int nbExtraZeros = 47 - nodeString.length();
231       String extraZeros = new String();
232       for (int i=0; i<nbExtraZeros; i++)
233         extraZeros = extraZeros.concat("0");
234 
235       nodeString = extraZeros.concat(nodeString);
236     }
237 
238     byte[] node_bits = nodeString.getBytes();
239     byte[] node = new byte[48];
240     for (int i=0; i<47; i++)
241       node[i] = node_bits[node_bits.length - i - 1];
242 
243     node[47] = ((new String("1")).getBytes())[0];
244     String theNode = Long.toHexString((new BigInteger(new String(reverseArray(node)), 2)).longValue());
245     if (theNode.length() < 12)
246     {
247       int nbExtraZeros = 12 - theNode.length();
248       String extraZeros = new String();
249       for (int i=0; i<nbExtraZeros; i++)
250         extraZeros = extraZeros.concat("0");
251       theNode = extraZeros.concat(theNode);
252     }
253 
254     String result = timeLow + "-" + timeMid +"-" + timeHiAndVersion + "-" + clockSeqHiAndReserved + clockSeqLow + "-" + theNode;
255 
256     return result.toUpperCase();
257   }
258 
259   /***
260    *
261    */
262   private static byte[] reverseArray(byte[] bits)
263   {
264     byte[] result = new byte[bits.length];
265     for (int i=0; i<result.length; i++)
266       result[i] = bits[result.length - 1 - i];
267 
268     return result;
269   }
270 
271 
272   /****************************************************************************/
273   /****************************** TEST DRIVER *********************************/
274   /****************************************************************************/
275 
276 
277   public static void main(String args[])
278   {
279     DefaultUUIDGen generator = new DefaultUUIDGen();
280 
281     long start = System.currentTimeMillis();
282 
283     for (int i = 1; i <= 100; ++i)
284       generator.uuidgen();
285 
286     long end = System.currentTimeMillis();
287 
288     System.out.println("DefaultUUIDGen: Generation of 100 UUID's took "+(end-start)+" milliseconds.");
289   }
290 }