Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
7a310f7
Introduce AbstractChecksumProvider and refactor
Feb 26, 2013
f9a1e1c
Remove default provider and update consumers
Mar 5, 2013
2706846
Bring back Utils methods and deprecate them
Mar 5, 2013
30e089a
Fix omero.client classpath error (see #10487)
Mar 5, 2013
1accc3d
Refactor ChecksumProvider into a fluent interface
Mar 6, 2013
b8a92d4
Refactor checksum test classes
Mar 7, 2013
d09a8e1
Rename methods in ChecksumProvider interface
Mar 7, 2013
598cf0d
Propagate new checksum usage through codebase
Mar 7, 2013
32c6f60
Update commons-codec to 1.6
Mar 7, 2013
72a067b
Add commons-codec to omero-common
Mar 7, 2013
575db4f
Replace bytesToHex methods with commons-codec
Mar 7, 2013
57b2321
Fix checksumProviderFactory missing in Spring ctx
Mar 8, 2013
3d1a843
Update Javadoc with @deprecated note
Mar 11, 2013
c2e61f8
Use checksumAsString instead of Hex.encode*
Mar 11, 2013
34b9efa
Make the Javadoc explicit about calling reset()
Mar 11, 2013
ecf3d93
Remove the commons-codec from omero-common
Mar 11, 2013
2521dbd
Use guava.Files when calculating file checksum
Mar 11, 2013
a08c1c3
Add missing Javadoc and remove unused field
Mar 12, 2013
c483d27
Remove reset(), rename method and update comments
Mar 12, 2013
493fb8e
Add logic for defensive checksumAs* methods
Mar 12, 2013
2556eac
Fix tests and consumers to use new method name
Mar 13, 2013
827e3fe
Adjust putBytes for truncated byte buffers.
mtbc Mar 13, 2013
095d0a7
Merge pull request #1 from mtbc/bytebuffer-limit
Mar 14, 2013
ab8a12b
Add unit test for truncated ByteBuffer
Mar 14, 2013
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions components/blitz/src/ome/services/blitz/impl/ScriptI.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import ome.tools.hibernate.QueryBuilder;
import ome.util.Utils;
import ome.util.checksum.ChecksumProviderFactory;
import ome.util.checksum.ChecksumType;

import omero.ApiUsageException;
import omero.RInt;
Expand Down Expand Up @@ -586,8 +587,8 @@ private OriginalFile makeFile(final String path, final String script,
file.setPath(FilenameUtils.getFullPath(path));
file.setMimetype(ParamsHelper.PYTHONSCRIPT);
file.setSize((long) script.getBytes().length);
file.setSha1(Utils.bytesToHex(
cpf.getProvider().getChecksum(script.getBytes())));
file.setSha1(cpf.getProvider(ChecksumType.SHA1)
.putBytes(script.getBytes()).checksumAsString());
return updateFile(file, current);
}

Expand Down
4 changes: 3 additions & 1 deletion components/blitz/src/ome/services/scripts/ScriptFinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import ome.util.Utils;
import ome.util.checksum.ChecksumProviderFactory;
import ome.util.checksum.ChecksumProviderFactoryImpl;
import ome.util.checksum.ChecksumType;
import omero.model.OriginalFileI;
import omero.model.ScriptJob;
import omero.model.ScriptJobI;
Expand Down Expand Up @@ -86,7 +87,8 @@ public OriginalFileI getFile(ServiceFactory sf) {
ChecksumProviderFactory cpf = new ChecksumProviderFactoryImpl();
try {
final byte[] buf = FileUtils.readFileToByteArray(source);
final String sha1 = Utils.bytesToHex(cpf.getProvider().getChecksum(buf));
final String sha1 = cpf.getProvider(ChecksumType.SHA1)
.putBytes(buf).checksumAsString();
log.debug("Loading script: " + sha1);

Parameters p = new Parameters();
Expand Down
6 changes: 3 additions & 3 deletions components/blitz/src/omero/client.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import ome.util.Utils;
import ome.util.checksum.ChecksumProviderFactory;
import ome.util.checksum.ChecksumProviderFactoryImpl;
import ome.util.checksum.ChecksumType;
import omero.api.ClientCallback;
import omero.api.ClientCallbackPrxHelper;
import omero.api.IAdminPrx;
Expand Down Expand Up @@ -928,9 +929,8 @@ public int killSession() {
*/
public String sha1(File file) {
ChecksumProviderFactory cpf = new ChecksumProviderFactoryImpl();
return Utils.bytesToHex(
cpf.getProvider().getChecksum(
file.getAbsolutePath()));
return cpf.getProvider(ChecksumType.SHA1).putFile(
file.getAbsolutePath()).checksumAsString();
}

public OriginalFile upload(File file) throws ServerError, IOException {
Expand Down
129 changes: 129 additions & 0 deletions components/common/src/ome/util/checksum/AbstractChecksumProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* 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) {
this.verifyState(this.hashBytes, this.hashString);
this.hasher.putBytes(byteArray);
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#putBytes(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.");
}
}
}
}
70 changes: 48 additions & 22 deletions components/common/src/ome/util/checksum/ChecksumProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,45 +22,71 @@
import java.nio.ByteBuffer;

/**
* A provider producing checksum or message digests (depending on the
* implementing class) of a given type of input. Inside the
* <code>ome.util.checksum</code> package, the term <i>checksum</i>
* An interface producing checksums or message digests (depending on the
* implementing class) of a given type of input. The object's internal state
* represents the current checksum value and each call to <code>putBytes()</code>
* updates this object's internal state. It is the callers responsibility to
* make sure calls to {@link ChecksumProvider#putFile(String)} are not intermixed
* with <code>putBytes()</code>. This object can only return a checksum for
* a file or byte structure, never both.
* <br/>
* Inside the <code>ome.util.checksum</code> package, the term <i>checksum</i>
* is understood as an "umbrella" term covering checksums, message digests and
* hashes. An UnsupportedOperationException is thrown for methods which were
* not present in the Utils class, which this interface supersedes.
* hashes.
*
* @author Blazej Pindelski, bpindelski at dundee.ac.uk
* @since 4.4.7
*/
public interface ChecksumProvider {

/**
* Returns a checksum of a byte array. If the array is null, throws NPE.
* Note that, although checksum results are consistent for any given hash
* function and byte array, different hash functions may calculate different
* checksums for an empty array despite its lack of content.
* Updates the internal checksum value with data from a byte array.
* If the array is null, throws NPE. Note that, although checksum results
* are consistent for any given hash function and byte array, different hash
* functions may calculate different checksums for an empty array despite
* its lack of content.
*
* @param buffer The input byte array.
* @return Checksum bytes inside an array.
* @param byteArray The input byte array.
* @return ChecksumProvider
*/
byte[] getChecksum(byte[] buffer);
ChecksumProvider putBytes(byte[] byteArray);

/**
* Returns a checksum of a file identified by a path. Throws a
* RuntimeException in a case of an IO error.
* Updates the internal checksum value with data from a byte buffer.
* If the array underlying the byte buffer is not accessible, throws an
* IllegalArgumentException.
*
* @param fileName <code>String</code> representing the absolute file path.
* @return Checksum bytes inside an array.
* @param byteBuffer The input byte buffer.
* @return ChecksumProvider
*/
byte[] getChecksum(String fileName);
ChecksumProvider putBytes(ByteBuffer byteBuffer);

/**
* Returns a checksum of a byte buffer. If the array underlying the byte
* buffer is not accessible, throws an IllegalArgumentException.
* Updates the internal checksum value with data from a file identified by a
* path. Throws a RuntimeException in a case of an IO error.
*
* @param buffer The input byte buffer.
* @return Checksum bytes inside an array.
* @param filePath <code>String</code> representing the absolute file path.
* @return ChecksumProvider
*/
byte[] getChecksum(ByteBuffer buffer);
ChecksumProvider putFile(String filePath);

/**
* Returns a byte array representation of the calculated checksum.
* Subsequent calls to this method will return the same object state. After
* calling this method any invocation of the mutating methods
* (<code>put*</code>) will cause it to throw IllegalStateException.
*
* @return <code>byte[]</code> The checksum in a byte array.
*/
byte[] checksumAsBytes();

/**
* Returns a <code>String</code> representing the checksum in hex form.
* Subsequent calls to this method will return the same object state. After
* calling this method any invocation of the mutating methods
* (<code>put*</code>) will cause it to throw IllegalStateException.
*
* @return <code>String</code> The hexadecimal value of the checksum.
*/
String checksumAsString();
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,12 @@

/**
* A factory producing throw-away objects of the {@link ChecksumProvider} type.
* If no {@link ChecksumType} given, defaults to SHA1.
*
* @author Blazej Pindelski, bpindelski at dundee.ac.uk
* @since 4.4.7
*/
public interface ChecksumProviderFactory {

/**
* Returns the default SHA1 {@link ChecksumProvider}.
*
* @return A SHA1 {@link ChecksumProvider}.
*/
ChecksumProvider getProvider();

/**
* Returns an implementation of {@link ChecksumProvider} depending on the
* specified {@link ChecksumType}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,6 @@
*/
public class ChecksumProviderFactoryImpl implements ChecksumProviderFactory {

/**
* @see ChecksumProviderFactory#getProvider()
*/
public ChecksumProvider getProvider() {
return this.getProvider(ChecksumType.SHA1);
}

/**
* @see ChecksumProviderFactory#getProvider(ChecksumType)
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,47 +19,19 @@

package ome.util.checksum;

import com.google.common.hash.HashFunction;
import com.google.common.hash.Hashing;

import java.nio.ByteBuffer;

/**
* An implementation of the {@link ChecksumProvider} interface using MD5
* as the message digest algorithm.
*
* @author Blazej Pindelski, bpindelski at dundee.ac.uk
* @since 4.4.7
*/
public class MD5ChecksumProviderImpl implements ChecksumProvider {

private final HashFunction md5 = Hashing.md5();

/**
* @see ChecksumProvider#getChecksum(byte[])
*/
public byte[] getChecksum(byte[] rawData) {
return this.md5.newHasher().putBytes(rawData).hash().asBytes();
}

/**
* @see ChecksumProvider#getChecksum(ByteBuffer)
*/
public byte[] getChecksum(ByteBuffer byteBuffer) {
if (byteBuffer.hasArray()) {
return this.md5.newHasher().putBytes(byteBuffer.array()).hash().asBytes();
} else {
throw new IllegalArgumentException("Supplied ByteBuffer has " +
"inaccessible array.");
}
}
public final class MD5ChecksumProviderImpl extends AbstractChecksumProvider {

/**
* @see ChecksumProvider#getChecksum(String)
*/
public byte[] getChecksum(String filePath) {
throw new UnsupportedOperationException("Method not "
+ "implemented for file path String.");
public MD5ChecksumProviderImpl() {
super(Hashing.md5());
}

}
Loading