KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > dotmarketing > util > GUIDGenerator


1 /*
2  * GUIDGenerator.java
3  *
4  * Created on 29 August 2001, 09:41
5  */

6
7 package com.dotmarketing.util;
8
9 import java.net.InetAddress JavaDoc;
10 import java.security.SecureRandom JavaDoc;
11 import java.util.Random JavaDoc;
12
13 /**
14  * This class is from: http://www.activescript.co.uk/
15  * <p>
16  * This GUID generator can be safely pooled on a single machine and deployed in
17  * a cluster to provide completely scalable performance.
18  * </p>
19  * <p>
20  * The problem of generating unique IDs can essentially be broken down as
21  * uniqueness over space and uniqueness over time which, when combined, produces
22  * a globally unique sequence.
23  * </p>
24  * <p>
25  * Taking the UUID and GUID Internet standards draft for the Network Working
26  * Group by Paul J. Leach, Microsoft, and Rich Salz, Certco, as a starting point
27  * we assume that the GUID be represented as a 36-digit alphanumeric (including
28  * hyphens) of the format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
29  * </p>
30  * <p>
31  * The first 20 characters represent the uniqueness over time (the low 32-bits
32  * of the time stamp as the first 8, the next 4 as the mid 16 bits of the time
33  * stamp, the next 4 as the high value of the time stamp multiplexed with the
34  * version, and the next 4 a combination of the lock sequence high -multiplexed
35  * with the variant field - and the low bits)
36  * </p>
37  * <p>
38  * Note: The internet guidelines suggest the timestamp as a 60-bit value to a
39  * precision of 100ns since 00:00:00.00, 15 October 1582 (the date of Gregorian
40  * reform to the Christian calendar)
41  * </p>
42  * <p>
43  * The last 12 characters are a 48-bit node identifier usually implemented as
44  * the IEEE 802 address, which gives uniqueness over space.
45  * </p>
46  * <p>
47  * These are combined to produce a unique sequence. <br>
48  * Some of the main problems in an EJB implementation of this technique are: -
49  * <ul>
50  * <li>1) there is no access to the traditional IEEE 802 address.</li>
51  * <li>2) more than one object can exist at the same time and so generate the
52  * same time stamp at a granularity of a millisecond (Java's timestamp
53  * granularity).</li>
54  * <li> 3) a clock sequence or equivalent is used as a way of reading/writing a
55  * value to storage (e.g. a database or system file) that can be used in case
56  * the clock is set backwards and as a seed for the number sequence. This is
57  * even more of a problem when a cluster of machines do not use the same
58  * database.</li>
59  * <li>4) Singletons are not portable and not recommended in the EJB specs.</li>
60  * </ul>
61  *
62  *
63  * <p>
64  * The GUID is constucted by.
65  * <ul>
66  * <li> 1) (1-8 hex characters) use the low 32 bits of
67  * System.currentTimeMillis(). Note: could use the recommended date format by
68  * adding 12219292800000L to the system time long before grabbing the low 32
69  * bits. <br>
70  * This gives us a uniqueness of a millisecond - therefore any clashing object
71  * will have to be generated within the same millisecond. </li>
72  * <li> 2) (9-16 hex characters) the IP address of the machine as a hex
73  * representation of the 32 bit integer underlying IP - gives us a spatial
74  * uniqueness to a single machine - guarantees that these characters will be
75  * different for machines in a cluster or on a LAN. Note: This is not
76  * appropriate for a global addressing scheme to distinguish java objects in any
77  * JVM on the Internet. </li>
78  * <li> 3) (17-24 hex characters) the hex value of the Stateless Session bean
79  * object's hashCode (a 32 bit int) - in the Java language spec - the hashcode
80  * value of Object is defined as - <I>As much as is reasonably practical, the
81  * hashCode method defined by class object does return distinct integers for
82  * distinct objects. (This is typically implemented by converting the internal
83  * address of the object into an integer, but this implementation technique is
84  * not required by the Java programming language.)</I>** </li>
85  *
86  * <li> 4) (25-32 hex characters) a random 32 bit integer generated for each
87  * method invocation from the SecureRandom java class using
88  * SecureRandom.nextInt(). This method produces a cryptographically strong
89  * pseudo-random integer. The Java lang defines this as - <I>Returns a
90  * pseudo-random, uniformly distributed int value drawn from this random number
91  * generator's sequence. The general contract of nextInt is that one int value
92  * in the specified range is pseudorandomly generated and returned. All n
93  * possible int values are produced with (approximately) equal probability.</I>**
94  * </li>
95  * </ul>
96  * <p>
97  * This gives us a value that is a combination of
98  * <ul>
99  * <li> 1) is unique to the millisecond</li>
100  * <li>2) is unique to the machine</li>
101  * <li>3) is unique to the object creating it</li>
102  * <li>4) is unique to the method call for the same object</li>
103  * </ul>
104  * <p>
105  * Note: the potential theoretical conflicts are:
106  * <ul>
107  * <li>1) that two objects on the same machine are assigned the exact same
108  * hashCode (I do not know of any implementations that do this but there may be
109  * some out there) and at the same millisecond must also get the same integer
110  * value from the SecureRandom implementation.</li>
111  * <li>2) The same int value is returned from the SecureRandom object in
112  * subsequent method calls for the same object in the same millisecond.</li>
113  * <li>3) A reset clock (which would require a redeployment of the bean) will
114  * produce an identical hashcode for the new deployment as a previous one AND
115  * the random values will have to be the same in the same repeated millisecond
116  * value as in a previous sequence. </li>
117  * </ul>
118  *
119  * @author Steve Woodcock
120  * @version 1.1
121  */

