package com.jqmobile.core.utils.plain;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CodingErrorAction;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;
/**
* UUID 作为主键与数据库原GUID二进制数组匹配工具类
* @author modi
*
*/
public final class UUIDUtils {
/**
* 获得空UUID
* @return
*/
public static UUID getEmptyUUID(){
return new UUID(0, 0);
}
public static UUID getUUIDByText(String text){
return md5s.get().digest(text);
}
private static class MD5Digest {
private static Charset UTF8 = Charset.forName("UTF-8");
private final MessageDigest md5;
private final CharsetEncoder encoder;
final UUID digest(CharSequence message) {
if (message == null) {
throw new IllegalArgumentException("message is null");
}
if (message.length() == 0) {
return getEmptyUUID();
}
final ByteBuffer bb;
try {
bb = this.encoder.encode(CharBuffer.wrap(message));
} catch (CharacterCodingException e) {
// UnsafeString.unsafe.throwException(e);
return null;// 永远不会到这里
}
this.md5.update(bb);
return getUUID(this.md5.digest());
}
// final byte[] digestTo16Bytes(CharSequence message) {
// if (message == null) {
// throw new IllegalArgumentException("message is null");
// }
// if (message.length() == 0) {
// return new byte[16];
// }
// final ByteBuffer bb;
// try {
// bb = this.encoder.encode(CharBuffer.wrap(message));
// } catch (CharacterCodingException e) {
//// UnsafeString.unsafe.throwException(e);
// return null;// 永远不会到这里
// }
// this.md5.update(bb);
// return this.md5.digest();
// }
//
// final long digestToLong(CharSequence message) {
// if (message == null) {
// throw new IllegalArgumentException("message is null");
// }
// if (message.length() == 0) {
// return 0;
// }
// try {
// this.md5.update(this.encoder.encode(CharBuffer.wrap(message)));
// } catch (CharacterCodingException e) {
//// UnsafeString.unsafe.throwException(e);
// return 0;
// }
// final byte[] buf = this.md5.digest();
// long msb = buf[0] & 0xff;
// for (int i = 1; i < 8; i++) {
// msb = (msb << 8) | (buf[i] & 0xff);
//
// }
// return msb;
// }
MD5Digest() {
MessageDigest md5;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
md5 = null;
}
this.md5 = md5;
this.encoder = UTF8.newEncoder();
this.encoder.onMalformedInput(CodingErrorAction.IGNORE);
this.encoder.onUnmappableCharacter(CodingErrorAction.IGNORE);
}
}
private static ThreadLocal<MD5Digest> md5s = new ThreadLocal<MD5Digest>() {
@Override
protected MD5Digest initialValue() {
return new MD5Digest();
};
};
/**
* 通过二进制数组获得UUID
* @param bytes
* @return
*/
public static UUID getUUID(byte[] bytes){
if (bytes == null) {
return null;
}
int length = bytes.length;
if (length == 0) {
return getEmptyUUID();
}
int c = length > 8 ? 8 : length;
int index = 0;
long msb = bytes[index++] & 0xff;
while (index < c) {
msb = (msb << 8) | (bytes[index++] & 0xff);
}
long lsb;
if (index < length) {
lsb = bytes[index++] & 0xff;
while (index < length) {
lsb = (lsb << 8) | (bytes[index++] & 0xff);
}
} else {
lsb = 0;
}
return new UUID(msb, lsb);
}
/**
* 通过UUID获得二进制数组
* @param id
* @return
*/
public static byte[] getBytes(UUID id){
byte[] bytes = new byte[16];
long sb = id.getLeastSignificantBits();
for (int i = 15; i >= 8; i--) {
bytes[i] = (byte) sb;
sb >>>= 8;
}
sb = id.getMostSignificantBits();
for (int i = 7; i >= 0; i--) {
bytes[i] = (byte) sb;
sb >>>= 8;
}
return bytes;
}
/**
* 通过UUID获得二进制数组
* @param uuid
* @return
*/
public static byte[] getBytes(String uuid){
return getBytes(UUID.fromString(uuid));
}
/**
* 不推荐使用方法,过度时期使用
* GUID字符串转换为UUID
* @param str 为GUID字符串,不可用UUID字符串
* @return
*/
@Deprecated
public static UUID valueOf(String str){
if (str == null) {
return null;
}
int strl = str.length();
if (strl == 32) {
return valueOf(hexToLong(str, 0), hexToLong(str, 16));
}else if(str.contains("-")){
return UUID.fromString(str);
}
return null;
}
private static long hexToLong(String str, int start) {
long temp = parseChar(str, start++);
temp = temp << 4 | parseChar(str, start++);
temp = temp << 4 | parseChar(str, start++);
temp = temp << 4 | parseChar(str, start++);
temp = temp << 4 | parseChar(str, start++);
temp = temp << 4 | parseChar(str, start++);
temp = temp << 4 | parseChar(str, start++);
temp = temp << 4 | parseChar(str, start++);
temp = temp << 4 | parseChar(str, start++);
temp = temp << 4 | parseChar(str, start++);
temp = temp << 4 | parseChar(str, start++);
temp = temp << 4 | parseChar(str, start++);
temp = temp << 4 | parseChar(str, start++);
temp = temp << 4 | parseChar(str, start++);
temp = temp << 4 | parseChar(str, start++);
return temp << 4 | parseChar(str, start++);
}
private final static int h2b_A_10 = 'A' - 10;
private final static int h2b_a_10 = 'a' - 10;
private static int parseChar(String s, int offset)
throws StringIndexOutOfBoundsException {
char c = s.charAt(offset);
if (c < '0') {
} else if (c <= '9') {
return c - '0';
} else if (c < 'A') {
} else if (c <= 'F') {
return c - h2b_A_10;
} else if (c < 'a') {
} else if (c <= 'f') {
return c - h2b_a_10;
}
throw new StringIndexOutOfBoundsException("在偏移量" + offset + "处出现无效的十六进制字符'" + c
+ "'");
}
/**
* 根据两个long创建ID
*
* @param mostSigBits
* 高位
* @param leastSigBits
* 地位
* @return 返回ID
*/
public static UUID valueOf(final long mostSigBits, final long leastSigBits) {
if (mostSigBits == 0 && leastSigBits == 0) {
return getEmptyUUID();
}
return new UUID(mostSigBits, leastSigBits);
}
public static String toGUIDString(UUID id){
boolean withPrefix = false, upperCase = true;
int j = withPrefix ? 34 : 32;
char[] hex = new char[j];
if (withPrefix) {
hex[0] = '0';
hex[1] = upperCase ? 'X' : 'x';
}
long sb = id.getLeastSignificantBits();
j -= 2;
byteToHex(hex, j, (byte) sb, upperCase);
j -= 2;
sb >>>= 8;
byteToHex(hex, j, (byte) sb, upperCase);
j -= 2;
sb >>>= 8;
byteToHex(hex, j, (byte) sb, upperCase);
j -= 2;
sb >>>= 8;
byteToHex(hex, j, (byte) sb, upperCase);
j -= 2;
sb >>>= 8;
byteToHex(hex, j, (byte) sb, upperCase);
j -= 2;
sb >>>= 8;
byteToHex(hex, j, (byte) sb, upperCase);
j -= 2;
sb >>>= 8;
byteToHex(hex, j, (byte) sb, upperCase);
j -= 2;
sb >>>= 8;
byteToHex(hex, j, (byte) sb, upperCase);
j -= 2;
sb = id.getMostSignificantBits();
byteToHex(hex, j, (byte) sb, upperCase);
j -= 2;
sb >>>= 8;
byteToHex(hex, j, (byte) sb, upperCase);
j -= 2;
sb >>>= 8;
byteToHex(hex, j, (byte) sb, upperCase);
j -= 2;
sb >>>= 8;
byteToHex(hex, j, (byte) sb, upperCase);
j -= 2;
sb >>>= 8;
byteToHex(hex, j, (byte) sb, upperCase);
j -= 2;
sb >>>= 8;
byteToHex(hex, j, (byte) sb, upperCase);
j -= 2;
sb >>>= 8;
byteToHex(hex, j, (byte) sb, upperCase);
j -= 2;
sb >>>= 8;
byteToHex(hex, j, (byte) sb, upperCase);
int charCount = hex.length;
if (charCount == 0) {
return "";
}
return new String(hex);
}
private static void byteToHex(char[] hex, int index, byte b,
boolean upperCase) {
int h = b >>> 4 & 0xF;
if (upperCase) {
hex[index] = (char) (h > 9 ? h + h2b_A_10 : h + '0');
h = b & 0xF;
hex[index + 1] = (char) (h > 9 ? h + h2b_A_10 : h + '0');
} else {
hex[index] = (char) (h > 9 ? h + h2b_a_10 : h + '0');
h = b & 0xF;
hex[index + 1] = (char) (h > 9 ? h + h2b_a_10 : h + '0');
}
}
public static byte[] getBytes(Object obj) {
if(obj instanceof String){
return getBytes((String)obj);
}else if(obj instanceof UUID){
return getBytes((UUID)obj);
}else if(obj instanceof byte[]){
return (byte[])obj;
}else{
throw new ClassCastException("UUID or String:"+obj.getClass());
}
}
}