View Javadoc
1   /*
2    * Licensed to The Apereo Foundation under one or more contributor license
3    * agreements. See the NOTICE file distributed with this work for additional
4    * information regarding copyright ownership.
5    *
6    *
7    * The Apereo Foundation licenses this file to you under the Educational
8    * Community License, Version 2.0 (the "License"); you may not use this file
9    * except in compliance with the License. You may obtain a copy of the License
10   * at:
11   *
12   *   http://opensource.org/licenses/ecl2.txt
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
17   * License for the specific language governing permissions and limitations under
18   * the License.
19   *
20   */
21  
22  
23  package org.opencastproject.util;
24  
25  import java.io.BufferedInputStream;
26  import java.io.File;
27  import java.io.FileInputStream;
28  import java.io.IOException;
29  import java.io.InputStream;
30  import java.io.Serializable;
31  import java.security.MessageDigest;
32  import java.security.NoSuchAlgorithmException;
33  
34  import javax.xml.bind.annotation.XmlAccessType;
35  import javax.xml.bind.annotation.XmlAccessorType;
36  import javax.xml.bind.annotation.XmlAttribute;
37  import javax.xml.bind.annotation.XmlType;
38  import javax.xml.bind.annotation.XmlValue;
39  
40  /**
41   * This class stores value and type of a generated checksum.
42   */
43  @XmlAccessorType(XmlAccessType.NONE)
44  @XmlType(name = "checksum", namespace = "http://mediapackage.opencastproject.org")
45  public final class Checksum implements Serializable {
46  
47    /** Serial version uid */
48    private static final long serialVersionUID = 1L;
49  
50    /** The checksum value */
51    @XmlValue
52    protected String value = null;
53  
54    /** The checksum type */
55    @XmlAttribute(name = "type")
56    protected ChecksumType type = null;
57  
58    /** Needed by JAXB */
59    public Checksum() {
60    }
61  
62    /**
63     * Creates a new checksum object of the specified value and checksum type.
64     *
65     * @param value
66     *          the value
67     * @param type
68     *          the type
69     */
70    private Checksum(String value, ChecksumType type) {
71      if (value == null)
72        throw new IllegalArgumentException("Checksum value is null");
73      if (type == null)
74        throw new IllegalArgumentException("Checksum type is null");
75      this.value = value;
76      this.type = type;
77    }
78  
79    /**
80     * Returns the checksum type.
81     *
82     * @return the type
83     */
84    public ChecksumType getType() {
85      return type;
86    }
87  
88    /**
89     * Returns the checksum value.
90     *
91     * @return the value
92     */
93    public String getValue() {
94      return value;
95    }
96  
97    /**
98     * Converts the checksum to a hex string.
99     *
100    * @param data
101    *          the digest
102    * @return the digest hex representation
103    */
104   public static String convertToHex(byte[] data) {
105     final StringBuffer buf = new StringBuffer();
106     for (int i = 0; i < data.length; i++) {
107       int halfbyte = (data[i] >>> 4) & 0x0F;
108       int twoHalfs = 0;
109       do {
110         if ((0 <= halfbyte) && (halfbyte <= 9))
111           buf.append((char) ('0' + halfbyte));
112         else
113           buf.append((char) ('a' + (halfbyte - 10)));
114         halfbyte = data[i] & 0x0F;
115       } while (twoHalfs++ < 1);
116     }
117     return buf.toString();
118   }
119 
120   @Override
121   public boolean equals(Object obj) {
122     if (obj instanceof Checksum) {
123       Checksum c = (Checksum) obj;
124       return type.equals(c.type) && value.equals(c.value);
125     }
126     return false;
127   }
128 
129   @Override
130   public int hashCode() {
131     return value.hashCode();
132   }
133 
134   @Override
135   public String toString() {
136     return value + " (" + type + ")";
137   }
138 
139   /**
140    * Creates a checksum from a string in the form "value (type)".
141    *
142    * @param checksum
143    *         the checksum in string form
144    * @return the checksum
145    * @throws NoSuchAlgorithmException
146    *           if the checksum of the specified type cannot be created
147    */
148   public static Checksum fromString(String checksum) throws NoSuchAlgorithmException {
149     String[] checksumParts = checksum.split(" ");
150 
151     if (checksumParts.length != 2) {
152       throw new IllegalArgumentException("Invalid string for checksum!");
153     }
154 
155     String value = checksumParts[0];
156     String type = checksumParts[1].replace("(","").replace(")", "");
157 
158     return create(type, value);
159   }
160 
161   /**
162    * Creates a checksum of type <code>type</code> and value <code>value</code>.
163    *
164    * @param type
165    *          the checksum type name
166    * @param value
167    *          the checksum value
168    * @return the checksum
169    * @throws NoSuchAlgorithmException
170    *           if the checksum of the specified type cannot be created
171    */
172   public static Checksum create(String type, String value) throws NoSuchAlgorithmException {
173     ChecksumType t = ChecksumType.fromString(type);
174     return new Checksum(value, t);
175   }
176 
177   /**
178    * Creates a checksum of type <code>type</code> and value <code>value</code>.
179    *
180    * @param type
181    *          the checksum type
182    * @param value
183    *          the checksum value
184    * @return the checksum
185    */
186   public static Checksum create(ChecksumType type, String value) {
187     return new Checksum(value, type);
188   }
189 
190   /**
191    * Creates a checksum of type <code>type</code> from the given file.
192    *
193    * @param type
194    *          the checksum type
195    * @param file
196    *          the file
197    * @return the checksum
198    * @throws IOException
199    *           if the file cannot be accessed
200    */
201   public static Checksum create(ChecksumType type, File file) throws IOException {
202     return create(type, new BufferedInputStream(new FileInputStream(file)));
203   }
204 
205   /**
206    * Creates a checksum of type <code>type</code> from the given input stream.
207    * The stream gets closed afterwards.
208    */
209   public static Checksum create(ChecksumType type, InputStream is) throws IOException {
210     MessageDigest checksum;
211     try {
212       checksum = MessageDigest.getInstance(type.getName());
213     } catch (NoSuchAlgorithmException e) {
214       throw new IllegalStateException("This system does not support checksums of type " + type.getName());
215     }
216     try {
217       byte[] bytes = new byte[1024];
218       int len = 0;
219       while ((len = is.read(bytes)) >= 0) {
220         checksum.update(bytes, 0, len);
221       }
222     } finally {
223       IoSupport.closeQuietly(is);
224     }
225     return new Checksum(convertToHex(checksum.digest()), type);
226   }
227 
228 }