diff --git a/common/source/java/ch/systemsx/cisd/common/io/ByteArrayBasedContentNode.java b/common/source/java/ch/systemsx/cisd/common/io/ByteArrayBasedContentNode.java index 33c6d6920a5e7f2199352c4ddc6293996498b841..4f3da04d574390c0ef954026e76c3ae406ddc020 100644 --- a/common/source/java/ch/systemsx/cisd/common/io/ByteArrayBasedContentNode.java +++ b/common/source/java/ch/systemsx/cisd/common/io/ByteArrayBasedContentNode.java @@ -40,6 +40,8 @@ public class ByteArrayBasedContentNode implements IHierarchicalContentNode private final String nameOrNull; private long lastModified; + + private Long checksum; /** * Creates an instance for the specified byte array. @@ -114,6 +116,15 @@ public class ByteArrayBasedContentNode implements IHierarchicalContentNode return byteArray.length; } + public long getChecksumCRC32() throws UnsupportedOperationException + { + if (checksum == null) + { + checksum = IOUtilities.getChecksumCRC32(new ByteArrayInputStream(byteArray)); + } + return checksum; + } + public IRandomAccessFile getFileContent() throws UnsupportedOperationException, IOExceptionUnchecked { diff --git a/common/source/java/ch/systemsx/cisd/common/io/FileBasedContentNode.java b/common/source/java/ch/systemsx/cisd/common/io/FileBasedContentNode.java index dcaa21daf374ae4707da7cdb929c39f076b6f196..1d94123442a840e8f80485c44dc2d669a7ceaf63 100644 --- a/common/source/java/ch/systemsx/cisd/common/io/FileBasedContentNode.java +++ b/common/source/java/ch/systemsx/cisd/common/io/FileBasedContentNode.java @@ -20,9 +20,12 @@ import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.IOException; import java.io.InputStream; import java.util.List; +import org.apache.commons.io.FileUtils; + import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel; import ch.systemsx.cisd.base.exceptions.IOExceptionUnchecked; import ch.systemsx.cisd.base.io.IRandomAccessFile; @@ -121,6 +124,17 @@ public class FileBasedContentNode implements IHierarchicalContentNode return file.length(); } + public long getChecksumCRC32() throws UnsupportedOperationException + { + try + { + return FileUtils.checksumCRC32(file); + } catch (IOException ex) + { + throw CheckedExceptionTunnel.wrapIfNecessary(ex); + } + } + public IRandomAccessFile getFileContent() throws UnsupportedOperationException, IOExceptionUnchecked { diff --git a/common/source/java/ch/systemsx/cisd/common/io/HierarchicalContentNodeBasedHierarchicalContentNode.java b/common/source/java/ch/systemsx/cisd/common/io/HierarchicalContentNodeBasedHierarchicalContentNode.java index 412b4e3bf431598b838c3b77011ad00a8ccd1d7b..5c898ac4fdd054592c7a97aba4907c2c6a9811f5 100644 --- a/common/source/java/ch/systemsx/cisd/common/io/HierarchicalContentNodeBasedHierarchicalContentNode.java +++ b/common/source/java/ch/systemsx/cisd/common/io/HierarchicalContentNodeBasedHierarchicalContentNode.java @@ -72,6 +72,11 @@ public class HierarchicalContentNodeBasedHierarchicalContentNode implements return 0; } + public long getChecksumCRC32() throws UnsupportedOperationException + { + return 0; + } + public IRandomAccessFile getFileContent() throws UnsupportedOperationException, IOExceptionUnchecked { @@ -172,6 +177,11 @@ public class HierarchicalContentNodeBasedHierarchicalContentNode implements return getContent().getFileLength(); } + public long getChecksumCRC32() throws UnsupportedOperationException + { + return getContent().getChecksumCRC32(); + } + public IRandomAccessFile getFileContent() throws UnsupportedOperationException, IOExceptionUnchecked { diff --git a/common/source/java/ch/systemsx/cisd/common/io/IOUtilities.java b/common/source/java/ch/systemsx/cisd/common/io/IOUtilities.java new file mode 100644 index 0000000000000000000000000000000000000000..7bef4b9d6a67b6f7e45f16968d5beccdfff30338 --- /dev/null +++ b/common/source/java/ch/systemsx/cisd/common/io/IOUtilities.java @@ -0,0 +1,56 @@ +/* + * Copyright 2012 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.common.io; + +import java.io.IOException; +import java.io.InputStream; +import java.util.zip.CRC32; +import java.util.zip.CheckedInputStream; +import java.util.zip.Checksum; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.io.output.NullOutputStream; + +import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel; + +/** + * Useful utility methods. + * + * @author Franz-Josef Elmer + */ +public class IOUtilities +{ + /** + * Calculates the CRC32 checksum of specified input stream. + * Note, that the input stream is closed after invocation of this method. + */ + public static long getChecksumCRC32(InputStream inputStream) + { + Checksum checksummer = new CRC32(); + InputStream in = null; + try { + in = new CheckedInputStream(inputStream, checksummer); + IOUtils.copy(in, new NullOutputStream()); + } catch (IOException ex) + { + throw CheckedExceptionTunnel.wrapIfNecessary(ex); + } finally { + IOUtils.closeQuietly(in); + } + return checksummer.getValue(); + } +} diff --git a/common/source/java/ch/systemsx/cisd/common/io/hierarchical_content/AbstractHierarchicalContentNode.java b/common/source/java/ch/systemsx/cisd/common/io/hierarchical_content/AbstractHierarchicalContentNode.java index 61e7f9ce7df6fa8d09c04c80e05303c7e94c207a..67b688939520f9a5126cbd7eaea2df6498cabbea 100644 --- a/common/source/java/ch/systemsx/cisd/common/io/hierarchical_content/AbstractHierarchicalContentNode.java +++ b/common/source/java/ch/systemsx/cisd/common/io/hierarchical_content/AbstractHierarchicalContentNode.java @@ -47,6 +47,9 @@ public abstract class AbstractHierarchicalContentNode implements IHierarchicalCo /** Returns size of a node known NOT to be a directory. */ abstract protected long doGetFileLength(); + /** Returns checksum of a node known NOT to be a directory. */ + abstract protected long doGetChecksumCRC32(); + /** Returns {@link IRandomAccessFile} of a node known NOT to be a directory. */ abstract protected IRandomAccessFile doGetFileContent(); @@ -92,6 +95,12 @@ public abstract class AbstractHierarchicalContentNode implements IHierarchicalCo return doGetFileLength(); } + public long getChecksumCRC32() throws UnsupportedOperationException + { + failOnDirectory(); + return doGetChecksumCRC32(); + } + public final IRandomAccessFile getFileContent() { failOnDirectory(); diff --git a/common/source/java/ch/systemsx/cisd/common/io/hierarchical_content/AbstractHierarchicalDirectoryContentNode.java b/common/source/java/ch/systemsx/cisd/common/io/hierarchical_content/AbstractHierarchicalDirectoryContentNode.java index c53211cca47c5bb414eebcc26b71035398527c97..22d9261b50cfc165c3fe0a537d485fdb342d2816 100644 --- a/common/source/java/ch/systemsx/cisd/common/io/hierarchical_content/AbstractHierarchicalDirectoryContentNode.java +++ b/common/source/java/ch/systemsx/cisd/common/io/hierarchical_content/AbstractHierarchicalDirectoryContentNode.java @@ -34,6 +34,12 @@ public abstract class AbstractHierarchicalDirectoryContentNode extends throw new UnsupportedOperationException(OPERATION_NOT_SUPPORTED_FOR_A_DIRECTORY); } + @Override + protected long doGetChecksumCRC32() + { + throw new UnsupportedOperationException(OPERATION_NOT_SUPPORTED_FOR_A_DIRECTORY); + } + @Override protected final IRandomAccessFile doGetFileContent() { diff --git a/common/source/java/ch/systemsx/cisd/common/io/hierarchical_content/DefaultFileBasedHierarchicalContentNode.java b/common/source/java/ch/systemsx/cisd/common/io/hierarchical_content/DefaultFileBasedHierarchicalContentNode.java index fac958829efb872a0a20ff7de4ac5cdbf8ee21de..4655beb189c03d25887b6ca64324cc3245ada105 100644 --- a/common/source/java/ch/systemsx/cisd/common/io/hierarchical_content/DefaultFileBasedHierarchicalContentNode.java +++ b/common/source/java/ch/systemsx/cisd/common/io/hierarchical_content/DefaultFileBasedHierarchicalContentNode.java @@ -19,10 +19,13 @@ package ch.systemsx.cisd.common.io.hierarchical_content; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; +import org.apache.commons.io.FileUtils; + import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel; import ch.systemsx.cisd.base.io.IRandomAccessFile; import ch.systemsx.cisd.base.io.RandomAccessFileImpl; @@ -119,6 +122,18 @@ class DefaultFileBasedHierarchicalContentNode extends AbstractHierarchicalConten return file.length(); } + @Override + protected long doGetChecksumCRC32() + { + try + { + return FileUtils.checksumCRC32(file); + } catch (IOException ex) + { + throw CheckedExceptionTunnel.wrapIfNecessary(ex); + } + } + @Override public IRandomAccessFile doGetFileContent() { diff --git a/common/source/java/ch/systemsx/cisd/common/io/hierarchical_content/HDF5ContainerBasedHierarchicalContentNode.java b/common/source/java/ch/systemsx/cisd/common/io/hierarchical_content/HDF5ContainerBasedHierarchicalContentNode.java index 234cdf081e5f49efcff63907fd933addf019c516..e1d55337195838f2af58c9d266c429beb3e4fcb9 100644 --- a/common/source/java/ch/systemsx/cisd/common/io/hierarchical_content/HDF5ContainerBasedHierarchicalContentNode.java +++ b/common/source/java/ch/systemsx/cisd/common/io/hierarchical_content/HDF5ContainerBasedHierarchicalContentNode.java @@ -27,6 +27,7 @@ import ch.systemsx.cisd.base.io.AdapterIInputStreamToInputStream; import ch.systemsx.cisd.base.io.IRandomAccessFile; import ch.systemsx.cisd.common.hdf5.HDF5Container; import ch.systemsx.cisd.common.hdf5.IHDF5ContainerReader; +import ch.systemsx.cisd.common.io.IOUtilities; import ch.systemsx.cisd.common.io.hierarchical_content.api.IHierarchicalContent; import ch.systemsx.cisd.common.io.hierarchical_content.api.IHierarchicalContentNode; import ch.systemsx.cisd.hdf5.h5ar.ArchiveEntry; @@ -259,6 +260,8 @@ public class HDF5ContainerBasedHierarchicalContentNode extends private HDF5DataSetBasedContent contentOrNull; private final HDF5ContainerBasedHierarchicalContentNode containerNode; + + private Long checksum; public HDF5FileNode(HDF5ContainerBasedHierarchicalContentNode containerNode, ArchiveEntry entry) @@ -310,6 +313,23 @@ public class HDF5ContainerBasedHierarchicalContentNode extends return entry.getSize(); } + @Override + protected long doGetChecksumCRC32() + { + if (checksum == null) + { + int entryChecksum = entry.getCrc32(); + if (entryChecksum != 0) + { + checksum = (long) entryChecksum; + } else + { + checksum = IOUtilities.getChecksumCRC32(doGetInputStream()); + } + } + return checksum; + } + @Override protected IRandomAccessFile doGetFileContent() { diff --git a/common/source/java/ch/systemsx/cisd/common/io/hierarchical_content/VirtualHierarchicalContent.java b/common/source/java/ch/systemsx/cisd/common/io/hierarchical_content/VirtualHierarchicalContent.java index fc1fe9c6b3c683996884af8e13f3dc50319042b4..9037e3a624405c075b544bf82215736e1e8b3b6f 100644 --- a/common/source/java/ch/systemsx/cisd/common/io/hierarchical_content/VirtualHierarchicalContent.java +++ b/common/source/java/ch/systemsx/cisd/common/io/hierarchical_content/VirtualHierarchicalContent.java @@ -437,6 +437,11 @@ class VirtualHierarchicalContent implements IHierarchicalContent } } + public long getChecksumCRC32() throws UnsupportedOperationException + { + return lastExistingNode().getChecksumCRC32(); + } + public IRandomAccessFile getFileContent() throws UnsupportedOperationException, IOExceptionUnchecked { diff --git a/common/source/java/ch/systemsx/cisd/common/io/hierarchical_content/api/IHierarchicalContentNode.java b/common/source/java/ch/systemsx/cisd/common/io/hierarchical_content/api/IHierarchicalContentNode.java index 4e18a1e3cc4e35e3d1e5924477d07941a3175179..0022b9e3c346e42cf0684db60fe8092438727956 100644 --- a/common/source/java/ch/systemsx/cisd/common/io/hierarchical_content/api/IHierarchicalContentNode.java +++ b/common/source/java/ch/systemsx/cisd/common/io/hierarchical_content/api/IHierarchicalContentNode.java @@ -91,6 +91,15 @@ public interface IHierarchicalContentNode * @throws UnsupportedOperationException if the node is an abstraction of a directory. */ long getFileLength() throws UnsupportedOperationException; + + /** + * Returns the CRC32 checksum of a file abstracted by this node. + * <p> + * NOTE: Call {@link #isDirectory()} first to make sure this node is NOT a directory. + * + * @throws UnsupportedOperationException if the node is an abstraction of a directory. + */ + long getChecksumCRC32() throws UnsupportedOperationException; /** * Returns a read only {@link IRandomAccessFile} with file content of the node. * diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/io/hierarchical_content/AbstractHierarchicalContentNodeTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/io/hierarchical_content/AbstractHierarchicalContentNodeTest.java index f45da3dbb92baec92e0bb7d9e4dff316db4ea165..09cd68e2c485fa3f14e7abe3e6b415963c2e4b82 100644 --- a/common/sourceTest/java/ch/systemsx/cisd/common/io/hierarchical_content/AbstractHierarchicalContentNodeTest.java +++ b/common/sourceTest/java/ch/systemsx/cisd/common/io/hierarchical_content/AbstractHierarchicalContentNodeTest.java @@ -171,6 +171,12 @@ public class AbstractHierarchicalContentNodeTest extends AssertJUnit return 0; } + @Override + protected long doGetChecksumCRC32() + { + return 0; + } + @Override protected IRandomAccessFile doGetFileContent() { @@ -238,6 +244,12 @@ public class AbstractHierarchicalContentNodeTest extends AssertJUnit return 0; } + @Override + protected long doGetChecksumCRC32() + { + return 0; + } + @Override protected IRandomAccessFile doGetFileContent() { diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/io/hierarchical_content/DefaultFileBasedHierarchicalContentTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/io/hierarchical_content/DefaultFileBasedHierarchicalContentTest.java index 1070487d7bf63b841dacad140665a3c0c138e32f..bf4f46190e74c6632b484640de6e7515e0ff81e4 100644 --- a/common/sourceTest/java/ch/systemsx/cisd/common/io/hierarchical_content/DefaultFileBasedHierarchicalContentTest.java +++ b/common/sourceTest/java/ch/systemsx/cisd/common/io/hierarchical_content/DefaultFileBasedHierarchicalContentTest.java @@ -659,6 +659,11 @@ public class DefaultFileBasedHierarchicalContentTest extends AbstractFileSystemT throw new UnsupportedOperationException(METHOD_NOT_IMPLEMENTED); } + public long getChecksumCRC32() throws UnsupportedOperationException + { + throw new UnsupportedOperationException(METHOD_NOT_IMPLEMENTED); + } + public InputStream getInputStream() throws UnsupportedOperationException, IOExceptionUnchecked { diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/content/PathInfoProviderBasedHierarchicalContent.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/content/PathInfoProviderBasedHierarchicalContent.java index 60998aad20ff135baf25b16dddfbda2bbcb26655..16a1a5e7a0a0a37ae994d123927aaec52dc67119 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/content/PathInfoProviderBasedHierarchicalContent.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/content/PathInfoProviderBasedHierarchicalContent.java @@ -237,6 +237,13 @@ class PathInfoProviderBasedHierarchicalContent implements IHierarchicalContent return pathInfo.getSizeInBytes(); } + @Override + protected long doGetChecksumCRC32() + { + // TODO Auto-generated method stub + return 0; + } + public File getFile() throws UnsupportedOperationException { File result = doGetFile(); diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/ImageUtilTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/ImageUtilTest.java index c20da02064ba7c82fd7291282091b70ff54f03e7..e5c728592c4a54f000038ad73b48f29209c6db82 100644 --- a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/ImageUtilTest.java +++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/ImageUtilTest.java @@ -94,6 +94,11 @@ public class ImageUtilTest extends AssertJUnit throw new UnsupportedOperationException(); } + public long getChecksumCRC32() throws UnsupportedOperationException + { + throw new UnsupportedOperationException(); + } + public IRandomAccessFile getFileContent() throws UnsupportedOperationException, IOExceptionUnchecked {