0001: /**********************************************************************
0002: Copyright (c) 2004 Ralf Ullrich and others. All rights reserved.
0003: Licensed under the Apache License, Version 2.0 (the "License");
0004: you may not use this file except in compliance with the License.
0005: You may obtain a copy of the License at
0006:
0007: http://www.apache.org/licenses/LICENSE-2.0
0008:
0009: Unless required by applicable law or agreed to in writing, software
0010: distributed under the License is distributed on an "AS IS" BASIS,
0011: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0012: See the License for the specific language governing permissions and
0013: limitations under the License.
0014:
0015:
0016: Contributors:
0017: ...
0018: **********************************************************************/package org.jpox.store.poid;
0019:
0020: import java.util.Date;
0021: import java.util.GregorianCalendar;
0022: import java.util.Random;
0023:
0024: import org.jpox.util.JPOXLogger;
0025:
0026: /**
0027: * An almost unique ID.
0028: *
0029: * This class represents a best possible derivate of a DCE UUID as is possible
0030: * with the standard Java API, which provides no way to determine the IEEE 802
0031: * address of a system and only provides a time with a granularity of
0032: * milliseconds instead of the required 100nanoseconds.
0033: *
0034: * It therefore uses random node values and also does not use non-volatile
0035: * storage for internal state fields.
0036: *
0037: * The uuid is internally stored as two 64 bit long values. This allows a fast
0038: * implementation of the <code>equals</code> method, but provides possibly
0039: * poor performance for the <code>compare</code> method due to the required
0040: * unpacking of the data.
0041: *
0042: * To create "real" UUIDs the default implementations of <code>loadState</code>
0043: * and <code>saveState</code> have to be overridden to provide hardware
0044: * derived node values and non-volatile generator state storage. The first is
0045: * not possible with Java's standard API and there is no standard way to do the
0046: * latter, therefore this class was called AUID = "almost unique id", as it
0047: * tries to circumvent these short comings by random initializations.
0048: *
0049: * Note: Due to the construction of the time stamp included in an AUID as a
0050: * 60-bit value of 100-nanosecond intervals since 00:00:00.00, 15 October 1582
0051: * (the date of Gregorian reform to the Christian Calendar), this implementation
0052: * will break due to field overflow on 23:21:00 CEST of March 31st in the year
0053: * 5236, that is when we are long gone and became ashes.
0054: *
0055: * @version $Revision: 1.4 $
0056: */
0057: class AUID implements Comparable {
0058: /**
0059: * This class represents the current state of the AUID generator.
0060: */
0061: protected static class State {
0062: /** The last time stamp used to create a AUID. */
0063: private long lastTime;
0064: /**
0065: * The time adjustment to be added to the last time stamp to create the
0066: * next AUID.
0067: */
0068: private long adjustTime;
0069: /** The current clock sequence. */
0070: private int clockSequence;
0071: /** The node value. */
0072: private long node;
0073: /** The version to use when constructing new AUIDs. */
0074: private int version;
0075: /** The variant to use when constructing new AUIDs. */
0076: private int variant;
0077: /** A random generator to be use for random initialization of fields. */
0078: private Random random;
0079: /**
0080: * A flag indicating if security attributes should be included in time
0081: * low field.
0082: */
0083: private boolean includeSecurityAttributes;
0084:
0085: /**
0086: * Sets the last time stamp used to create an AUID.
0087: *
0088: * @param lastTime
0089: * the last time stamp used to create an AUID.
0090: */
0091: public void setLastTime(long lastTime) {
0092: this .lastTime = lastTime;
0093: }
0094:
0095: /**
0096: * Returns the last time stamp used to create an AUID.
0097: *
0098: * @return the last time stamp used to create an AUID.
0099: */
0100: public long getLastTime() {
0101: return lastTime;
0102: }
0103:
0104: /**
0105: * Sets the time adjustment to be added to the last time stamp to create
0106: * the next AUID.
0107: *
0108: * @param adjustTime
0109: * The time adjustment to be added to the last time stamp to
0110: * create the next AUID.
0111: */
0112: public void setAdjustTime(long adjustTime) {
0113: this .adjustTime = adjustTime;
0114: }
0115:
0116: /**
0117: * Returns the time adjustment to be added to the last time stamp to
0118: * create the next AUID.
0119: *
0120: * @return The time adjustment to be added to the last time stamp to
0121: * create the next AUID.
0122: */
0123: public long getAdjustTime() {
0124: return adjustTime;
0125: }
0126:
0127: /**
0128: * Returns the time adjustment to be added to the last time stamp to
0129: * create the next AUID and increments it.
0130: *
0131: * @return The time adjustment to be added to the last time stamp to
0132: * create the next AUID before incrementation.
0133: */
0134: public long incrementAdjustTime() {
0135: return adjustTime++;
0136: }
0137:
0138: /**
0139: * Sets the current clock sequence.
0140: *
0141: * @param clockSequence
0142: * the current clock sequence.
0143: */
0144: public void setClockSequence(int clockSequence) {
0145: this .clockSequence = clockSequence;
0146: }
0147:
0148: /**
0149: * Returns the current clock sequence.
0150: *
0151: * @return the current clock sequence.
0152: */
0153: public int getClockSequence() {
0154: return clockSequence;
0155: }
0156:
0157: /**
0158: * Set the node value.
0159: *
0160: * @param node
0161: * the node value.
0162: */
0163: public void setNode(long node) {
0164: this .node = node;
0165: }
0166:
0167: /**
0168: * Returns the node value.
0169: *
0170: * @return the node value.
0171: */
0172: public long getNode() {
0173: return node;
0174: }
0175:
0176: /**
0177: * Sets the version to use when constructing new AUIDs.
0178: *
0179: * @param version
0180: * the version to use when constructing new AUIDs.
0181: */
0182: public void setVersion(int version) {
0183: this .version = version;
0184: }
0185:
0186: /**
0187: * Returns the version to use when constructing new AUIDs.
0188: *
0189: * @return the version to use when constructing new AUIDs.
0190: */
0191: public int getVersion() {
0192: return version;
0193: }
0194:
0195: /**
0196: * Sets the variant to use when constructing new AUIDs.
0197: *
0198: * @param variant
0199: * the variant to use when constructing new AUIDs.
0200: */
0201: public void setVariant(int variant) {
0202: this .variant = variant;
0203: }
0204:
0205: /**
0206: * Returns the variant to use when constructing new AUIDs.
0207: *
0208: * @return the variant to use when constructing new AUIDs.
0209: */
0210: public int getVariant() {
0211: return variant;
0212: }
0213:
0214: /**
0215: * Sets the random generator used for initialization of fields.
0216: *
0217: * @param random
0218: * the random generator to use for initialization of fields.
0219: */
0220: public void setRandom(Random random) {
0221: this .random = random;
0222: }
0223:
0224: /**
0225: * Returns the random generator used for initialization of fields.
0226: *
0227: * @return the random generator used for initialization of fields.
0228: */
0229: public Random getRandom() {
0230: return random;
0231: }
0232:
0233: /**
0234: * Sets if security attributes have to be included in time low field.
0235: *
0236: * @param includeSecurityAttributes
0237: * if <code>true</code> security attributes will included.
0238: */
0239: public void setIncludeSecurityAttributes(
0240: boolean includeSecurityAttributes) {
0241: this .includeSecurityAttributes = includeSecurityAttributes;
0242: }
0243:
0244: /**
0245: * Returns wether security attribute have to be included.
0246: *
0247: * @return <code>true</code> if security attributes have to be
0248: * included.
0249: */
0250: public boolean getIncludeSecurityAttributes() {
0251: return includeSecurityAttributes;
0252: }
0253: }
0254:
0255: // These two are commented out since not enabled in the code
0256: // private static final int VERSION_DCE = 1;
0257: // private static final int VERSION_DCE_SECURE = 2;
0258:
0259: private static final int VERSION_RANDOM_NODE = 3;
0260: private static final int VARIANT_NCS = 0x0000;
0261: private static final int VARIANT_DCE = 0x8000;
0262: private static final int VARIANT_MICROSOFT = 0xc000;
0263: private static final int VARIANT_RESERVED = 0xe000;
0264: private static final int CS_MASK_NCS = 0x7fff;
0265: private static final int CS_MASK_DCE = 0x3fff;
0266: private static final int CS_MASK_MICROSOFT = 0x1fff;
0267: private static final int CS_MASK_RESERVED = 0x1fff;
0268: private static final long MAXIMUM_ENTROPIC_TIME_MS = 5000;
0269:
0270: /**
0271: * Scale from System.currentTimeMillis() granularity to that of AUID.
0272: */
0273: private static final long TIME_SCALE = 10000;
0274:
0275: /**
0276: * The offset between UTC and the AUID timestamps in 100-nanosecond
0277: * intervals since 00:00:00.00, 15 October 1582 (the date of Gregorian
0278: * reform to the Christian Calendar).
0279: */
0280: private static final long UTC_OFFSET = new GregorianCalendar()
0281: .getGregorianChange().getTime()
0282: * TIME_SCALE;
0283: /**
0284: * An array of chars for Hex conversion.
0285: */
0286: private static final char[] HEX_CHARS = { '0', '1', '2', '3', '4',
0287: '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
0288:
0289: /**
0290: * The state of the AUID generator.
0291: */
0292: private static State auidState = null;
0293:
0294: /**
0295: * The first 64 bits of the uuid value.
0296: */
0297: private long firstHalf;
0298:
0299: /**
0300: * The last 64 bits of the uuid value.
0301: */
0302: private long secondHalf;
0303:
0304: /**
0305: * Constructs an AUID with new values.
0306: */
0307: public AUID() {
0308: makeUnique(0, false);
0309: }
0310:
0311: /**
0312: * Constructs an AUID with new values and the specified security attributes.
0313: * The subclass which calls this constructor MUST set the state accordingly.
0314: *
0315: * @param securityAttributes
0316: * the security attributes to include in the new AUID.
0317: */
0318: protected AUID(int securityAttributes) {
0319: makeUnique(securityAttributes, true);
0320: }
0321:
0322: /**
0323: * Constructs an AUID from the specified values. This constructor is for
0324: * subclasses only and should not be made available to API users.
0325: *
0326: * @param time
0327: * the time field of the new AUID
0328: * @param version
0329: * the version of the new AUID
0330: * @param clockSeq
0331: * the clock sequence of the new AUID
0332: * @param variant
0333: * the variant of the new AUID
0334: * @param node
0335: * the node of the new AUID
0336: */
0337: protected AUID(long time, int version, int clockSeq, int variant,
0338: long node) {
0339: packFirstHalf(time, version);
0340: packSecondHalf(clockSeq, variant, node);
0341: }
0342:
0343: /**
0344: * Constructs an AUID from the specified original DCE field values. This
0345: * constructor is for subclasses only and should not be made available to
0346: * API users.
0347: *
0348: * @param timeLow
0349: * the time low field of the new AUID
0350: * @param timeMid
0351: * the time mid field of the new AUID
0352: * @param timeHiAndVersion
0353: * the packed time high and version field of the new AUID
0354: * @param clockSeqHiAndVariant
0355: * the packed clock sequence high and variant field of the new
0356: * AUID
0357: * @param clockSeqLow
0358: * the clock sequence low field of the new AUID
0359: * @param node
0360: * the node field of the new AUID
0361: */
0362: protected AUID(long timeLow, long timeMid, long timeHiAndVersion,
0363: int clockSeqHiAndVariant, int clockSeqLow, long node) {
0364: packDCEFieldsFirstHalf(timeLow, timeMid, timeHiAndVersion);
0365: packDCEFieldsSecondHalf(clockSeqHiAndVariant, clockSeqLow, node);
0366: }
0367:
0368: /**
0369: * Constructs an AUID with the same values as the specified AUID.
0370: *
0371: * @param auid
0372: * the AUID to clone
0373: */
0374: protected AUID(AUID auid) {
0375: firstHalf = auid.firstHalf;
0376: secondHalf = auid.secondHalf;
0377: }
0378:
0379: /**
0380: * Constructs an AUID from the specified string representation.
0381: *
0382: * @param auid string in the format "LLLLLLLL-MMMM-HHHH-CCCC-NNNNNNNNNNNN"
0383: * @throws NumberFormatException
0384: * if <code>auid</code> does not match the pattern
0385: * "LLLLLLLL-MMMM-HHHH-CCCC-NNNNNNNNNNNN" where 'L', 'M', 'H',
0386: * 'C' and 'N' are time low, mid, high, clock sequence and node
0387: * fields respectively.
0388: * a string representation of an AUID
0389: */
0390: public AUID(String auid) {
0391: try {
0392: firstHalf = parseFirstHalf(auid.subSequence(0, 18));
0393: secondHalf = parseSecondHalf(auid.subSequence(18, 36));
0394: } catch (IndexOutOfBoundsException ioobe) {
0395: throw new NumberFormatException();
0396: } catch (NumberFormatException nfe) {
0397: throw new NumberFormatException();
0398: }
0399: }
0400:
0401: /**
0402: * Constructs an AUID from the specified string representation in
0403: * CharSequence.
0404: *
0405: * @param auid
0406: * a string representation of an AUID
0407: * @throws NumberFormatException
0408: * if <code>auid</code> does not match the pattern
0409: * "LLLLLLLL-MMMM-HHHH-CCCC-NNNNNNNNNNNN" where 'L', 'M', 'H',
0410: * 'C' and 'N' are time low, mid, high, clock sequence and node
0411: * fields respectively.
0412: */
0413: public AUID(CharSequence auid) {
0414: try {
0415: firstHalf = parseFirstHalf(auid.subSequence(0, 18));
0416: secondHalf = parseSecondHalf(auid.subSequence(18, 36));
0417: } catch (IndexOutOfBoundsException ioobe) {
0418: throw new NumberFormatException();
0419: } catch (NumberFormatException nfe) {
0420: throw new NumberFormatException();
0421: }
0422: }
0423:
0424: /**
0425: * Constructs an AUID from the specified byte array representation, which is
0426: * in the same format as returned by <code>getBytes(dst, dstBegin)</code>.
0427: * This constructor is equal to <code>AUID(bytes, 0)</code>.
0428: *
0429: * @param bytes
0430: * a byte array representation of an AUID
0431: */
0432: public AUID(byte[] bytes) {
0433: this (bytes, 0);
0434: }
0435:
0436: /**
0437: * Constructs an AUID from the specified byte array representation, which is
0438: * in the same format as returned by <code>getBytes(dst, dstBegin)</code>.
0439: *
0440: * @param bytes
0441: * a byte array representation of an AUID
0442: * @param offset
0443: * the offset at which the byte array representation is located
0444: * in the byte array.
0445: */
0446: public AUID(byte[] bytes, int offset) {
0447: long timeLow = getOctets(4, bytes, 0 + offset, true);
0448: long timeMid = getOctets(2, bytes, 4 + offset, true);
0449: long timeHAV = getOctets(2, bytes, 6 + offset, true);
0450: int csHAV = (int) getOctets(1, bytes, 8 + offset, true);
0451: int csLow = (int) getOctets(1, bytes, 9 + offset, true);
0452: long node = getOctets(6, bytes, 10 + offset, true);
0453: packDCEFieldsFirstHalf(timeLow, timeMid, timeHAV);
0454: packDCEFieldsSecondHalf(csHAV, csLow, node);
0455: }
0456:
0457: /**
0458: * Parse a String representation of an AUID. Equal to
0459: * <code>new AUID(auid)</code>.
0460: *
0461: * @param auid
0462: * a string representation of an AUID
0463: * @return the AUID represented by <code>auid</code>.
0464: * @throws NumberFormatException
0465: * if <code>auid</code> does not match the pattern
0466: * "LLLLLLLL-MMMM-HHHH-CCCC-NNNNNNNNNNNN" where 'L', 'M', 'H',
0467: * 'C' and 'N' are time low, mid, high, clock sequence and node
0468: * fields respectively.
0469: */
0470: public static AUID parse(String auid) {
0471: return new AUID(auid);
0472: }
0473:
0474: /**
0475: * Parse a String representation of an AUID. Equal to
0476: * <code>new AUID(auid)</code>.
0477: *
0478: * @param auid string in the format "LLLLLLLL-MMMM-HHHH-CCCC-NNNNNNNNNNNN"
0479: * @return the AUID represented by <code>auid</code>.
0480: * @throws NumberFormatException
0481: * if <code>auid</code> does not match the pattern
0482: * "LLLLLLLL-MMMM-HHHH-CCCC-NNNNNNNNNNNN" where 'L', 'M', 'H',
0483: * 'C' and 'N' are time low, mid, high, clock sequence and node
0484: * fields respectively.
0485: * a string representation of an AUID
0486: */
0487: public static AUID parse(CharSequence auid) {
0488: return new AUID(auid);
0489: }
0490:
0491: /**
0492: * Identifies the variant from the combined clock sequence and variant
0493: * value, as it is returned by <code>getClockSeqAndVariant()</code>.
0494: *
0495: * May be overridden to support new variants.
0496: *
0497: * @param clockSeqAndVariant
0498: * the combined clock sequence and variant value, as it is
0499: * returned by <code>getClockSeqAndVariant()</code>.
0500: * @return the variant identified in the specified combined value.
0501: * @throws IllegalArgumentException
0502: * if variant could not be identified.
0503: */
0504: protected int identifyVariant(int clockSeqAndVariant) {
0505: if ((clockSeqAndVariant & ~CS_MASK_NCS) == VARIANT_NCS) {
0506: return VARIANT_NCS;
0507: }
0508: if ((clockSeqAndVariant & ~CS_MASK_DCE) == VARIANT_DCE) {
0509: return VARIANT_DCE;
0510: }
0511: if ((clockSeqAndVariant & ~CS_MASK_MICROSOFT) == VARIANT_MICROSOFT) {
0512: return VARIANT_NCS;
0513: }
0514: if ((clockSeqAndVariant & ~CS_MASK_RESERVED) == VARIANT_RESERVED) {
0515: return VARIANT_RESERVED;
0516: }
0517: // should not occur
0518: throw new IllegalArgumentException();
0519: }
0520:
0521: /**
0522: * This returns the bit mask to be applied to a clock sequence before it is
0523: * ORed with the variant value.
0524: *
0525: * May be overridden to support new variants.
0526: *
0527: * @param variant
0528: * the variant for which the mask shall be returned.
0529: * @return the mask to apply to a sequence when combining values.
0530: */
0531: public int getClockSeqMaskForVariant(int variant) {
0532: switch (variant) {
0533: case VARIANT_NCS:
0534: return CS_MASK_NCS;
0535: case VARIANT_DCE:
0536: return CS_MASK_DCE;
0537: case VARIANT_MICROSOFT:
0538: return CS_MASK_MICROSOFT;
0539: case VARIANT_RESERVED:
0540: return CS_MASK_RESERVED;
0541: default:
0542: throw new IllegalArgumentException();
0543: }
0544: }
0545:
0546: /**
0547: * Returns the current time as 100-nanosecond intervals since 00:00:00.00,
0548: * 15 October 1582 (the date of Gregorian reform to the Christian Calendar).
0549: * This may be overridden to support high resolution time devices.
0550: *
0551: * @return a time stamp for use in an AUID
0552: */
0553: protected long getCurrentTime() {
0554: return System.currentTimeMillis() * TIME_SCALE - UTC_OFFSET;
0555: }
0556:
0557: /**
0558: * Loads the generator state from non-volatile storage into the provided
0559: * State object or creates a new one if <code>null</code>.
0560: *
0561: * Overriding this method allows to actually add persistent storage
0562: * facilities for the generator state and may also support non-random node
0563: * that have been retrieved from the hardware. <br />
0564: * To override this method follow this pattern:
0565: *
0566: * <pre>
0567: * protected State loadState(State state)
0568: * {
0569: * State loadInto = state;
0570: * if (loadInto == null)
0571: * {
0572: * if (staticStateField == null)
0573: * {
0574: * loadInto = staticStateField = new State();
0575: * }
0576: * state = staticStateField;
0577: * }
0578: * if (loadInto != null)
0579: * {
0580: * if (loadInto.random == null)
0581: * {
0582: * // set loadInto.random to a customized Random generator if possible
0583: * // YOUR CODE TO SET RANDOM GENERATOR GOES HERE (OPTIONAL)
0584: * }
0585: * // call super implementation to initialize with defaults.
0586: * super(loadInto);
0587: * // load state into loadInto (consider to use getClass() to distinguish
0588: * // between multiple stored versions).
0589: * // always load lastTime and adjustTime
0590: * // load clock sequence only if node value is retrieved from hardware that
0591: * // cannot be moved to another system and is guaranteed to be unique between
0592: * // different systems
0593: * // Do not modify the above values if loading failed (for example due to
0594: * // I/O failure).
0595: * // YOUR CODE TO LOAD CLOCK RELATED VALUES GOES HERE (REQUIRED)
0596: * // Set node, version, variant and security attribute inclusion as required.
0597: * // YOUR CODE TO SET NODE, VERSION, VARIANT VALUES GOES HERE (RECOMMENDED)
0598: * }
0599: * return state;
0600: * }
0601: * </pre>
0602: *
0603: * @param state
0604: * the State object into which the state has to be loaded.
0605: * @return an initialized State object
0606: */
0607: protected State loadState(State state) {
0608: State loadInto = state;
0609: if (loadInto == null) {
0610: if (auidState == null) {
0611: loadInto = auidState = new State();
0612: }
0613: state = auidState;
0614: }
0615: if (loadInto != null) {
0616: if (loadInto.getRandom() == null) {
0617: // set random generator
0618: //loadInto.setRandom(new Random(System.currentTimeMillis()));
0619: //loadInto.setRandom(new Random(EntropicSeed.calculate(32)));
0620: loadInto.setRandom(new Random(entropicSeed(32, System
0621: .currentTimeMillis())));
0622: }
0623: // no super implementation to call
0624: // initialize clock related
0625: loadInto.setLastTime(getCurrentTime());
0626: loadInto.setAdjustTime(0);
0627: loadInto.setClockSequence(loadInto.getRandom().nextInt());
0628: // initialize attribute fields
0629: loadInto
0630: .setNode(loadInto.getRandom().nextLong() & 0x0000ffffffffffffL);
0631: loadInto.setVersion(VERSION_RANDOM_NODE);
0632: loadInto.setVariant(VARIANT_DCE);
0633: loadInto.setIncludeSecurityAttributes(false);
0634: }
0635: return state;
0636: }
0637:
0638: /**
0639: * Can be overridden together with <code>loadState</code> to provide
0640: * persistent storage for the auid generator state. The default
0641: * implementation does nothing.
0642: *
0643: * @param state
0644: * the State object to persist.
0645: */
0646: protected void saveState(State state) {
0647: }
0648:
0649: /**
0650: * This is the implementation of <code>getBytes(dst, dstBegin)</code>,
0651: * however, the endianess can be specified through the boolean argument.
0652: * Subclasses can use this to provide little endian byte array
0653: * representations. If this is done, there should also be a constructor
0654: * using this byte array order. If this method is overridden to provide a
0655: * different field order, the new field order will also be used by the
0656: * <code>getBytes(dst, dstBegin)</code> method.
0657: *
0658: * @param dst
0659: * the destination byte array, if <code>null</code> a new array
0660: * will be created
0661: * @param dstBegin
0662: * the offset to use when writing into the destination byte
0663: * array, ignored if dst is <code>null</code>
0664: * @param bigendian
0665: * if <code>true</code> big endian byte order is used
0666: * @return a byte array
0667: */
0668: protected byte[] getBytes(byte[] dst, int dstBegin,
0669: boolean bigendian) {
0670: if (dst == null) {
0671: dst = new byte[16];
0672: dstBegin = 0;
0673: }
0674: putOctets(getTimeLow(), 4, dst, dstBegin, bigendian);
0675: putOctets(getTimeMid(), 2, dst, dstBegin + 4, bigendian);
0676: putOctets(getTimeHighAndVersion(), 2, dst, dstBegin + 6,
0677: bigendian);
0678: putOctets(getClockSeqHighAndVariant(), 1, dst, dstBegin + 8,
0679: bigendian);
0680: putOctets(getClockSeqLow(), 1, dst, dstBegin + 9, bigendian);
0681: putOctets(getNode(), 6, dst, dstBegin + 10, bigendian);
0682: return dst;
0683: }
0684:
0685: /**
0686: * Returns the AUID value as byte array. The array will be filled with the
0687: * original DCE fields in big endian order, that is each field starts with
0688: * the most significant byte:
0689: *
0690: * <pre>
0691: *
0692: *
0693: * +---------------------------+---------+---+---+-------+-------+
0694: * ! FIELD DESCRIPTION ! OCTETS ! LENGTH in bits !
0695: * +---------------------------+---------+---------------+-------+
0696: * ! time low ! 0 - 3 ! 32 !
0697: * +---------------------------+---------+-------+-------+
0698: * ! time mid ! 4 - 5 ! 16 !
0699: * +---------------------------+---------+-------+
0700: * ! time hi and version ! 6 - 7 ! 16 !
0701: * +---------------------------+---------+---+---+
0702: * ! clock seq hi and reserved ! 8 ! 8 !
0703: * +---------------------------+---------+---+
0704: * ! clock seq low ! 9 ! 8 !
0705: * +---------------------------+---------+---+-------------------+
0706: * ! node ! 10 - 15 ! 48 !
0707: * +---------------------------+---------+-----------------------+
0708: *
0709: *
0710: * </pre>
0711: *
0712: * This implementation just returns
0713: * <code>getBytes(dst, dstBegin, true)</code>.
0714: * @param dst
0715: * the destination byte array, if <code>null</code> a new array
0716: * will be created
0717: * @param dstBegin
0718: * the offset to use when writing into the destination byte
0719: * array, ignored if dst is <code>null</code>
0720: * @return a byte array
0721: */
0722: public byte[] getBytes(byte[] dst, int dstBegin) {
0723: return getBytes(dst, dstBegin, true);
0724: }
0725:
0726: /**
0727: * Appends the String representation of this AUID to the specified
0728: * StringBuffer or if null to a new created StringBuffer and returns the
0729: * StringBuffer. This method is called by <code>toString</code>,
0730: * therefore it is sufficient to override this method together with
0731: * providing new parse methods to create a new string representation of an
0732: * AUID.
0733: *
0734: * @param sb
0735: * the StringBuffer to use
0736: * @return a StringBuffer to which this AUID has been appended
0737: */
0738: public StringBuffer toStringBuffer(StringBuffer sb) {
0739: if (sb == null) {
0740: sb = new StringBuffer();
0741: }
0742: toHex(sb, getTimeLow(), 8);
0743: sb.append('-');
0744: toHex(sb, getTimeMid(), 4);
0745: sb.append('-');
0746: toHex(sb, getTimeHighAndVersion(), 4);
0747: sb.append('-');
0748: toHex(sb, getClockSeqAndVariant(), 4);
0749: sb.append('-');
0750: toHex(sb, getNode(), 12);
0751: return sb;
0752: }
0753:
0754: /**
0755: * Packs time and version into the first 64 bits (octets 0-7).
0756: */
0757: private void packFirstHalf(long time, int version) {
0758: firstHalf = ((long) version << 60)
0759: | (time & 0x0fffffffffffffffL);
0760: }
0761:
0762: /**
0763: * Packs the original DCE fields time low, mid and hiAndVersion into the
0764: * first 64 bits (octets 0-7).
0765: */
0766: private void packDCEFieldsFirstHalf(long timeLow, long timeMid,
0767: long timeHiAndVersion) {
0768: firstHalf = (timeHiAndVersion << 48) | (timeMid << 32)
0769: | timeLow;
0770: }
0771:
0772: /**
0773: * Packs clock sequence, variant and node into the second 64 bits (octets
0774: * 8-15).
0775: */
0776: private void packSecondHalf(int clockSeq, int variant, long node) {
0777: int csMasked = clockSeq & getClockSeqMaskForVariant(variant);
0778: int csLow = csMasked & 0xff;
0779: int csHigh = (variant | csMasked) >>> 8;
0780: secondHalf = (node << 16) | (csLow << 8) | csHigh;
0781: }
0782:
0783: /**
0784: * Packs the original DCE fields clockSeqHiAndVariant, clockSeqLow and node
0785: * into the second 64 bits (octets 8-15).
0786: */
0787: private void packDCEFieldsSecondHalf(int clockSeqHiAndVariant,
0788: int clockSeqLow, long node) {
0789: secondHalf = (node << 16) | (clockSeqLow << 8)
0790: | clockSeqHiAndVariant;
0791: }
0792:
0793: /**
0794: * Contains the algorithm to create an AUID.
0795: */
0796: private void makeUnique(int securityAttributes,
0797: boolean hasSecurityAttributes) {
0798: synchronized (AUID.class) {
0799: // prepare generation
0800: State state = loadState(null);
0801: // DCE algorithm to generate UUID:
0802: // 1. determine time stamp and clock sequence
0803: long now = getCurrentTime();
0804: if (now < state.getLastTime()) {
0805: state.setClockSequence(state.getClockSequence() + 1);
0806: state.setAdjustTime(0);
0807: state.setLastTime(now);
0808: } else if (now != state.getLastTime()) {
0809: if (now < (state.getLastTime() + state.getAdjustTime())) {
0810: throw new IllegalStateException(
0811: "Clock overrun occured.");
0812: }
0813: state.setAdjustTime(0);
0814: state.setLastTime(now);
0815: }
0816: now += state.incrementAdjustTime();
0817: // 2a. replace time-low with security attributes if version is
0818: // DCE_SECURE
0819: if (state.getIncludeSecurityAttributes()) {
0820: if (hasSecurityAttributes) {
0821: now = (now & 0xffffffff00000000L)
0822: | securityAttributes;
0823: } else {
0824: throw new IllegalArgumentException(
0825: "Required to include security attributes as declared in state.");
0826: }
0827: } else {
0828: if (hasSecurityAttributes) {
0829: throw new IllegalArgumentException(
0830: "Cannot include security attributes if not declared in state.");
0831: }
0832: }
0833: // 2b., 3., 4., 5. set time low, mid high and version fields
0834: packFirstHalf(now, state.getVersion());
0835: // 6., 7., 8. set clock sequence and variant fields
0836: packSecondHalf(state.getClockSequence(),
0837: state.getVariant(), state.getNode());
0838: saveState(state);
0839: }
0840: }
0841:
0842: /**
0843: * Converts <code>nibbles</code> least significant nibbles of
0844: * <code>value</code> into a hex representation and appends it to
0845: * <code>result</code>.
0846: */
0847: private void toHex(StringBuffer result, long value, int nibbles) {
0848: if (nibbles > 0) {
0849: toHex(result, value >>> 4, nibbles - 1);
0850: result.append(HEX_CHARS[(int) value & 0xf]);
0851: }
0852: }
0853:
0854: /**
0855: * Converts a hex character into the corresponding nibble value.
0856: *
0857: * @return the nibble value.
0858: * @throws NumberFormatException
0859: * if <code>c</code> is not a valid hex character.
0860: */
0861: private long parseNibble(char c) {
0862: switch (c) {
0863: case '0':
0864: return 0;
0865: case '1':
0866: return 1;
0867: case '2':
0868: return 2;
0869: case '3':
0870: return 3;
0871: case '4':
0872: return 4;
0873: case '5':
0874: return 5;
0875: case '6':
0876: return 6;
0877: case '7':
0878: return 7;
0879: case '8':
0880: return 8;
0881: case '9':
0882: return 9;
0883: case 'a':
0884: case 'A':
0885: return 10;
0886: case 'b':
0887: case 'B':
0888: return 11;
0889: case 'c':
0890: case 'C':
0891: return 12;
0892: case 'd':
0893: case 'D':
0894: return 13;
0895: case 'e':
0896: case 'E':
0897: return 14;
0898: case 'f':
0899: case 'F':
0900: return 15;
0901: default:
0902: throw new NumberFormatException();
0903: }
0904: }
0905:
0906: /**
0907: * Tests wether <code>c</code> is a hyphen '-' character.
0908: *
0909: * @throws NumberFormatException
0910: * if <code>c</code> is not a hyphen '-' character.
0911: */
0912: private void parseHyphen(char c) {
0913: if (c != '-') {
0914: throw new NumberFormatException();
0915: }
0916: }
0917:
0918: /**
0919: * Parses the character sequence <code>cs</code> from begin to end as hex
0920: * string.
0921: *
0922: * @throws NumberFormatException
0923: * if <code>cs</code> contains non-hex characters.
0924: */
0925: private long parseHex(CharSequence cs) {
0926: long retval = 0;
0927: for (int i = 0; i < cs.length(); i++) {
0928: retval = (retval << 4) + parseNibble(cs.charAt(i));
0929: }
0930: return retval;
0931: }
0932:
0933: /**
0934: * Parses the character sequence <code>cs</code> from begin to end as the
0935: * first 18 charcters of a string representation of an AUID.
0936: *
0937: * @return the first 64 bits represented by <code>cs</code>.
0938: * @throws NumberFormatException
0939: * if <code>cs</code> does no match the pattern
0940: * "LLLLLLLL-MMMM-HHHH" where 'L', 'M', 'H' are time low, mid
0941: * and high fields respectively.
0942: */
0943: private long parseFirstHalf(CharSequence charSequence) {
0944: long timeLow = parseHex(charSequence.subSequence(0, 8));
0945: parseHyphen(charSequence.charAt(8));
0946: long timeMid = parseHex(charSequence.subSequence(9, 13));
0947: parseHyphen(charSequence.charAt(13));
0948: long timeHi = parseHex(charSequence.subSequence(14, 18));
0949: return (timeHi << 48) | (timeMid << 32) | timeLow;
0950: }
0951:
0952: /**
0953: * Parses the character sequence <code>cs</code> from begin to end as the
0954: * second 18 charcters of a string representation of an AUID.
0955: *
0956: * @return the second 64 bits represented by <code>cs</code>.
0957: * @throws NumberFormatException
0958: * if <code>cs</code> does no match the pattern
0959: * "-CCCC-NNNNNNNNNNNN" where 'C', 'N' are clock sequence and
0960: * node fields respectively.
0961: */
0962: private long parseSecondHalf(CharSequence charSequence) {
0963: parseHyphen(charSequence.charAt(0));
0964: long clockSeq = parseHex(charSequence.subSequence(1, 5));
0965: parseHyphen(charSequence.charAt(5));
0966: long node = parseHex(charSequence.subSequence(6, 18));
0967: return (node << 16) | ((clockSeq & 0xff) << 8)
0968: | (clockSeq >>> 8);
0969: }
0970:
0971: /**
0972: * Gets a value from the specified byte array starting at begin with the
0973: * specified number of octets and endianess.
0974: * @param octets
0975: * the number of octets
0976: * @param bytes
0977: * the array to get the value from
0978: * @param begin
0979: * the offset to use when writing into the destination byte
0980: * array, ignored if dst is <code>null</code>
0981: * @param bigendian
0982: * if <code>true</code> big endian byte order is used
0983: * @return the octet
0984: */
0985: protected static final long getOctets(int octets, byte[] bytes,
0986: int begin, boolean bigendian) {
0987: if (octets > 1) {
0988: if (bigendian) {
0989: return ((bytes[begin] & 0xffL) << (8 * (octets - 1)))
0990: | getOctets(octets - 1, bytes, begin + 1,
0991: bigendian);
0992: } else {
0993: return getOctets(octets - 1, bytes, begin, bigendian)
0994: | ((bytes[begin + octets - 1] & 0xffL) << (8 * (octets - 1)));
0995: }
0996: } else {
0997: return bytes[begin] & 0xffL;
0998: }
0999: }
1000:
1001: /**
1002: * Puts the specified value into the byte array in the specified endianess.
1003: * @param value
1004: * the value
1005: * @param octets
1006: * the number of octets
1007: * @param dst
1008: * the destination array
1009: * @param dstBegin
1010: * the offset to use when writing into the destination byte
1011: * array, ignored if dst is <code>null</code>
1012: * @param bigendian
1013: * if <code>true</code> big endian byte order is used
1014: */
1015: protected static final void putOctets(long value, int octets,
1016: byte[] dst, int dstBegin, boolean bigendian) {
1017: if (bigendian) {
1018: if (octets > 1) {
1019: putOctets(value >>> 8, octets - 1, dst, dstBegin,
1020: bigendian);
1021: }
1022: dst[dstBegin + octets - 1] = (byte) (value & 0xff);
1023: } else {
1024: dst[dstBegin] = (byte) (value & 0xff);
1025: if (octets > 1) {
1026: putOctets(value >>> 8, octets - 1, dst, dstBegin + 1,
1027: bigendian);
1028: }
1029: }
1030: }
1031:
1032: /**
1033: * Returns time low octets 0-3 (unsigned) int in a signed long.
1034: *
1035: * @return the time low field (original DCE field).
1036: */
1037: public final long getTimeLow() {
1038: return firstHalf & 0xffffffff;
1039: }
1040:
1041: /**
1042: * Returns time mid octets 4-5 (unsigned) int in a signed long.
1043: *
1044: * @return the time mid field (original DCE field).
1045: */
1046: public final long getTimeMid() {
1047: return (firstHalf >>> 32) & 0xffff;
1048: }
1049:
1050: /**
1051: * Returns time high octets 6-7 (unsigned) int in a signed long.
1052: *
1053: * @return the time high field with version masked out.
1054: */
1055: public final long getTimeHigh() {
1056: return (firstHalf >>> 48) & 0x0fff;
1057: }
1058:
1059: /**
1060: * Returns octets 6-7 (unsigned) int in a signed long.
1061: *
1062: * @return the time high and version field (original DCE field).
1063: */
1064: public final long getTimeHighAndVersion() {
1065: return (firstHalf >>> 48);
1066: }
1067:
1068: /**
1069: * Returns octets 0-7 time only.
1070: *
1071: * @return the complete time value.
1072: */
1073: public final long getTime() {
1074: return firstHalf & 0x0fffffffffffffffL;
1075: }
1076:
1077: /**
1078: * Returns the time of the AUID as Date. This is a narrowing conversion
1079: * because Date only supports a granularity of milliseconds, while the time
1080: * value represents 100 nanosecond intervals. Use <code>getNanos</code> to
1081: * retrieve the truncated nanoseconds.
1082: *
1083: * @return the complete time value as Date truncated to the next
1084: * millisecond.
1085: */
1086: public final Date getDate() {
1087: return new Date((getTime() + UTC_OFFSET) / TIME_SCALE);
1088: }
1089:
1090: /**
1091: * Returns the nanoseconds truncated from the time of the AUID by
1092: * <code>getDate</code>.
1093: *
1094: * @return the nanoseconds truncated from the time of the AUID by
1095: * <code>getDate</code>.
1096: */
1097: public final long getNanos() {
1098: return (getTime() + UTC_OFFSET) % TIME_SCALE;
1099: }
1100:
1101: /**
1102: * Returns octets 6-7 version only.
1103: *
1104: * @return the version field.
1105: */
1106: public final int getVersion() {
1107: return (int) (firstHalf >>> 60);
1108: }
1109:
1110: /**
1111: * Returns clock sequence high and variant octet 8 (unsigned) small in a
1112: * signed int.
1113: *
1114: * @return the clock seq hi and reserved (variant) field (original DCE
1115: * field).
1116: */
1117: public final int getClockSeqHighAndVariant() {
1118: return (int) (secondHalf & 0xff);
1119: }
1120:
1121: /**
1122: * Returns clock sequence low octet 9 (unsigned) small in a signed int.
1123: *
1124: * @return the clock seq low field (original DCE field).
1125: */
1126: public final int getClockSeqLow() {
1127: return (int) ((secondHalf >>> 8) & 0xff);
1128: }
1129:
1130: /**
1131: * Returns clock sequence and variant octets 8-9 (unsigned) short in a
1132: * signed int.
1133: *
1134: * @return the clock sequence and variant field.
1135: */
1136: public final int getClockSeqAndVariant() {
1137: return (getClockSeqHighAndVariant() << 8) | getClockSeqLow();
1138: }
1139:
1140: /**
1141: * Returns clock sequence.
1142: *
1143: * @return the clock sequence field.
1144: */
1145: public final int getClockSeq() {
1146: int csv = getClockSeqAndVariant();
1147: return csv & getClockSeqMaskForVariant(identifyVariant(csv));
1148: }
1149:
1150: /**
1151: * Returns the variant.
1152: *
1153: * @return the variant field.
1154: */
1155: public final int getVariant() {
1156: return identifyVariant(getClockSeqAndVariant());
1157: }
1158:
1159: /**
1160: * Returns node value octets 10-15 (unsigned) 48-bit in a signed long.
1161: *
1162: * @return the node field (original DCE field).
1163: */
1164: public final long getNode() {
1165: return secondHalf >>> 16;
1166: }
1167:
1168: /**
1169: * Conveniance method just returns <code>getBytes(null, 0)</code>.
1170: *
1171: * @return <code>getBytes(null, 0)</code>.
1172: */
1173: public final byte[] getBytes() {
1174: return getBytes(null, 0);
1175: }
1176:
1177: /*
1178: * Object methods
1179: */
1180: public boolean equals(Object obj) {
1181: if (obj instanceof AUID) {
1182: AUID other = (AUID) obj;
1183: return (firstHalf == other.firstHalf)
1184: && (secondHalf == other.secondHalf);
1185: }
1186: return false;
1187: }
1188:
1189: public int hashCode() {
1190: return (int) (firstHalf ^ (firstHalf >>> 32) ^ secondHalf ^ (secondHalf >>> 32));
1191: }
1192:
1193: public String toString() {
1194: return toStringBuffer(null).toString();
1195: }
1196:
1197: /*
1198: * Comparable methods
1199: */
1200: public int compareTo(Object o) {
1201: AUID other = (AUID) o;
1202: long cmp = getTimeLow() - other.getTimeLow();
1203: if (cmp != 0) {
1204: cmp = getTimeMid() - other.getTimeMid();
1205: if (cmp != 0) {
1206: cmp = getTimeHighAndVersion()
1207: - other.getTimeHighAndVersion();
1208: if (cmp != 0) {
1209: cmp = getClockSeqHighAndVariant()
1210: - other.getClockSeqHighAndVariant();
1211: if (cmp != 0) {
1212: cmp = getClockSeqLow() - other.getClockSeqLow();
1213: if (cmp != 0) {
1214: cmp = getNode() - other.getNode();
1215: }
1216: }
1217: }
1218: }
1219: }
1220: return (cmp == 0 ? 0 : (cmp < 0 ? -1 : 1));
1221: }
1222:
1223: /*
1224: * Utility method for "real" random seed
1225: */
1226: private static long entropicSeed(int bits, long initialSeed) {
1227: if (bits > 63) {
1228: bits = 63;
1229: } else if (bits < 1) {
1230: bits = 1;
1231: }
1232: final long startTime = System.currentTimeMillis();
1233: final int[] counters = new int[bits + 1];
1234: final Random[] randoms = new Random[bits];
1235: final Thread[] threads = new Thread[bits];
1236: final int endvalue = bits * 128;
1237: final int lastindex = bits;
1238: // create threads
1239: Random random = new Random(initialSeed);
1240: for (int i = 0; i < bits; i++) {
1241: final int this index = i;
1242: long nextSeed = random.nextLong();
1243: randoms[i] = new Random(nextSeed);
1244: threads[i] = new Thread() {
1245: public void run() {
1246: try {
1247: while (counters[lastindex] < endvalue) {
1248: long value = randoms[this index].nextLong();
1249: int loop = ((int) (value & 255)) + 16;
1250: for (int a = 0; a < loop; a++) {
1251: randoms[this index].nextLong();
1252: if (System.currentTimeMillis()
1253: - startTime > MAXIMUM_ENTROPIC_TIME_MS) {
1254: break;
1255: }
1256: }
1257: counters[this index]++;
1258: if (System.currentTimeMillis() - startTime > MAXIMUM_ENTROPIC_TIME_MS) {
1259: break;
1260: }
1261: }
1262: } catch (Throwable t) {
1263: JPOXLogger.POID.error(t);
1264: counters[this index] = endvalue;
1265: } finally {
1266: threads[this index] = null;
1267: }
1268: }
1269: };
1270: threads[i].start();
1271: }
1272: // check if all threads revolved at least bits times
1273: for (int i = 0; i < bits; i++) {
1274: while (counters[i] < bits) {
1275: Thread.yield();
1276: if (System.currentTimeMillis() - startTime > MAXIMUM_ENTROPIC_TIME_MS) {
1277: break;
1278: }
1279: }
1280: }
1281: // check if all threads together revolved often enough
1282: while (counters[lastindex] < endvalue) {
1283: Thread.yield();
1284: int sum = 0;
1285: for (int i = 0; i < bits; i++) {
1286: sum += counters[i];
1287: }
1288: counters[lastindex] = sum;
1289: if (System.currentTimeMillis() - startTime > MAXIMUM_ENTROPIC_TIME_MS) {
1290: break;
1291: }
1292: }
1293: // check if all threads stopped
1294: for (int i = 0; i < bits; i++) {
1295: while (threads[i] != null) {
1296: Thread.yield();
1297: }
1298: }
1299: // create a new seed
1300: long seed = 0;
1301: for (int i = 0; i < bits; i++) {
1302: //seed = (seed << 1) + (randoms[i].nextLong() & 1);
1303: seed += randoms[i].nextLong();
1304: }
1305: return seed;
1306: }
1307: }
|