/**  
 * @Copyright  com.taiyiche  
 * @author 刘峻辉
 * @description 用户登录token生成器
 * @date 2016-08-08
 */
package com.util;


import java.io.IOException;  
import java.io.UnsupportedEncodingException;  
import java.net.InetAddress;  
import java.security.MessageDigest;  
import java.security.NoSuchAlgorithmException;  
import java.security.SecureRandom;  
import java.util.HashMap;  
import java.util.Map;  
import java.util.Random;  
import java.util.concurrent.atomic.AtomicLong;  
import java.util.concurrent.locks.ReentrantLock;  
 

public class UniqId {  
   private static char[] digits = { '0', '1', '2', '3', '4', '5', '6', '7',  
           '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };  
 
   private static Map<Character, Integer> rDigits = new HashMap<Character, Integer>(  
           16);  
   static {  
       for (int i = 0; i < digits.length; ++i) {  
           rDigits.put(digits[i], i);  
       }  
   }  
 
   private static UniqId me = new UniqId();  
   private String hostAddr;  
   private Random random = new SecureRandom();  
   private MessageDigest mHasher;  
   private UniqTimer timer = new UniqTimer();  
 
   private ReentrantLock opLock = new ReentrantLock();  
 
   private UniqId() {  
       try {  
           InetAddress addr = InetAddress.getLocalHost();  
 
           hostAddr = addr.getHostAddress();  
       } catch (IOException e) {  
           hostAddr = String.valueOf(System.currentTimeMillis());  
       }  
 
       if (hostAddr == null || hostAddr.length() == 0  
               || "127.0.0.1".equals(hostAddr)) {  
           hostAddr = String.valueOf(System.currentTimeMillis());  
       }  
 
       try {  
           mHasher = MessageDigest.getInstance("MD5");  
       } catch (NoSuchAlgorithmException nex) {  
           mHasher = null;  
       }  
   }  
 
   /** 
    * 获取UniqID实例 
    *  
    * @return UniqId 
    */  
   public static UniqId getInstance() {  
       return me;  
   }  
 
   /** 
    * 获得不会重复的毫秒数 
    *  
    * @return 
    */  
   public long getUniqTime() {  
       return timer.getCurrentTime();  
   }  
 
   /** 
    * 获得UniqId 
    *  
    * @return uniqTime-randomNum-hostAddr-threadId 
    */  
   public String getUniqID() {  
       StringBuffer sb = new StringBuffer();  
       long t = timer.getCurrentTime();  
 
       sb.append(t);  
 
       sb.append("-");  
 
       sb.append(random.nextInt(8999) + 1000);  
 
       sb.append("-");  
       sb.append(hostAddr);  
 
       sb.append("-");  
       sb.append(Thread.currentThread().hashCode());  
 
       return sb.toString();  
   }  
 
   /** 
    * 获取MD5之后的uniqId string 
    *  
    * @return uniqId md5 string 
    */  
   public String getUniqIDHashString() {  
       return hashString(getUniqID());  
   }  
 
   /** 
    * 获取MD5之后的uniqId 
    *  
    * @return byte[16] 
    */  
   public byte[] getUniqIDHash() {  
       return hash(getUniqID());  
   }  
 
   /** 
    * 对字符串进行md5 
    *  
    * @param str 
    * @return md5 byte[16] 
    */  
   public byte[] hash(String str) {  
       opLock.lock();  
       try {  
           byte[] bt = mHasher.digest(str.getBytes("UTF-8"));  
           if (null == bt || bt.length != 16) {  
               throw new IllegalArgumentException("md5 need");  
           }  
           return bt;  
       } catch (UnsupportedEncodingException e) {  
           throw new RuntimeException("unsupported utf-8 encoding", e);  
       } finally {  
           opLock.unlock();  
       }  
   }  
 
   /** 
    * 对二进制数据进行md5 
    *  
    * @param str 
    * @return md5 byte[16] 
    */  
   public byte[] hash(byte[] data) {  
       opLock.lock();  
       try {  
           byte[] bt = mHasher.digest(data);  
           if (null == bt || bt.length != 16) {  
               throw new IllegalArgumentException("md5 need");  
           }  
           return bt;  
       } finally {  
           opLock.unlock();  
       }  
   }  
 
   /** 
    * 对字符串进行md5 string 
    *  
    * @param str 
    * @return md5 string 
    */  
   public String hashString(String str) {  
       byte[] bt = hash(str);  
       return bytes2string(bt);  
   }  
 
   /** 
    * 对字节流进行md5 string 
    *  
    * @param str 
    * @return md5 string 
    */  
   public String hashBytes(byte[] str) {  
       byte[] bt = hash(str);  
       return bytes2string(bt);  
   }  
 
   /** 
    * 将一个字节数组转化为可见的字符串 
    *  
    * @param bt 
    * @return 
    */  
   public String bytes2string(byte[] bt) {  
       int l = bt.length;  
 
       char[] out = new char[l << 1];  
 
       for (int i = 0, j = 0; i < l; i++) {  
           out[j++] = digits[(0xF0 & bt[i]) >>> 4];  
           out[j++] = digits[0x0F & bt[i]];  
       }  
 
       return new String(out);  
   }  
 
   /** 
    * 将字符串转换为bytes 
    *  
    * @param str 
    * @return byte[] 
    */  
   public byte[] string2bytes(String str) {  
       if (null == str) {  
           throw new NullPointerException("参数不能为空");  
       }  
       if (str.length() != 32) {  
           throw new IllegalArgumentException("字符串长度必须是32");  
       }  
       byte[] data = new byte[16];  
       char[] chs = str.toCharArray();  
       for (int i = 0; i < 16; ++i) {  
           int h = rDigits.get(chs[i * 2]).intValue();  
           int l = rDigits.get(chs[i * 2 + 1]).intValue();  
           data[i] = (byte) ((h & 0x0F) << 4 | (l & 0x0F));  
       }  
       return data;  
   }  
 
   /** 
    * 实现不重复的时间 
    *  
    * @author dogun 
    */  
   private static class UniqTimer {  
       private AtomicLong lastTime = new AtomicLong(System.currentTimeMillis());  
 
       public long getCurrentTime() {  
           return this.lastTime.incrementAndGet();  
       }  
   }  
}  