122 public class GUIDGenerator {
123
124     /** Creates new GUIDGenerator */
125     public GUIDGenerator() throws Exception JavaDoc {
126
127         try {
128             StringBuffer JavaDoc stringbuffer = new StringBuffer JavaDoc();
129             StringBuffer JavaDoc stringbuffer1 = new StringBuffer JavaDoc();
130             seeder = new SecureRandom JavaDoc();
131             InetAddress JavaDoc inetaddress = InetAddress.getLocalHost();
132             byte abyte0[] = inetaddress.getAddress();
133             String JavaDoc s = hexFormat(getInt(abyte0), 8);
134             String JavaDoc s1 = hexFormat(hashCode(), 8);
135             stringbuffer.append("-");
136             stringbuffer1.append(s.substring(0, 4));
137             stringbuffer.append(s.substring(0, 4));
138             stringbuffer.append("-");
139             stringbuffer1.append(s.substring(4));
140             stringbuffer.append(s.substring(4));
141             stringbuffer.append("-");
142             stringbuffer1.append(s1.substring(0, 4));
143             stringbuffer.append(s1.substring(0, 4));
144             stringbuffer.append("-");
145             stringbuffer1.append(s1.substring(4));
146             stringbuffer.append(s1.substring(4));
147             midValue = stringbuffer.toString();
148             midValueUnformated = stringbuffer1.toString();
149             int i = seeder.nextInt();
150         } catch (Exception JavaDoc exception) {
151             throw new Exception JavaDoc("error - failure to instantiate GUIDGenerator" + exception);
152         }
153     }
154
155     /**
156      * <p>
157      * The private method that actually does the work. The String passed into
158      * the method is either the formatted or unformatted mid value which is
159      * combined with the low 32 bits (obtained by a bit wise &) of the time and
160      * the next value in the secureRandom sequence.
161      * </p>
162      *
163      * @param s
164      * The string containing the mid value of the required format for
165      * the UUID.
166      * @return A string containing the UUID in the desired format.
167      *
168      */

169     private String JavaDoc getVal(String JavaDoc s) {
170         int i = (int) System.currentTimeMillis() & 0xffffffff;
171         int j = seeder.nextInt();
172         return hexFormat(i, 8) + s + hexFormat(j, 8);
173     }
174
175     /**
176      * <p>
177      * Used to provide a UUID that does not conform to the GUID RFC. The String
178      * returned does not have the xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
179      * instead it is xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx. This is to provide a
180      * shorter version of the UUID for easier database manipulation.
181      * </p>
182      * <p>
183      * However, it is recommended that th full format be used.
184      * </P>
185      *
186      * @throws RemoteException
187      * Required to be thrown by the EJB specification.
188      * @return A String representing a UUID in the format
189      * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx. Each character in the string is
190      * a hexadecimal.
191      */

192     public String JavaDoc getUnformatedUUID() {
193         return getVal(midValueUnformated);
194     }
195
196     /**
197      * <p>
198      * Returns a UUID formated according to the draft internet standard. See the
199      * class level documentation for more details.
200      * </P>
201      *
202      * @return A String representing a UUID in the format
203      * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
204      */

205     public String JavaDoc getUUID() {
206         return getVal(midValue);
207     }
208
209     /**
210      * <p>
211      * A utility method to take a byte array of 4 bytes and produce an int
212      * value. This is used to convert the quad xxx.xxx.xxx.xxx value of the IP
213      * address to the underlying 32-bit int that the ip address represents.
214      * There is no way to obtain this value in Java so we need to convert it
215      * ourselves. </P
216      *
217      * @param abyte0
218      * Th byte array containg 4 bytes that represent an IP address.
219      * @return An int that is the actual value of the ip address.
220      */

221     private int getInt(byte abyte0[]) {
222         int i = 0;
223         int j = 24;
224         for (int k = 0; j >= 0; k++) {
225             int l = abyte0[k] & 0xff;
226             i += l << j;
227             j -= 8;
228         }
229
230         return i;
231     }
232
233     /**
234      * <p>
235      * A utility method to produce a correctly formatted hex string string from
236      * an int value and and an int specifying the length the hex string that
237      * represents the int value should be.
238      * </p>
239      * <p>
240      * Utilises both the padHex and toHexString methods.
241      * </p>
242      *
243      * @param i
244      * The int value that is to be transformed to a hex string.
245      * @param j
246      * An int specifying the length of the hex string to be returned.
247      * @return A string that contains the formatted hex string.
248      */

249     private String JavaDoc hexFormat(int i, int j) {
250         String JavaDoc s = Integer.toHexString(i);
251         return padHex(s, j) + s;
252     }
253
254     /**
255      * <p>
256      * A utility method that takes in a string of hex characters and prepends a
257      * number characters to the string to make up a string of the required
258      * length as defined in the int value passed into the method. This is
259      * because the values for say the hashcode on a lower memory machine will
260      * only be 4 characters long and so to the correct formatting is produced 0
261      * characters must be prepended to the fornt of the string.
262      * <p>
263      *
264      * @param s
265      * The String containing the hex values.
266      * @param i
267      * The int specifying the length that the string should be.
268      * @return A String of the correct length containing the original hex value
269      * and a number of pad zeros at the front of the string.
270      */

271     private String JavaDoc padHex(String JavaDoc s, int i) {
272         StringBuffer JavaDoc stringbuffer = new StringBuffer JavaDoc();
273         if (s.length() < i) {
274             for (int j = 0; j < i - s.length(); j++)
275                 stringbuffer.append("0");
276
277         }
278         return stringbuffer.toString();
279     }
280
281     /**
282      * <p>
283      * The random seed used in the method call to provide the required
284      * randomized element. The normal random class is not used as the sequences
285      * produced are more uniform than this implementation and will produce a
286      * predictable sequence which could lead to a greater chance of number
287      * clashes.
288      * <p>
289      */

290     private SecureRandom JavaDoc seeder;
291
292     /**
293      * <p>
294      * The cached mid value of the UUID. This consists of the hexadecimal
295      * version of the IP address of the machine and the object's hashcode. These
296      * are stored as -xxxx-xxxx-xxxx-xxxx to speed up the method calls. This
297      * value does not change over the lifespan of the object and so is able to
298      * be cached in this manner.
299      * <p>
300      */

301     private String JavaDoc midValue;
302
303     /**
304      * <p>
305      * The unformatted cached mid value of the UUID. This consists of the
306      * hexadecimal version of the IP address of the machine and the object's
307      * hashcode. These are stored as xxxxxxxxxxxxxxxx to speed up the method
308      * calls. This value does not change over the lifespan of the object and so
309      * is able to be cached in this manner. This vlaue is used to supply the
310      * middle part of the UUID for the unformatted method.
311      * <p>
312      */

313     private String JavaDoc midValueUnformated;
314 }
315
Popular Tags