/*
* Copyright (C) 2013 University of Dundee & Open Microscopy Environment.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package ome.util.checksum;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import com.google.common.base.Optional;
import com.google.common.hash.HashCode;
import com.google.common.hash.HashFunction;
import com.google.common.hash.Hasher;
import com.google.common.io.Files;
/**
* Abstract skeleton class implementing {@link ChecksumProvider} and providing
* implementations of the interface methods using a universal checksum class
* object. Classes extending this class shall pass in a concrete checksum
* algorithm implementation (a {@link HashFunction} instance) as the constructor
* parameter.
*
* @author Blazej Pindelski, bpindelski at dundee.ac.uk
* @since 4.4.7
*/
public class AbstractChecksumProvider implements ChecksumProvider {
private final HashFunction hashFunction;
private Hasher hasher;
private Optional<HashCode> hashCode = Optional.absent();
private Optional<byte[]> hashBytes = Optional.absent();
private Optional<String> hashString = Optional.absent();
/**
* Protected ctor. There should not be an instance of this class.
* @param hashFunction
*/
protected AbstractChecksumProvider(HashFunction hashFunction) {
this.hashFunction = hashFunction;
this.hasher = this.hashFunction.newHasher();
}
/**
* @see ChecksumProvider#putBytes(byte[])
*/
public ChecksumProvider putBytes(byte[] byteArray) {
return this.putBytes(byteArray, 0, byteArray.length);
}
/**
* @see ChecksumProvider#putBytes(byte[], int, int)
*/
public ChecksumProvider putBytes(byte[] byteArray, int offset, int length) {
this.verifyState(this.hashBytes, this.hashString);
this.hasher.putBytes(byteArray, offset, length);
return this;
}
/**
* @see ChecksumProvider#putBytes(ByteBuffer)
*/
public ChecksumProvider putBytes(ByteBuffer byteBuffer) {
this.verifyState(this.hashBytes, this.hashString);
if (byteBuffer.hasArray()) {
this.hasher.putBytes(byteBuffer.array(), 0, byteBuffer.limit());
return this;
} else {
throw new IllegalArgumentException("Supplied ByteBuffer has " +
"inaccessible array.");
}
}
/**
* @see ChecksumProvider#putFile(String)
*/
public ChecksumProvider putFile(String filePath) {
this.verifyState(this.hashBytes, this.hashString);
try {
this.hashCode = Optional.of(
Files.hash(new File(filePath), this.hashFunction));
return this;
} catch (IOException io) {
throw new RuntimeException(io);
}
}
/**
* @see ChecksumProvider#checksumAsBytes()
*/
public byte[] checksumAsBytes() {
this.hashBytes = Optional.of(this.pickChecksum().asBytes());
return this.hashBytes.get();
}
/**
* @see ChecksumProvider#checksumAsString()
*/
public String checksumAsString() {
this.hashString = Optional.of(this.pickChecksum().toString());
return this.hashString.get();
}
private HashCode pickChecksum() {
return this.hashCode.isPresent() ?
this.hashCode.get() : this.hasher.hash();
}
private void verifyState(Optional... optionalObjects) {
for (Optional optionalObject : optionalObjects) {
if (optionalObject.isPresent()) {
throw new IllegalStateException("Checksum state already set. " +
"Mutation illegal.");
}
}
}
}