001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018:
019: package org.apache.tools.ant.types.selectors.modifiedselector;
020:
021: import java.io.File;
022: import java.io.FileInputStream;
023: import java.security.DigestInputStream;
024: import java.security.MessageDigest;
025: import java.security.NoSuchAlgorithmException;
026: import java.security.NoSuchProviderException;
027: import org.apache.tools.ant.BuildException;
028:
029: /**
030: * Computes a 'hashvalue' for the content of file using
031: * java.security.MessageDigest.
032: * Use of this algorithm doesn't require any additional nested <param>s.
033: * Supported <param>s are:
034: * <table>
035: * <tr>
036: * <th>name</th><th>values</th><th>description</th><th>required</th>
037: * </tr>
038: * <tr>
039: * <td> algorithm.algorithm </td>
040: * <td> MD5 | SHA (default provider) </td>
041: * <td> name of the algorithm the provider should use </td>
042: * <td> no, defaults to MD5 </td>
043: * </tr>
044: * <tr>
045: * <td> algorithm.provider </td>
046: * <td> </td>
047: * <td> name of the provider to use </td>
048: * <td> no, defaults to <i>null</i> </td>
049: * </tr>
050: * </table>
051: *
052: * @version 2004-07-08
053: * @since Ant 1.6
054: */
055: public class DigestAlgorithm implements Algorithm {
056:
057: // ----- member variables -----
058:
059: /**
060: * MessageDigest algorithm to be used.
061: */
062: private String algorithm = "MD5";
063:
064: /**
065: * MessageDigest Algorithm provider
066: */
067: private String provider = null;
068:
069: /**
070: * Message Digest instance
071: */
072: private MessageDigest messageDigest = null;
073:
074: /**
075: * Size of the read buffer to use.
076: */
077: private int readBufferSize = 8 * 1024;
078:
079: // ----- Algorithm-Configuration -----
080:
081: /**
082: * Specifies the algorithm to be used to compute the checksum.
083: * Defaults to "MD5". Other popular algorithms like "SHA" may be used as well.
084: * @param algorithm the digest algorithm to use
085: */
086: public void setAlgorithm(String algorithm) {
087: this .algorithm = algorithm;
088: }
089:
090: /**
091: * Sets the MessageDigest algorithm provider to be used
092: * to calculate the checksum.
093: * @param provider provider to use
094: */
095: public void setProvider(String provider) {
096: this .provider = provider;
097: }
098:
099: /** Initialize the security message digest. */
100: public void initMessageDigest() {
101: if (messageDigest != null) {
102: return;
103: }
104:
105: if ((provider != null) && !"".equals(provider)
106: && !"null".equals(provider)) {
107: try {
108: messageDigest = MessageDigest.getInstance(algorithm,
109: provider);
110: } catch (NoSuchAlgorithmException noalgo) {
111: throw new BuildException(noalgo);
112: } catch (NoSuchProviderException noprovider) {
113: throw new BuildException(noprovider);
114: }
115: } else {
116: try {
117: messageDigest = MessageDigest.getInstance(algorithm);
118: } catch (NoSuchAlgorithmException noalgo) {
119: throw new BuildException(noalgo);
120: }
121: }
122: }
123:
124: // ----- Logic -----
125:
126: /**
127: * This algorithm supports only MD5 and SHA.
128: * @return <i>true</i> if all is ok, otherwise <i>false</i>.
129: */
130: public boolean isValid() {
131: return "SHA".equalsIgnoreCase(algorithm)
132: || "MD5".equalsIgnoreCase(algorithm);
133: }
134:
135: /**
136: * Computes a value for a file content with the specified digest algorithm.
137: * @param file File object for which the value should be evaluated.
138: * @return The value for that file
139: */
140: // implementation adapted from ...taskdefs.Checksum, thanks to Magesh for hint
141: public String getValue(File file) {
142: initMessageDigest();
143: String checksum = null;
144: try {
145: if (!file.canRead()) {
146: return null;
147: }
148: FileInputStream fis = null;
149:
150: byte[] buf = new byte[readBufferSize];
151: try {
152: messageDigest.reset();
153: fis = new FileInputStream(file);
154: DigestInputStream dis = new DigestInputStream(fis,
155: messageDigest);
156: while (dis.read(buf, 0, readBufferSize) != -1) {
157: // do nothing
158: }
159: dis.close();
160: fis.close();
161: fis = null;
162: byte[] fileDigest = messageDigest.digest();
163: StringBuffer checksumSb = new StringBuffer();
164: for (int i = 0; i < fileDigest.length; i++) {
165: String hexStr = Integer
166: .toHexString(0x00ff & fileDigest[i]);
167: if (hexStr.length() < 2) {
168: checksumSb.append("0");
169: }
170: checksumSb.append(hexStr);
171: }
172: checksum = checksumSb.toString();
173: } catch (Exception e) {
174: return null;
175: }
176: } catch (Exception e) {
177: return null;
178: }
179: return checksum;
180: }
181:
182: /**
183: * Override Object.toString().
184: * @return some information about this algorithm.
185: */
186: public String toString() {
187: StringBuffer buf = new StringBuffer();
188: buf.append("<DigestAlgorithm:");
189: buf.append("algorithm=").append(algorithm);
190: buf.append(";provider=").append(provider);
191: buf.append(">");
192: return buf.toString();
193: }
194: }
|