生成类似于MongoDB产生的ObjectId

  1 package com.jt.boot.utils;
  2 
  3 import com.google.common.base.Objects;
  4 
  5 import java.net.NetworkInterface;
  6 import java.nio.ByteBuffer;
  7 import java.util.Date;
  8 import java.util.Enumeration;
  9 import java.util.Random;
 10 import java.util.concurrent.atomic.AtomicInteger;
 11 import java.util.logging.Level;
 12 import java.util.logging.Logger;
 13 
 14 /**
 15  * <p>A globally unique identifier for objects.</p>
 16  * <p/>
 17  * <p>Consists of 12 bytes, divided as follows:</p>
 18  * <table border="1">
 19  * <caption>ObjectID layout</caption>
 20  * <tr>
 21  * <td>0</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td><td>10</td><td>11</td>
 22  * </tr>
 23  * <tr>
 24  * <td colspan="4">time</td><td colspan="3">machine</td> <td colspan="2">pid</td><td colspan="3">inc</td>
 25  * </tr>
 26  * </table>
 27  * <p/>
 28  * <p>Instances of this class are immutable.</p>
 29  */
 30 public class ObjectId implements Comparable<ObjectId>, java.io.Serializable {
 31 
 32     private final int _time;
 33     private final int _machine;
 34     private final int _inc;
 35     private boolean _new;
 36     private static final int _genmachine;
 37 
 38     private static AtomicInteger _nextInc = new AtomicInteger((new Random()).nextInt());
 39 
 40     private static final long serialVersionUID = -4415279469780082174L;
 41 
 42     private static final Logger LOGGER = Logger.getLogger("org.bson.ObjectId");
 43 
 44     /**
 45      * Create a new object id.
 46      */
 47     public ObjectId() {
 48         _time = (int) (System.currentTimeMillis() / 1000);
 49         _machine = _genmachine;
 50         _inc = _nextInc.getAndIncrement();
 51         _new = true;
 52     }
 53     
 54     public static String id() {
 55         return get().toHexString();
 56     }
 57 
 58     /**
 59      * Gets a new object id.
 60      *
 61      * @return the new id
 62      */
 63     public static ObjectId get() {
 64         return new ObjectId();
 65     }
 66 
 67     /**
 68      * Checks if a string could be an {@code ObjectId}.
 69      *
 70      * @param s a potential ObjectId as a String.
 71      * @return whether the string could be an object id
 72      * @throws IllegalArgumentException if hexString is null
 73      */
 74     public static boolean isValid(String s) {
 75         if (s == null)
 76             return false;
 77 
 78         final int len = s.length();
 79         if (len != 24)
 80             return false;
 81 
 82         for (int i = 0; i < len; i++) {
 83             char c = s.charAt(i);
 84             if (c >= '0' && c <= '9')
 85                 continue;
 86             if (c >= 'a' && c <= 'f')
 87                 continue;
 88             if (c >= 'A' && c <= 'F')
 89                 continue;
 90 
 91             return false;
 92         }
 93 
 94         return true;
 95     }
 96 
 97 
 98     /**
 99      * Converts this instance into a 24-byte hexadecimal string representation.
100      *
101      * @return a string representation of the ObjectId in hexadecimal format
102      */
103     public String toHexString() {
104         final StringBuilder buf = new StringBuilder(24);
105         for (final byte b : toByteArray()) {
106             buf.append(String.format("%02x", b & 0xff));
107         }
108         return buf.toString();
109     }
110 
111     /**
112      * Convert to a byte array.  Note that the numbers are stored in big-endian order.
113      *
114      * @return the byte array
115      */
116     public byte[] toByteArray() {
117         byte b[] = new byte[12];
118         ByteBuffer bb = ByteBuffer.wrap(b);
119         // by default BB is big endian like we need
120         bb.putInt(_time);
121         bb.putInt(_machine);
122         bb.putInt(_inc);
123         return b;
124     }
125 
126     private int _compareUnsigned(int i, int j) {
127         long li = 0xFFFFFFFFL;
128         li = i & li;
129         long lj = 0xFFFFFFFFL;
130         lj = j & lj;
131         long diff = li - lj;
132         if (diff < Integer.MIN_VALUE)
133             return Integer.MIN_VALUE;
134         if (diff > Integer.MAX_VALUE)
135             return Integer.MAX_VALUE;
136         return (int) diff;
137     }
138 
139     public int compareTo(ObjectId id) {
140         if (id == null)
141             return -1;
142 
143         int x = _compareUnsigned(_time, id._time);
144         if (x != 0)
145             return x;
146 
147         x = _compareUnsigned(_machine, id._machine);
148         if (x != 0)
149             return x;
150 
151         return _compareUnsigned(_inc, id._inc);
152     }
153 
154     /**
155      * Gets the timestamp (number of seconds since the Unix epoch).
156      *
157      * @return the timestamp
158      */
159     public int getTimestamp() {
160         return _time;
161     }
162 
163     /**
164      * Gets the timestamp as a {@code Date} instance.
165      *
166      * @return the Date
167      */
168     public Date getDate() {
169         return new Date(_time * 1000L);
170     }
171 
172 
173     /**
174      * Gets the current value of the auto-incrementing counter.
175      *
176      * @return the current counter value.
177      */
178     public static int getCurrentCounter() {
179         return _nextInc.get();
180     }
181 
182 
183     static {
184 
185         try {
186             // build a 2-byte machine piece based on NICs info
187             int machinePiece;
188             {
189                 try {
190                     StringBuilder sb = new StringBuilder();
191                     Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();
192                     while (e.hasMoreElements()) {
193                         NetworkInterface ni = e.nextElement();
194                         sb.append(ni.toString());
195                     }
196                     machinePiece = sb.toString().hashCode() << 16;
197                 } catch (Throwable e) {
198                     // exception sometimes happens with IBM JVM, use random
199                     LOGGER.log(Level.WARNING, e.getMessage(), e);
200                     machinePiece = (new Random().nextInt()) << 16;
201                 }
202                 LOGGER.fine("machine piece post: " + Integer.toHexString(machinePiece));
203             }
204 
205             // add a 2 byte process piece. It must represent not only the JVM but the class loader.
206             // Since static var belong to class loader there could be collisions otherwise
207             final int processPiece;
208             {
209                 int processId = new Random().nextInt();
210                 try {
211                     processId = java.lang.management.ManagementFactory.getRuntimeMXBean().getName().hashCode();
212                 } catch (Throwable t) {
213                 }
214 
215                 ClassLoader loader = ObjectId.class.getClassLoader();
216                 int loaderId = loader != null ? System.identityHashCode(loader) : 0;
217 
218                 StringBuilder sb = new StringBuilder();
219                 sb.append(Integer.toHexString(processId));
220                 sb.append(Integer.toHexString(loaderId));
221                 processPiece = sb.toString().hashCode() & 0xFFFF;
222                 LOGGER.fine("process piece: " + Integer.toHexString(processPiece));
223             }
224 
225             _genmachine = machinePiece | processPiece;
226             LOGGER.fine("machine : " + Integer.toHexString(_genmachine));
227         } catch (Exception e) {
228             throw new RuntimeException(e);
229         }
230 
231     }
232 
233     @Override
234     public boolean equals(Object o) {
235         if (this == o) return true;
236         if (o == null || getClass() != o.getClass()) return false;
237 
238         ObjectId that = (ObjectId) o;
239 
240         return Objects.equal(this.serialVersionUID, that.serialVersionUID) &&
241                 Objects.equal(this.LOGGER, that.LOGGER) &&
242                 Objects.equal(this._time, that._time) &&
243                 Objects.equal(this._machine, that._machine) &&
244                 Objects.equal(this._inc, that._inc) &&
245                 Objects.equal(this._new, that._new) &&
246                 Objects.equal(this._nextInc, that._nextInc) &&
247                 Objects.equal(this._genmachine, that._genmachine);
248     }
249 
250     @Override
251     public int hashCode() {
252         return Objects.hashCode(serialVersionUID, LOGGER, _time, _machine, _inc, _new,
253                 _nextInc, _genmachine);
254     }
255 
256     public static void main(String[] args) {
257         System.out.println(new ObjectId().toHexString());
258         System.out.println(new ObjectId().toHexString());
259         System.out.println(new ObjectId().toHexString());
260     }
261 }

 

posted @ 2016-12-30 15:06  yweihainan  阅读(4609)  评论(0编辑  收藏  举报