diff --git a/src/main/java/htsjdk/samtools/cram/build/CramIO.java b/src/main/java/htsjdk/samtools/cram/build/CramIO.java index bd7a5d3420..166e9c4259 100644 --- a/src/main/java/htsjdk/samtools/cram/build/CramIO.java +++ b/src/main/java/htsjdk/samtools/cram/build/CramIO.java @@ -29,7 +29,6 @@ import htsjdk.samtools.cram.structure.ContainerIO; import htsjdk.samtools.cram.structure.CramHeader; import htsjdk.samtools.cram.structure.Slice; -import htsjdk.samtools.cram.structure.block.FileHeaderBlock; import htsjdk.samtools.seekablestream.SeekableFileStream; import htsjdk.samtools.seekablestream.SeekableStream; import htsjdk.samtools.util.BufferedLineReader; @@ -249,7 +248,7 @@ private static long writeContainerForSamFileHeader(final int major, final SAMFil final int length = Math.max(1024, data.length + data.length / 2); final byte[] blockContent = new byte[length]; System.arraycopy(data, 0, blockContent, 0, Math.min(data.length, length)); - final FileHeaderBlock block = Block.uncompressedFileHeaderBlock(blockContent); + final Block block = Block.uncompressedFileHeaderBlock(blockContent); final Container container = new Container(); container.blockCount = 1; @@ -328,7 +327,7 @@ public static boolean replaceCramHeader(final File file, final CramHeader newHea final long pos = countingInputStream.getCount(); countingInputStream.close(); - final FileHeaderBlock block = Block.uncompressedFileHeaderBlock(toByteArray(newHeader.getSamFileHeader())); + final Block block = Block.uncompressedFileHeaderBlock(toByteArray(newHeader.getSamFileHeader())); final ExposedByteArrayOutputStream byteArrayOutputStream = new ExposedByteArrayOutputStream(); block.write(newHeader.getVersion().major, byteArrayOutputStream); if (byteArrayOutputStream.size() > c.containerByteSize) { diff --git a/src/main/java/htsjdk/samtools/cram/structure/ContainerIO.java b/src/main/java/htsjdk/samtools/cram/structure/ContainerIO.java index 38e0223b34..7b9df358ab 100644 --- a/src/main/java/htsjdk/samtools/cram/structure/ContainerIO.java +++ b/src/main/java/htsjdk/samtools/cram/structure/ContainerIO.java @@ -6,8 +6,8 @@ import htsjdk.samtools.cram.io.ExposedByteArrayOutputStream; import htsjdk.samtools.cram.structure.block.Block; import htsjdk.samtools.cram.structure.block.BlockContentType; -import htsjdk.samtools.cram.structure.block.CompressionHeaderBlock; import htsjdk.samtools.util.Log; +import htsjdk.samtools.util.RuntimeIOException; import org.apache.commons.compress.utils.CountingOutputStream; import java.io.ByteArrayInputStream; @@ -81,7 +81,7 @@ private static Container readContainer(final int major, final InputStream inputS return container; } - container.header = CompressionHeaderBlock.readAsCompressionHeader(major, inputStream); + container.header = readAsCompressionHeader(major, inputStream); howManySlices = Math.min(container.landmarks.length, howManySlices); @@ -164,7 +164,7 @@ public static int writeContainer(final Version version, final Container containe final ExposedByteArrayOutputStream byteArrayOutputStream = new ExposedByteArrayOutputStream(); - final CompressionHeaderBlock block = Block.uncompressedCompressionHeaderBlock(container.header.toByteArray()); + final Block block = Block.uncompressedCompressionHeaderBlock(container.header.toByteArray()); block.write(version.major, byteArrayOutputStream); container.blockCount = 1; @@ -217,4 +217,21 @@ public void write(final int b) throws IOException { return countingOutputStream.getBytesWritten(); } + + /** + * Read a COMPRESSION_HEADER Block from an InputStream and return its contents as a CompressionHeader + * + * @param major the CRAM major version number + * @param inputStream the stream to read from + * @return a new CompressionHeader from the input + */ + private static CompressionHeader readAsCompressionHeader(final int major, final InputStream inputStream) { + final Block block = Block.read(major, inputStream); + if (block.getContentType() != BlockContentType.COMPRESSION_HEADER) + throw new RuntimeIOException("Content type does not match: " + block.getContentType().name()); + + final CompressionHeader header = new CompressionHeader(); + header.read(block.getUncompressedContent()); + return header; + } } diff --git a/src/main/java/htsjdk/samtools/cram/structure/Slice.java b/src/main/java/htsjdk/samtools/cram/structure/Slice.java index f6e4c26900..dca639a785 100644 --- a/src/main/java/htsjdk/samtools/cram/structure/Slice.java +++ b/src/main/java/htsjdk/samtools/cram/structure/Slice.java @@ -22,9 +22,8 @@ import htsjdk.samtools.cram.encoding.reader.MultiRefSliceAlignmentSpanReader; import htsjdk.samtools.cram.io.BitInputStream; import htsjdk.samtools.cram.io.DefaultBitInputStream; -import htsjdk.samtools.cram.structure.block.CoreDataBlock; +import htsjdk.samtools.cram.structure.block.Block; import htsjdk.samtools.cram.structure.block.ExternalDataBlock; -import htsjdk.samtools.cram.structure.block.SliceHeaderBlock; import htsjdk.samtools.util.Log; import htsjdk.samtools.util.SequenceUtil; @@ -56,8 +55,8 @@ public class Slice { public byte[] refMD5 = new byte[16]; // content associated with ids: - public SliceHeaderBlock headerBlock; - public CoreDataBlock coreBlock; + public Block headerBlock; + public Block coreBlock; public ExternalDataBlock embeddedRefBlock; public Map external; diff --git a/src/main/java/htsjdk/samtools/cram/structure/SliceIO.java b/src/main/java/htsjdk/samtools/cram/structure/SliceIO.java index 56986d07ea..ee057c31ae 100644 --- a/src/main/java/htsjdk/samtools/cram/structure/SliceIO.java +++ b/src/main/java/htsjdk/samtools/cram/structure/SliceIO.java @@ -39,7 +39,9 @@ class SliceIO { private static final Log log = Log.getInstance(SliceIO.class); private static void readSliceHeader(final int major, final Slice slice, final InputStream readInputStream) throws IOException { - slice.headerBlock = SliceHeaderBlock.read(major, readInputStream); + slice.headerBlock = Block.read(major, readInputStream); + if (slice.headerBlock.getContentType() != BlockContentType.MAPPED_SLICE) + throw new RuntimeException("Content type does not match: " + slice.headerBlock.getContentType().name()); final InputStream parseInputStream = new ByteArrayInputStream(slice.headerBlock.getUncompressedContent()); @@ -110,7 +112,7 @@ private static void readSliceBlocks(final int major, final Slice slice, final In switch (block.getContentType()) { case CORE: - slice.coreBlock = (CoreDataBlock) block; + slice.coreBlock = block; break; case EXTERNAL: final ExternalDataBlock extBlock = (ExternalDataBlock) block; diff --git a/src/main/java/htsjdk/samtools/cram/structure/block/Block.java b/src/main/java/htsjdk/samtools/cram/structure/block/Block.java index 4bcf1ffb2d..288bea86d4 100644 --- a/src/main/java/htsjdk/samtools/cram/structure/block/Block.java +++ b/src/main/java/htsjdk/samtools/cram/structure/block/Block.java @@ -35,7 +35,7 @@ * methods, for example to read a block from an input stream. Blocks can be written out to an output stream, this may be considered as a way * to serialize/deserialize blocks. */ -public abstract class Block { +public class Block { /** * Only external blocks have meaningful Content IDs * Other blocks are required to have a Content ID of 0 @@ -63,7 +63,7 @@ public abstract class Block { private final int uncompressedLength; /** - * Abstract constructor of a generic Block, to be called by subclasses. + * Private constructor of a generic Block, to be called by static factory methods and subclasses. * * @param method the block compression method. Can be RAW, if uncompressed * @param type whether this is a header or data block, and which kind @@ -95,10 +95,10 @@ protected Block(final BlockCompressionMethod method, * The block will have RAW (no) compression and FILE_HEADER content type. * * @param rawContent the uncompressed content of the block - * @return a new {@link FileHeaderBlock} object + * @return a new {@link Block} object */ - public static FileHeaderBlock uncompressedFileHeaderBlock(final byte[] rawContent) { - return new FileHeaderBlock(BlockCompressionMethod.RAW, rawContent, rawContent.length); + public static Block uncompressedFileHeaderBlock(final byte[] rawContent) { + return new Block(BlockCompressionMethod.RAW, BlockContentType.FILE_HEADER, rawContent, rawContent.length); } /** @@ -106,10 +106,10 @@ public static FileHeaderBlock uncompressedFileHeaderBlock(final byte[] rawConten * The block will have RAW (no) compression and COMPRESSION_HEADER content type. * * @param rawContent the uncompressed content of the block - * @return a new {@link CompressionHeaderBlock} object + * @return a new {@link Block} object */ - public static CompressionHeaderBlock uncompressedCompressionHeaderBlock(final byte[] rawContent) { - return new CompressionHeaderBlock(BlockCompressionMethod.RAW, rawContent, rawContent.length); + public static Block uncompressedCompressionHeaderBlock(final byte[] rawContent) { + return new Block(BlockCompressionMethod.RAW, BlockContentType.COMPRESSION_HEADER, rawContent, rawContent.length); } /** @@ -117,10 +117,10 @@ public static CompressionHeaderBlock uncompressedCompressionHeaderBlock(final by * The block will have RAW (no) compression and MAPPED_SLICE content type. * * @param rawContent the uncompressed content of the block - * @return a new {@link SliceHeaderBlock} object + * @return a new {@link Block} object */ - public static SliceHeaderBlock uncompressedSliceHeaderBlock(final byte[] rawContent) { - return new SliceHeaderBlock(BlockCompressionMethod.RAW, rawContent, rawContent.length); + public static Block uncompressedSliceHeaderBlock(final byte[] rawContent) { + return new Block(BlockCompressionMethod.RAW, BlockContentType.MAPPED_SLICE, rawContent, rawContent.length); } /** @@ -128,10 +128,10 @@ public static SliceHeaderBlock uncompressedSliceHeaderBlock(final byte[] rawCont * The block will have RAW (no) compression and CORE content type. * * @param rawContent the uncompressed content of the block - * @return a new {@link CoreDataBlock} object + * @return a new {@link Block} object */ - public static CoreDataBlock uncompressedCoreBlock(final byte[] rawContent) { - return new CoreDataBlock(BlockCompressionMethod.RAW, rawContent, rawContent.length); + public static Block uncompressedCoreBlock(final byte[] rawContent) { + return new Block(BlockCompressionMethod.RAW, BlockContentType.CORE, rawContent, rawContent.length); } /** @@ -233,19 +233,10 @@ public static Block read(final int major, InputStream inputStream) { } } - switch (type) { - case FILE_HEADER: - return new FileHeaderBlock(method, compressedContent, uncompressedSize); - case COMPRESSION_HEADER: - return new CompressionHeaderBlock(method, compressedContent, uncompressedSize); - case MAPPED_SLICE: - return new SliceHeaderBlock(method, compressedContent, uncompressedSize); - case EXTERNAL: - return new ExternalDataBlock(method, compressedContent, uncompressedSize, contentId); - case CORE: - return new CoreDataBlock(method, compressedContent, uncompressedSize); - default: - throw new CRAMException("Unknown BlockContentType " + type.name()); + if (type == BlockContentType.EXTERNAL) { + return new ExternalDataBlock(method, compressedContent, uncompressedSize, contentId); + } else { + return new Block(method, type, compressedContent, uncompressedSize); } } catch (final IOException e) { @@ -258,7 +249,6 @@ public static Block read(final int major, InputStream inputStream) { * * @param major CRAM version major number * @param outputStream output stream to write to - * @throws IOException as per java IO contract */ public final void write(final int major, final OutputStream outputStream) { try { diff --git a/src/main/java/htsjdk/samtools/cram/structure/block/CompressionHeaderBlock.java b/src/main/java/htsjdk/samtools/cram/structure/block/CompressionHeaderBlock.java deleted file mode 100644 index 8e5ed976e3..0000000000 --- a/src/main/java/htsjdk/samtools/cram/structure/block/CompressionHeaderBlock.java +++ /dev/null @@ -1,57 +0,0 @@ -package htsjdk.samtools.cram.structure.block; - -import htsjdk.samtools.cram.structure.CompressionHeader; -import htsjdk.samtools.util.RuntimeIOException; - -import java.io.InputStream; - -/** - * A Block used by Containers to store Compression Header data - */ -public class CompressionHeaderBlock extends Block { - private static final BlockContentType type = BlockContentType.COMPRESSION_HEADER; - - /** - * Create a new compression header block with the given compression method and uncompressed content. - * The block will have COMPRESSION_HEADER content type. - * - * @param method the compression method used in this block - * @param compressedContent the content of this block, in compressed mode - * @param uncompressedLength the length of the content stored in this block when uncompressed - */ - CompressionHeaderBlock(final BlockCompressionMethod method, - final byte[] compressedContent, - final int uncompressedLength) { - super(method, type, compressedContent, uncompressedLength); - } - - /** - * Read a Block from an InputStream using Block.read() and cast to a CompressionHeaderBlock - * if the Block Content Type is correct - * - * @param major the CRAM major version number - * @param inputStream the stream to read from - * @return a new CompressionHeaderBlock from the input - */ - public static CompressionHeaderBlock read(final int major, final InputStream inputStream) { - final Block block = Block.read(major, inputStream); - if (block.getContentType() != type) - throw new RuntimeIOException("Content type does not match: " + block.getContentType().name()); - - return (CompressionHeaderBlock) block; - } - - /** - * Read a CompressionHeaderBlock from an InputStream and return its contents as a CompressionHeader - * - * @param major the CRAM major version number - * @param inputStream the stream to read from - * @return a new CompressionHeader from the input - */ - public static CompressionHeader readAsCompressionHeader(final int major, final InputStream inputStream) { - final CompressionHeaderBlock block = read(major, inputStream); - final CompressionHeader header = new CompressionHeader(); - header.read(block.getUncompressedContent()); - return header; - } -} diff --git a/src/main/java/htsjdk/samtools/cram/structure/block/CoreDataBlock.java b/src/main/java/htsjdk/samtools/cram/structure/block/CoreDataBlock.java deleted file mode 100644 index 9f1e28ec20..0000000000 --- a/src/main/java/htsjdk/samtools/cram/structure/block/CoreDataBlock.java +++ /dev/null @@ -1,22 +0,0 @@ -package htsjdk.samtools.cram.structure.block; - -/** - * A Block used by Slices to store core data - */ -public class CoreDataBlock extends Block { - private static final BlockContentType type = BlockContentType.CORE; - - /** - * Create a new core data block with the given compression method and uncompressed content. - * The block will have CORE content type. - * - * @param method the compression method used in this block - * @param compressedContent the content of this block, in compressed mode - * @param uncompressedLength the length of the content stored in this block when uncompressed - */ - CoreDataBlock(final BlockCompressionMethod method, - final byte[] compressedContent, - final int uncompressedLength) { - super(method, type, compressedContent, uncompressedLength); - } -} diff --git a/src/main/java/htsjdk/samtools/cram/structure/block/ExternalDataBlock.java b/src/main/java/htsjdk/samtools/cram/structure/block/ExternalDataBlock.java index c3acab7931..621f558f87 100644 --- a/src/main/java/htsjdk/samtools/cram/structure/block/ExternalDataBlock.java +++ b/src/main/java/htsjdk/samtools/cram/structure/block/ExternalDataBlock.java @@ -4,8 +4,6 @@ * A Block used by Slices to store data externally */ public class ExternalDataBlock extends Block { - private static final BlockContentType type = BlockContentType.EXTERNAL; - private final int contentId; /** @@ -21,7 +19,7 @@ public class ExternalDataBlock extends Block { final byte[] compressedContent, final int uncompressedLength, final int contentId) { - super(method, type, compressedContent, uncompressedLength); + super(method, BlockContentType.EXTERNAL, compressedContent, uncompressedLength); this.contentId = contentId; } diff --git a/src/main/java/htsjdk/samtools/cram/structure/block/FileHeaderBlock.java b/src/main/java/htsjdk/samtools/cram/structure/block/FileHeaderBlock.java deleted file mode 100644 index d954a125d4..0000000000 --- a/src/main/java/htsjdk/samtools/cram/structure/block/FileHeaderBlock.java +++ /dev/null @@ -1,22 +0,0 @@ -package htsjdk.samtools.cram.structure.block; - -/** - * A Block used by Containers to store File Header data - */ -public class FileHeaderBlock extends Block { - private static final BlockContentType type = BlockContentType.FILE_HEADER; - - /** - * Create a new file header block with the given compression method and uncompressed content. - * The block will have FILE_HEADER content type. - * - * @param method the compression method used in this block - * @param compressedContent the content of this block, in compressed mode - * @param uncompressedLength the length of the content stored in this block when uncompressed - */ - FileHeaderBlock(final BlockCompressionMethod method, - final byte[] compressedContent, - final int uncompressedLength) { - super(method, type, compressedContent, uncompressedLength); - } -} diff --git a/src/main/java/htsjdk/samtools/cram/structure/block/SliceHeaderBlock.java b/src/main/java/htsjdk/samtools/cram/structure/block/SliceHeaderBlock.java deleted file mode 100644 index 42b99278a6..0000000000 --- a/src/main/java/htsjdk/samtools/cram/structure/block/SliceHeaderBlock.java +++ /dev/null @@ -1,40 +0,0 @@ -package htsjdk.samtools.cram.structure.block; - -import java.io.InputStream; - -/** - * A Block used by Slices to store their header data - */ -public class SliceHeaderBlock extends Block { - private static final BlockContentType type = BlockContentType.MAPPED_SLICE; - - /** - * Create a new slice header block with the given compression method and uncompressed content. - * The block will have MAPPED_SLICE content type. - * - * @param method the compression method used in this block - * @param compressedContent the content of this block, in compressed mode - * @param uncompressedLength the length of the content stored in this block when uncompressed - */ - SliceHeaderBlock(final BlockCompressionMethod method, - final byte[] compressedContent, - final int uncompressedLength) { - super(method, type, compressedContent, uncompressedLength); - } - - /** - * Read a Block from an InputStream using Block.read() and cast to a SliceHeaderBlock - * if the Block Content Type is correct - * - * @param major the CRAM major version number - * @param inputStream the stream to read from - * @return a new SliceHeaderBlock from the input - */ - public static SliceHeaderBlock read(final int major, final InputStream inputStream) { - final Block block = Block.read(major, inputStream); - if (block.getContentType() != type) - throw new RuntimeException("Content type does not match: " + block.getContentType().name()); - - return (SliceHeaderBlock) block; - } -} diff --git a/src/test/java/htsjdk/samtools/cram/structure/BlockTest.java b/src/test/java/htsjdk/samtools/cram/structure/BlockTest.java index bd943df691..cb8a970ff7 100644 --- a/src/test/java/htsjdk/samtools/cram/structure/BlockTest.java +++ b/src/test/java/htsjdk/samtools/cram/structure/BlockTest.java @@ -33,16 +33,16 @@ private void contentCheck(final Block actual, public void uncompressedTest() { final byte[] testData = "TEST STRING".getBytes(); - final FileHeaderBlock fhBlock = Block.uncompressedFileHeaderBlock(testData); + final Block fhBlock = Block.uncompressedFileHeaderBlock(testData); contentCheck(fhBlock, testData, testData); - final CompressionHeaderBlock chBlock = Block.uncompressedCompressionHeaderBlock(testData); + final Block chBlock = Block.uncompressedCompressionHeaderBlock(testData); contentCheck(chBlock, testData, testData); - final SliceHeaderBlock shBlock = Block.uncompressedSliceHeaderBlock(testData); + final Block shBlock = Block.uncompressedSliceHeaderBlock(testData); contentCheck(shBlock, testData, testData); - final CoreDataBlock core = Block.uncompressedCoreBlock(testData); + final Block core = Block.uncompressedCoreBlock(testData); contentCheck(core, testData, testData); }