001: /*
002: * (c) Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
003: * [See end of file]
004: */
005:
006: package com.hp.hpl.jena.shared.uuid;
007:
008: import com.hp.hpl.jena.shared.uuid.JenaUUID.FormatException;
009:
010: /* RFC 4122 "A Universally Unique IDentifier (UUID) URN Namespace"
011: ftp://ftp.rfc-editor.org/in-notes/rfc4122.txt
012: Originally: http://www.opengroup.org/onlinepubs/009629399/apdxa.htm
013:
014: Version 1, variant 2: timebased:
015: 60 bits of time
016: 48 bits of nodeId
017: 12 bits of clock sequence
018: 2 bits variant
019: 4 bits version
020:
021: laid out as:
022:
023: 0 1 2 3
024: 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
025: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
026: | time_low | 8 hex digits
027: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
028: | time_mid | time_hi_and_version | 4-4
029: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
030: |clk_seq_hi_res | clk_seq_low | node (0-1) | 4-
031: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
032: | node (2-5) | 12
033: +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
034:
035: Java5 introduced java.util.UUID but it does not include an timebased generator.
036: It provides an API to manipulate timebased UUIDs, and also factory methods for
037: vversion 4 (random) and version 3 (name based/MD5) or version 5 (name based/SHA1).
038: Version 2 is DCE Security version, with embedded POSIX UIDs.
039:
040: Most significant long:
041:
042: 0xFFFFFFFF00000000 time_low
043: 0x00000000FFFF0000 time_mid
044: 0x000000000000F000 version
045: 0x0000000000000FFF time_hi
046:
047: Least significant long:
048:
049: 0xC000000000000000 variant C = 1100 (base 2)
050: 0x3FFF000000000000 clock_seq 3 = 0011 (base 2)
051: 0x0000FFFFFFFFFFFF node
052:
053: Note on variant: despite the javadoc document, the variant is defined as the
054: top 3 bits of octet 8. But the low bit is a "don't care" in this variant
055: and is used by the clock.
056:
057: */
058:
059: /** Generator for timebased UUIDs (version 1, variant 2)
060: *
061: * @author Andy Seaborne
062: * @version $Id: UUID_V1_Gen.java,v 1.3 2008/01/02 12:06:07 andy_seaborne Exp $
063: */
064:
065: public class UUID_V1_Gen implements UUIDFactory {
066: // Constants
067: static final int versionHere = 1; // Version 1: time-based. This is one character hex string.
068: static final int variantHere = 2; // DCE varient
069:
070: static final long maskTimeLow = 0xFFFFFFFF00000000L;
071: static final long maskTimeMid = 0x00000000FFFF0000L;
072: static final long maskTimeHigh = 0x0000000000000FFFL;
073: static final long maskVersion = 0x000000000000F000L;
074:
075: static final long maskVariant = 0xC000000000000000L;
076: static final long maskClockSeq = 0x3FFF000000000000L;
077: static final long maskNode = 0x0000FFFFFFFFFFFFL;
078:
079: // Generator variables.
080: long gregorianTime = 0;
081: static final long UUIDS_PER_TICK = 100;
082: long uuids_this _tick = UUIDS_PER_TICK + 1; // Force reset first time.
083:
084: // Genrator initial state
085: int clockSeq = 0;
086: private static final int CLOCK_BITS = 8;
087: long node = 0;
088:
089: // Time control
090: private long lastTime = 0;
091: private long DELAY = 10; // Milliseconds
092:
093: public UUID_V1_Gen() {
094: reset();
095: }
096:
097: /** (Re)set the network id (a random number) and the timstamp */
098:
099: public void reset() {
100: setInitialState();
101: setTime();
102: }
103:
104: public JenaUUID generate() {
105: return generateV1();
106: }
107:
108: public UUID_V1 generateV1() {
109:
110: long timestamp = 0;
111: synchronized (this ) {
112: if (uuids_this _tick >= UUIDS_PER_TICK)
113: setTime();
114: timestamp = gregorianTime + uuids_this _tick;
115: uuids_this _tick++;
116: }
117: return generate(timestamp);
118: }
119:
120: /* 8-4-4-4-12 = 32+4 dashes = 36 chars
121:
122: UUID = <time_low> "-" <time_mid> "-"
123: <time_high_and_version> "-"
124: <variant_and_sequence> "-"
125: <node>
126: time_low = 4*<hexOctet>
127: time_mid = 2*<hexOctet>
128: time_high_and_version = 2*<hexOctet>
129: variant_and_sequence = 2*<hexOctet>
130: node = 6*<hexOctet>
131: hexOctet = <hexDigit><hexDigit>
132: */
133:
134: public JenaUUID parse(String s) throws FormatException {
135: s = s.toLowerCase();
136:
137: if (s.length() != 36)
138: throw new FormatException(
139: "UUID string is not 36 chars long: it's "
140: + s.length() + " [" + s + "]");
141:
142: if (s.charAt(8) != '-' && s.charAt(13) != '-'
143: && s.charAt(18) != '-' && s.charAt(23) != '-')
144: throw new FormatException(
145: "String does not have dashes in the right places: "
146: + s);
147:
148: UUID_V1 u = parse$(s);
149: if (u.getVersion() != versionHere)
150: throw new FormatException("Wrong version (Expected: "
151: + versionHere + "Got: " + u.getVersion() + "): "
152: + s);
153: if (u.getVariant() != variantHere)
154: throw new FormatException("Wrong version (Expected: "
155: + variantHere + "Got: " + u.getVariant() + "): "
156: + s);
157: return u;
158: }
159:
160: static UUID_V1 parse$(String s) {
161: // The UUID broken up into parts.
162: // 00000000-0000-0000-0000-000000000000
163: // ^ ^ ^ ^ ^
164: // Byte: 0 4 6 8 10
165: // Char: 0 9 14 19 24 including hyphens
166: int x = (int) Bits.unpack(s, 19, 23);
167: int variant = (int) (x >>> 14);
168: int clockSeq = x & 0x3FFF;
169:
170: long timeHigh = Bits.unpack(s, 15, 18);
171: long timeMid = Bits.unpack(s, 9, 13);
172: long timeLow = Bits.unpack(s, 0, 8);
173:
174: long node = Bits.unpack(s, 24, 36);
175: int version = (int) Bits.unpack(s, 14, 15);
176: return generate(version, variant, timeHigh, timeMid, timeLow,
177: clockSeq, node);
178: }
179:
180: // Easier to have parse and unparse code close together
181: public static String unparse(UUID_V1 uuid) {
182: int _variant = uuid.getVariant(); // (int)((UUID_V1_Gen.maskVariant & uuid.bitsLower)>>>62) ;
183: int _version = uuid.getVersion(); // (int)((UUID_V1_Gen.maskVersion & uuid.bitsUpper)>>>12) ;
184:
185: long timeHigh = uuid.getTimeHigh();
186: long timeMid = uuid.getTimeMid();
187: long timeLow = uuid.getTimeLow();
188:
189: long node = uuid.getNode();
190: long clockSeq = uuid.getClockSequence();
191:
192: StringBuffer sBuff = new StringBuffer();
193: JenaUUID.toHex(sBuff, timeLow, 4);
194: sBuff.append('-');
195: JenaUUID.toHex(sBuff, timeMid, 2);
196: sBuff.append('-');
197: JenaUUID.toHex(sBuff, _version << 12 | timeHigh, 2);
198: sBuff.append('-');
199: JenaUUID.toHex(sBuff, (long) _variant << 14 | clockSeq, 2);
200: sBuff.append('-');
201: JenaUUID.toHex(sBuff, node, 6);
202: return sBuff.toString();
203: }
204:
205: private UUID_V1 generate(long timestamp) {
206: return generate(versionHere, variantHere, timestamp, clockSeq,
207: node);
208: }
209:
210: // Testing.
211: public static UUID_V1 generate(int version, int variant,
212: long timestamp, long clockSeq, long node) {
213: long timeHigh = timestamp >>> (60 - 12); // Top 12 bits of 60 bit number.
214: long timeMid = (timestamp >>> 32) & 0xFFFFL; // 16 bits, bits 32-47
215: long timeLow = timestamp & 0xFFFFFFFFL; // Low 32 bits
216:
217: return generate(version, variant, timeHigh, timeMid, timeLow,
218: clockSeq, node);
219: }
220:
221: private static UUID_V1 generate(int version, int variant,
222: long timeHigh, long timeMid, long timeLow, long clockSeq,
223: long node) {
224: long mostSigBits = (timeLow << 32) | (timeMid << 16)
225: | (versionHere << 12) | timeHigh;
226: long leastSigBits = (long) variantHere << 62
227: | (long) (clockSeq << 48) | node;
228: return new UUID_V1(mostSigBits, leastSigBits);
229: }
230:
231: private void setTime() {
232: long time = 0;
233:
234: // Wait for a clock tick.
235: synchronized (this ) {
236: if (lastTime == 0)
237: lastTime = System.currentTimeMillis();
238:
239: boolean done = false;
240: while (!done) {
241: time = System.currentTimeMillis();
242: if (time < lastTime + DELAY) {
243: // pause for a while to wait for time to change
244: try {
245: Thread.sleep(DELAY);
246: } catch (java.lang.InterruptedException e) {
247: } // ignore exception
248: continue;
249: } else {
250: done = true;
251: }
252: }
253: }
254:
255: // We claim this tick just passed! 1 UUID per 100ns so ...
256: //UUIDS_PER_TICK = (time-lastTime)*10 ;
257: lastTime = time;
258: uuids_this _tick = 0;
259:
260: // Convert to the UUID base time (00:00:00.00, 15 October 1582)
261: // That's the date of the Gregorian calendar reforms
262: // See the text quoted for the number.
263: // Java base time is is January 1, 1970.
264:
265: gregorianTime = time * 10 + 0x01B21DD213814000L;
266: }
267:
268: private void setInitialState() {
269: long random = LibUUID.makeRandom().nextLong();
270:
271: node = Bits.unpack(random, 0, 47); // Low 48bits, except grousp address bit
272: node = Bits.set(node, 47); // Set group address bit
273:
274: // Can also set the clock sequence number to increase the randomness.
275: // Use up to 13 bits for the clock (actually, it's 14 bits as
276: // strays into the variant).
277: // We use less to ge a characteristic "-80??-" in the string
278:
279: clockSeq = 0;
280: if (CLOCK_BITS != 0)
281: clockSeq = (int) Bits.unpack(random, 48, (48 + CLOCK_BITS));
282: }
283: }
284:
285: /*
286: * (c) Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
287: * All rights reserved.
288: *
289: * Redistribution and use in source and binary forms, with or without
290: * modification, are permitted provided that the following conditions
291: * are met:
292: * 1. Redistributions of source code must retain the above copyright
293: * notice, this list of conditions and the following disclaimer.
294: * 2. Redistributions in binary form must reproduce the above copyright
295: * notice, this list of conditions and the following disclaimer in the
296: * documentation and/or other materials provided with the distribution.
297: * 3. The name of the author may not be used to endorse or promote products
298: * derived from this software without specific prior written permission.
299: *
300: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
301: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
302: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
303: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
304: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
305: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
306: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
307: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
308: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
309: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
310: */
|