MD5Hash.java
上传用户:quxuerui
上传日期:2018-01-08
资源大小:41811k
文件大小:6k
源码类别:

网格计算

开发平台:

Java

  1. /**
  2.  * Licensed to the Apache Software Foundation (ASF) under one
  3.  * or more contributor license agreements.  See the NOTICE file
  4.  * distributed with this work for additional information
  5.  * regarding copyright ownership.  The ASF licenses this file
  6.  * to you under the Apache License, Version 2.0 (the
  7.  * "License"); you may not use this file except in compliance
  8.  * with the License.  You may obtain a copy of the License at
  9.  *
  10.  *     http://www.apache.org/licenses/LICENSE-2.0
  11.  *
  12.  * Unless required by applicable law or agreed to in writing, software
  13.  * distributed under the License is distributed on an "AS IS" BASIS,
  14.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15.  * See the License for the specific language governing permissions and
  16.  * limitations under the License.
  17.  */
  18. package org.apache.hadoop.io;
  19. import java.io.IOException;
  20. import java.io.DataInput;
  21. import java.io.DataOutput;
  22. import java.io.InputStream;
  23. import java.util.Arrays;
  24. import java.security.*;
  25. /** A Writable for MD5 hash values.
  26.  */
  27. public class MD5Hash implements WritableComparable<MD5Hash> {
  28.   public static final int MD5_LEN = 16;
  29.   private static ThreadLocal<MessageDigest> DIGESTER_FACTORY = new ThreadLocal<MessageDigest>() {
  30.     protected MessageDigest initialValue() {
  31.       try {
  32.         return MessageDigest.getInstance("MD5");
  33.       } catch (NoSuchAlgorithmException e) {
  34.         throw new RuntimeException(e);
  35.       }
  36.     }
  37.   };
  38.   private byte[] digest;
  39.   /** Constructs an MD5Hash. */
  40.   public MD5Hash() {
  41.     this.digest = new byte[MD5_LEN];
  42.   }
  43.   /** Constructs an MD5Hash from a hex string. */
  44.   public MD5Hash(String hex) {
  45.     setDigest(hex);
  46.   }
  47.   
  48.   /** Constructs an MD5Hash with a specified value. */
  49.   public MD5Hash(byte[] digest) {
  50.     if (digest.length != MD5_LEN)
  51.       throw new IllegalArgumentException("Wrong length: " + digest.length);
  52.     this.digest = digest;
  53.   }
  54.   
  55.   // javadoc from Writable
  56.   public void readFields(DataInput in) throws IOException {
  57.     in.readFully(digest);
  58.   }
  59.   /** Constructs, reads and returns an instance. */
  60.   public static MD5Hash read(DataInput in) throws IOException {
  61.     MD5Hash result = new MD5Hash();
  62.     result.readFields(in);
  63.     return result;
  64.   }
  65.   // javadoc from Writable
  66.   public void write(DataOutput out) throws IOException {
  67.     out.write(digest);
  68.   }
  69.   /** Copy the contents of another instance into this instance. */
  70.   public void set(MD5Hash that) {
  71.     System.arraycopy(that.digest, 0, this.digest, 0, MD5_LEN);
  72.   }
  73.   /** Returns the digest bytes. */
  74.   public byte[] getDigest() { return digest; }
  75.   /** Construct a hash value for a byte array. */
  76.   public static MD5Hash digest(byte[] data) {
  77.     return digest(data, 0, data.length);
  78.   }
  79.   /** Construct a hash value for the content from the InputStream. */
  80.   public static MD5Hash digest(InputStream in) throws IOException {
  81.     final byte[] buffer = new byte[4*1024]; 
  82.     final MessageDigest digester = DIGESTER_FACTORY.get();
  83.     for(int n; (n = in.read(buffer)) != -1; ) {
  84.       digester.update(buffer, 0, n);
  85.     }
  86.     return new MD5Hash(digester.digest());
  87.   }
  88.   /** Construct a hash value for a byte array. */
  89.   public static MD5Hash digest(byte[] data, int start, int len) {
  90.     byte[] digest;
  91.     MessageDigest digester = DIGESTER_FACTORY.get();
  92.     digester.update(data, start, len);
  93.     digest = digester.digest();
  94.     return new MD5Hash(digest);
  95.   }
  96.   /** Construct a hash value for a String. */
  97.   public static MD5Hash digest(String string) {
  98.     return digest(UTF8.getBytes(string));
  99.   }
  100.   /** Construct a hash value for a String. */
  101.   public static MD5Hash digest(UTF8 utf8) {
  102.     return digest(utf8.getBytes(), 0, utf8.getLength());
  103.   }
  104.   /** Construct a half-sized version of this MD5.  Fits in a long **/
  105.   public long halfDigest() {
  106.     long value = 0;
  107.     for (int i = 0; i < 8; i++)
  108.       value |= ((digest[i] & 0xffL) << (8*(7-i)));
  109.     return value;
  110.   }
  111.   /**
  112.    * Return a 32-bit digest of the MD5.
  113.    * @return the first 4 bytes of the md5
  114.    */
  115.   public int quarterDigest() {
  116.     int value = 0;
  117.     for (int i = 0; i < 4; i++)
  118.       value |= ((digest[i] & 0xff) << (8*(3-i)));
  119.     return value;    
  120.   }
  121.   /** Returns true iff <code>o</code> is an MD5Hash whose digest contains the
  122.    * same values.  */
  123.   public boolean equals(Object o) {
  124.     if (!(o instanceof MD5Hash))
  125.       return false;
  126.     MD5Hash other = (MD5Hash)o;
  127.     return Arrays.equals(this.digest, other.digest);
  128.   }
  129.   /** Returns a hash code value for this object.
  130.    * Only uses the first 4 bytes, since md5s are evenly distributed.
  131.    */
  132.   public int hashCode() {
  133.     return quarterDigest();
  134.   }
  135.   /** Compares this object with the specified object for order.*/
  136.   public int compareTo(MD5Hash that) {
  137.     return WritableComparator.compareBytes(this.digest, 0, MD5_LEN,
  138.                                            that.digest, 0, MD5_LEN);
  139.   }
  140.   /** A WritableComparator optimized for MD5Hash keys. */
  141.   public static class Comparator extends WritableComparator {
  142.     public Comparator() {
  143.       super(MD5Hash.class);
  144.     }
  145.     public int compare(byte[] b1, int s1, int l1,
  146.                        byte[] b2, int s2, int l2) {
  147.       return compareBytes(b1, s1, MD5_LEN, b2, s2, MD5_LEN);
  148.     }
  149.   }
  150.   static {                                        // register this comparator
  151.     WritableComparator.define(MD5Hash.class, new Comparator());
  152.   }
  153.   private static final char[] HEX_DIGITS =
  154.   {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
  155.   /** Returns a string representation of this object. */
  156.   public String toString() {
  157.     StringBuffer buf = new StringBuffer(MD5_LEN*2);
  158.     for (int i = 0; i < MD5_LEN; i++) {
  159.       int b = digest[i];
  160.       buf.append(HEX_DIGITS[(b >> 4) & 0xf]);
  161.       buf.append(HEX_DIGITS[b & 0xf]);
  162.     }
  163.     return buf.toString();
  164.   }
  165.   /** Sets the digest value from a hex string. */
  166.   public void setDigest(String hex) {
  167.     if (hex.length() != MD5_LEN*2)
  168.       throw new IllegalArgumentException("Wrong length: " + hex.length());
  169.     byte[] digest = new byte[MD5_LEN];
  170.     for (int i = 0; i < MD5_LEN; i++) {
  171.       int j = i << 1;
  172.       digest[i] = (byte)(charToNibble(hex.charAt(j)) << 4 |
  173.                          charToNibble(hex.charAt(j+1)));
  174.     }
  175.     this.digest = digest;
  176.   }
  177.   private static final int charToNibble(char c) {
  178.     if (c >= '0' && c <= '9') {
  179.       return c - '0';
  180.     } else if (c >= 'a' && c <= 'f') {
  181.       return 0xa + (c - 'a');
  182.     } else if (c >= 'A' && c <= 'F') {
  183.       return 0xA + (c - 'A');
  184.     } else {
  185.       throw new RuntimeException("Not a hex character: " + c);
  186.     }
  187.   }
  188. }