001: /*
002: * BEGIN_HEADER - DO NOT EDIT
003: *
004: * The contents of this file are subject to the terms
005: * of the Common Development and Distribution License
006: * (the "License"). You may not use this file except
007: * in compliance with the License.
008: *
009: * You can obtain a copy of the license at
010: * https://open-esb.dev.java.net/public/CDDLv1.0.html.
011: * See the License for the specific language governing
012: * permissions and limitations under the License.
013: *
014: * When distributing Covered Code, include this CDDL
015: * HEADER in each file and include the License file at
016: * https://open-esb.dev.java.net/public/CDDLv1.0.html.
017: * If applicable add the following below this CDDL HEADER,
018: * with the fields enclosed by brackets "[]" replaced with
019: * your own identifying information: Portions Copyright
020: * [year] [name of copyright owner]
021: */
022:
023: /*
024: * @(#)ExchangeIdGeneratorImpl.java
025: * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved.
026: *
027: * END_HEADER - DO NOT EDIT
028: */
029: package com.sun.jbi.messaging;
030:
031: import java.util.Enumeration;
032:
033: import java.net.NetworkInterface;
034: import java.net.InetAddress;
035:
036: import java.security.SecureRandom;
037:
038: /**
039: *
040: * This class is used to generate message exchange identifiers.
041: *
042: * This implementation uses time-based UUID's as its basis. Since the UUID itself is not
043: * really needed (and it's only in J2SE 5.0) we only return a string representation. The
044: * String representation is changed from the standard to be simpler to contruct and easier
045: * to compare with other timestamp that might be available.
046: *
047: * @author Sun Microsystems, Inc
048: *
049: */
050:
051: public final class ExchangeIdGeneratorImpl implements
052: com.sun.jbi.messaging.ExchangeIdGenerator {
053: /**
054: * Timestamp of last id generated.
055: */
056: long mLastTimestamp;
057: /**
058: * Number of ticks within the same millisecond.
059: */
060: int mCounter;
061: /**
062: * Random portion that will be created initially or if the clock goes backwards.
063: */
064: int mSequence;
065: /**
066: * Random portion of the id that is based on the machine.
067: */
068: long mNode;
069: /**
070: * Offset from 15-oct-1582 to 1-jan-1970 for timestamp correction.
071: */
072: private final static long CLOCK_OFFSET = 0x01b21dd213814000L;
073: /**
074: * Scale from currentTimeMillis() to 100 ns of timestamps. This is also used
075: * to generate a different timestamp if called within the same millisecond.
076: */
077: private final static int CLOCK_SCALE = 10000;
078:
079: /*
080: * The random number generator used by this class to create random
081: * based UUIDs.
082: */
083: private SecureRandom mRandom = new SecureRandom();
084:
085: /**
086: * Generate the next Id.
087: *
088: * @return a randomly generated <tt>String</tt>.
089: */
090: public String nextId() {
091: long now = System.currentTimeMillis();
092: StringBuilder sb = new StringBuilder(40);
093: int counter;
094: long node;
095: int sequence;
096:
097: synchronized (this ) {
098: node = mNode;
099: sequence = mSequence;
100: if (mNode == 0 || now < mLastTimestamp) {
101: initialize();
102: node = mNode;
103: sequence = mSequence;
104: } else if (now == mLastTimestamp) {
105: //
106: // If we have generated the limit of UUID's per tick we have to wait.
107: //
108: if (mCounter == CLOCK_SCALE) {
109: mCounter &= 0xFF;
110: do {
111: try {
112: Thread.sleep(1L);
113: } catch (InterruptedException ie) {
114: }
115: now = System.currentTimeMillis();
116: } while (now == mLastTimestamp);
117: }
118: } else {
119: mCounter &= 0xff;
120: }
121: mLastTimestamp = now;
122: counter = ++mCounter;
123: }
124:
125: //
126: // Format up the identifier.
127: //
128: sb.append(node);
129: sb.append('-');
130: sb.append(sequence);
131: sb.append('-');
132: sb.append(now * CLOCK_SCALE + CLOCK_OFFSET + counter);
133: return (sb.toString());
134: }
135:
136: private void initialize() {
137: //
138: // For added entropy, add seeding material to the RNG. We use our set of network
139: // interface address as input.
140: //
141: if (mNode == 0) {
142: Enumeration eni;
143:
144: //
145: // Let the RNG seed itself.
146: //
147: mRandom.nextBytes(new byte[16]);
148:
149: //
150: // Now add the InetAddresses.
151: //
152: try {
153: eni = NetworkInterface.getNetworkInterfaces();
154: while (eni.hasMoreElements()) {
155: NetworkInterface ni = (NetworkInterface) eni
156: .nextElement();
157: Enumeration eia = ni.getInetAddresses();
158: while (eia.hasMoreElements()) {
159: InetAddress ia = (InetAddress) eia
160: .nextElement();
161: mRandom.setSeed(ia.getAddress());
162: }
163: }
164: } catch (java.net.SocketException sEx) {
165:
166: }
167: mNode = mRandom.nextLong() & 0xffffffffffffL;
168:
169: }
170:
171: mCounter = (mRandom.nextInt() & 0xff);
172: mSequence = (mRandom.nextInt() & 0xffff);
173: }
174: }
|