001: /*
002: * ====================================================================
003: * Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
004: *
005: * This software is licensed as described in the file COPYING, which
006: * you should have received as part of this distribution. The terms
007: * are also available at http://svnkit.com/license.html
008: * If newer versions of this license are posted there, you may use a
009: * newer version instead, at your option.
010: * ====================================================================
011: */
012: package org.tmatesoft.svn.core.internal.util;
013:
014: import java.util.Random;
015: import java.util.Arrays;
016: import java.rmi.server.UID;
017: import java.security.MessageDigest;
018: import java.security.NoSuchAlgorithmException;
019: import java.text.MessageFormat;
020:
021: import org.tmatesoft.svn.core.SVNException;
022: import org.tmatesoft.svn.core.SVNErrorMessage;
023: import org.tmatesoft.svn.core.SVNErrorCode;
024: import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
025:
026: /**
027: * @version 1.1.1
028: * @author TMate Software Ltd.
029: */
030: public class SVNUUIDGenerator {
031:
032: private static final int NODE_LENGTH = 6;
033: private static byte[] ourUUIDStateNode = new byte[NODE_LENGTH];
034: private static long ourUUIDStateSeqNum;
035: private static long ourLastGeneratedTime;
036: private static long ourFudgeFactor;
037:
038: /*
039: * We must be sure we don't use the same time values for generating 'random'
040: * UUIDs
041: */
042: private static long getCurrentTime() {
043: long currentTime = System.currentTimeMillis();
044: /* if clock reading changed since last UUID generated... */
045: if (ourLastGeneratedTime != currentTime) {
046: /*
047: * The clock reading has changed since the last UUID was generated.
048: * Reset the fudge factor. if we are generating them too fast, then
049: * the fudge may need to be reset to something greater than zero.
050: */
051: if (ourLastGeneratedTime + ourFudgeFactor > currentTime) {
052: ourFudgeFactor = ourLastGeneratedTime + ourFudgeFactor
053: - currentTime + 1;
054: } else {
055: ourFudgeFactor = 0;
056: }
057: ourLastGeneratedTime = currentTime;
058: } else {
059: /* We generated two really fast. Bump the fudge factor. */
060: ++ourFudgeFactor;
061: }
062: return currentTime + ourFudgeFactor;
063: }
064:
065: public static synchronized byte[] generateUUID()
066: throws SVNException {
067: if (ourUUIDStateNode[0] == 0) {
068: initState();
069: }
070: long timestamp = getCurrentTime();
071: byte[] uuidData = new byte[16];
072: uuidData[0] = (byte) timestamp;
073: uuidData[1] = (byte) (timestamp >> 8);
074: uuidData[2] = (byte) (timestamp >> 16);
075: uuidData[3] = (byte) (timestamp >> 24);
076: uuidData[4] = (byte) (timestamp >> 32);
077: uuidData[5] = (byte) (timestamp >> 40);
078: uuidData[6] = (byte) (timestamp >> 48);
079: uuidData[7] = (byte) (((timestamp >> 56) & 0x0F) | 0x10);
080: uuidData[8] = (byte) (((ourUUIDStateSeqNum >> 8) & 0x3F) | 0x80);
081: uuidData[9] = (byte) ourUUIDStateSeqNum;
082: System
083: .arraycopy(ourUUIDStateNode, 0, uuidData, 10,
084: NODE_LENGTH);
085: return uuidData;
086: }
087:
088: public static String formatUUID(byte[] uuid) {
089: if (uuid.length < 16) {
090: byte[] tmpBuf = new byte[16];
091: Arrays.fill(tmpBuf, (byte) 0);
092: System.arraycopy(uuid, 0, tmpBuf, 0, uuid.length);
093: uuid = tmpBuf;
094: }
095: String[] hexNumbers = new String[16];
096: for (int i = 0; i < 16; i++) {
097: hexNumbers[i] = SVNFormatUtil.getHexNumberFromByte(uuid[i]);
098: }
099: String formatString = "{0}{1}{2}{3}-{4}{5}-{6}{7}-{8}{9}-{10}{11}{12}{13}{14}{15}";
100: Object args = hexNumbers;
101: return MessageFormat.format(formatString, (Object[]) args);
102: }
103:
104: private static void initState() throws SVNException {
105: /*
106: * Offset between UUID formatted times and System.currentTimeMillis()
107: * formatted times. UUID UTC base time is October 15, 1582.
108: * System.currentTimeMillis() base time is January 1, 1970.
109: */
110: long currentTime = System.currentTimeMillis() * 10 + 0x01B21DD213814000L;
111: Random randomGen = new Random();
112: randomGen
113: .setSeed(((currentTime >> 32) ^ currentTime) & 0xffffffffL);
114: ourUUIDStateSeqNum = randomGen.nextLong() & 0x0FFFFL;
115: getRandomInfo(ourUUIDStateNode);
116: }
117:
118: private static void getRandomInfo(byte[] node) throws SVNException {
119: UID uid = new UID();
120: MessageDigest digest = null;
121: try {
122: digest = MessageDigest.getInstance("MD5");
123: } catch (NoSuchAlgorithmException e) {
124: SVNErrorMessage err = SVNErrorMessage.create(
125: SVNErrorCode.IO_ERROR,
126: "MD5 implementation not found: {0}", e
127: .getLocalizedMessage());
128: SVNErrorManager.error(err, e);
129: }
130: digest.update(uid.toString().getBytes());
131: byte[] seed = digest.digest();
132: int numToCopy = node.length < seed.length ? node.length
133: : seed.length;
134: System.arraycopy(seed, 0, node, 0, numToCopy);
135: node[0] |= 0x01;
136: }
137: }
|