From e80374ba8559a0b124e868d906de9fb59482752c Mon Sep 17 00:00:00 2001 From: Tim Fennell Date: Sat, 25 Apr 2026 08:26:06 -0600 Subject: [PATCH 1/2] Apply Palantir Java Format to entire codebase This is a mechanical reformat of every .java file under src/ via the Palantir Java Format style. There are no behavior changes. The follow-up commit adds the Spotless Gradle plugin that produced this output, wires it into the build as an enforcement step, updates the contributor docs, deletes the obsolete java-style-eclipse.xml and java-style-intellij.xml style guides, and adds .git-blame-ignore-revs so this commit is skipped by `git blame`. The single non-mechanical change in this commit is the removal of one stray "// the imports for unit testing." comment from VariantContextUnitTest.java that was preventing the formatter from treating the surrounding imports as a contiguous block. The comment carried no information. Part of #1761. --- src/main/java/htsjdk/annotations/BetaAPI.java | 7 +- .../java/htsjdk/annotations/InternalAPI.java | 7 +- .../codecs/hapref/fasta/FASTACodecV1_0.java | 34 +- .../codecs/hapref/fasta/FASTADecoderV1_0.java | 35 +- .../beta/codecs/reads/ReadsCodecUtils.java | 56 +- .../beta/codecs/reads/bam/BAMCodec.java | 14 +- .../beta/codecs/reads/bam/BAMDecoder.java | 17 +- .../codecs/reads/bam/BAMDecoderOptions.java | 7 +- .../beta/codecs/reads/bam/BAMEncoder.java | 16 +- .../codecs/reads/bam/BAMEncoderOptions.java | 15 +- .../reads/bam/bamV1_0/BAMCodecV1_0.java | 10 +- .../reads/bam/bamV1_0/BAMDecoderV1_0.java | 14 +- .../reads/bam/bamV1_0/BAMEncoderV1_0.java | 32 +- .../beta/codecs/reads/cram/CRAMCodec.java | 18 +- .../beta/codecs/reads/cram/CRAMDecoder.java | 78 +- .../codecs/reads/cram/CRAMDecoderOptions.java | 6 +- .../beta/codecs/reads/cram/CRAMEncoder.java | 30 +- .../codecs/reads/cram/CRAMEncoderOptions.java | 3 - .../reads/cram/cramV2_1/CRAMCodecV2_1.java | 7 +- .../reads/cram/cramV2_1/CRAMDecoderV2_1.java | 3 +- .../reads/cram/cramV2_1/CRAMEncoderV2_1.java | 3 +- .../reads/cram/cramV3_0/CRAMCodecV3_0.java | 8 +- .../reads/cram/cramV3_0/CRAMDecoderV3_0.java | 1 - .../reads/cram/cramV3_0/CRAMEncoderV3_0.java | 1 - .../reads/cram/cramV3_1/CRAMCodecV3_1.java | 6 +- .../reads/cram/cramV3_1/CRAMDecoderV3_1.java | 1 - .../reads/cram/cramV3_1/CRAMEncoderV3_1.java | 2 - .../codecs/reads/htsget/HtsgetBAMCodec.java | 31 +- .../codecs/reads/htsget/HtsgetBAMDecoder.java | 11 +- .../htsgetBAMV1_2/HtsgetBAMCodecV1_2.java | 13 +- .../htsgetBAMV1_2/HtsgetBAMDecoderV1_2.java | 15 +- .../beta/codecs/reads/sam/SAMCodec.java | 16 +- .../beta/codecs/reads/sam/SAMDecoder.java | 15 +- .../beta/codecs/reads/sam/SAMEncoder.java | 12 +- .../reads/sam/samV1_0/SAMCodecV1_0.java | 7 +- .../reads/sam/samV1_0/SAMDecoderV1_0.java | 7 +- .../reads/sam/samV1_0/SAMEncoderV1_0.java | 27 +- .../beta/codecs/variants/vcf/VCFCodec.java | 25 +- .../beta/codecs/variants/vcf/VCFDecoder.java | 58 +- .../beta/codecs/variants/vcf/VCFEncoder.java | 56 +- .../variants/vcf/VariantsCodecUtils.java | 5 +- .../variants/vcf/vcfv3_2/VCFCodecV3_2.java | 13 +- .../variants/vcf/vcfv3_2/VCFDecoderV3_2.java | 3 +- .../variants/vcf/vcfv3_2/VCFEncoderV3_2.java | 5 +- .../variants/vcf/vcfv3_3/VCFCodecV3_3.java | 13 +- .../variants/vcf/vcfv3_3/VCFDecoderV3_3.java | 3 +- .../variants/vcf/vcfv3_3/VCFEncoderV3_3.java | 5 +- .../variants/vcf/vcfv4_0/VCFCodecV4_0.java | 13 +- .../variants/vcf/vcfv4_0/VCFDecoderV4_0.java | 3 +- .../variants/vcf/vcfv4_0/VCFEncoderV4_0.java | 5 +- .../variants/vcf/vcfv4_1/VCFCodecV4_1.java | 13 +- .../variants/vcf/vcfv4_1/VCFDecoderV4_1.java | 3 +- .../variants/vcf/vcfv4_1/VCFEncoderV4_1.java | 5 +- .../variants/vcf/vcfv4_2/VCFCodecV4_2.java | 11 +- .../variants/vcf/vcfv4_2/VCFDecoderV4_2.java | 1 - .../variants/vcf/vcfv4_2/VCFEncoderV4_2.java | 3 +- .../variants/vcf/vcfv4_3/VCFCodecV4_3.java | 13 +- .../variants/vcf/vcfv4_3/VCFDecoderV4_3.java | 3 +- .../beta/exception/HtsjdkPluginException.java | 1 - src/main/java/htsjdk/beta/io/IOPathUtils.java | 45 +- .../java/htsjdk/beta/io/bundle/Bundle.java | 27 +- .../htsjdk/beta/io/bundle/BundleBuilder.java | 12 +- .../htsjdk/beta/io/bundle/BundleJSON.java | 107 +- .../htsjdk/beta/io/bundle/BundleResource.java | 2 - .../beta/io/bundle/BundleResourceBase.java | 38 +- .../beta/io/bundle/BundleResourceType.java | 9 +- .../htsjdk/beta/io/bundle/IOPathResource.java | 24 +- .../beta/io/bundle/InputStreamResource.java | 22 +- .../beta/io/bundle/OutputStreamResource.java | 10 +- .../io/bundle/SeekableStreamResource.java | 22 +- .../beta/io/bundle/SignatureStream.java | 5 +- src/main/java/htsjdk/beta/package-info.java | 2 - .../java/htsjdk/beta/plugin/HtsCodec.java | 14 +- .../htsjdk/beta/plugin/HtsContentType.java | 2 +- .../java/htsjdk/beta/plugin/HtsDecoder.java | 4 +- .../htsjdk/beta/plugin/HtsDecoderOptions.java | 3 +- .../java/htsjdk/beta/plugin/HtsEncoder.java | 2 - .../htsjdk/beta/plugin/HtsEncoderOptions.java | 3 +- .../java/htsjdk/beta/plugin/HtsHeader.java | 5 +- .../java/htsjdk/beta/plugin/HtsRecord.java | 5 +- .../java/htsjdk/beta/plugin/HtsVersion.java | 5 +- src/main/java/htsjdk/beta/plugin/IOUtils.java | 49 +- .../plugin/hapref/HapRefDecoderOptions.java | 3 +- .../plugin/hapref/HaploidReferenceCodec.java | 10 +- .../hapref/HaploidReferenceDecoder.java | 2 +- .../HaploidReferenceDecoderOptions.java | 3 +- .../hapref/HaploidReferenceEncoder.java | 2 +- .../HaploidReferenceEncoderOptions.java | 3 +- .../hapref/HaploidReferenceFormats.java | 1 - .../plugin/interval/HtsIntervalUtils.java | 28 +- .../htsjdk/beta/plugin/interval/HtsQuery.java | 11 +- .../plugin/interval/HtsQueryInterval.java | 32 +- .../htsjdk/beta/plugin/reads/ReadsBundle.java | 40 +- .../htsjdk/beta/plugin/reads/ReadsCodec.java | 5 +- .../beta/plugin/reads/ReadsDecoder.java | 4 +- .../plugin/reads/ReadsDecoderOptions.java | 26 +- .../beta/plugin/reads/ReadsEncoder.java | 2 +- .../plugin/reads/ReadsEncoderOptions.java | 5 +- .../beta/plugin/reads/ReadsFormats.java | 1 - .../htsjdk/beta/plugin/reads/ReadsQuery.java | 1 - .../registry/HaploidReferenceResolver.java | 33 +- .../plugin/registry/HtsCodecRegistry.java | 37 +- .../plugin/registry/HtsCodecResolver.java | 161 +- .../plugin/registry/HtsDefaultRegistry.java | 14 +- .../beta/plugin/registry/ReadsResolver.java | 25 +- .../plugin/registry/VariantsResolver.java | 21 +- .../beta/plugin/variants/VariantsBundle.java | 25 +- .../beta/plugin/variants/VariantsCodec.java | 5 +- .../beta/plugin/variants/VariantsDecoder.java | 2 +- .../variants/VariantsDecoderOptions.java | 6 +- .../beta/plugin/variants/VariantsEncoder.java | 2 +- .../variants/VariantsEncoderOptions.java | 12 +- src/main/java/htsjdk/io/AsyncWriterPool.java | 37 +- src/main/java/htsjdk/io/HtsPath.java | 69 +- src/main/java/htsjdk/io/IOPath.java | 11 +- .../htsjdk/samtools/AbstractBAMFileIndex.java | 94 +- .../samtools/AbstractSAMHeaderRecord.java | 14 +- .../java/htsjdk/samtools/AlignmentBlock.java | 12 +- .../htsjdk/samtools/AsyncSAMFileWriter.java | 23 +- .../htsjdk/samtools/BAMFileConstants.java | 3 +- .../java/htsjdk/samtools/BAMFileReader.java | 385 +++-- .../java/htsjdk/samtools/BAMFileSpan.java | 74 +- .../java/htsjdk/samtools/BAMFileWriter.java | 61 +- src/main/java/htsjdk/samtools/BAMIndex.java | 5 +- .../java/htsjdk/samtools/BAMIndexContent.java | 144 +- .../java/htsjdk/samtools/BAMIndexMerger.java | 39 +- .../htsjdk/samtools/BAMIndexMetaData.java | 576 +++---- .../java/htsjdk/samtools/BAMIndexWriter.java | 5 +- src/main/java/htsjdk/samtools/BAMIndexer.java | 48 +- .../htsjdk/samtools/BAMIteratorFilter.java | 11 +- ...MQueryMultipleIntervalsIteratorFilter.java | 22 +- src/main/java/htsjdk/samtools/BAMRecord.java | 73 +- .../java/htsjdk/samtools/BAMRecordCodec.java | 66 +- .../java/htsjdk/samtools/BAMSBIIndexer.java | 7 +- .../samtools/BAMStartingAtIteratorFilter.java | 2 +- .../java/htsjdk/samtools/BAMStreamWriter.java | 13 +- .../java/htsjdk/samtools/BamConverter.java | 29 +- .../java/htsjdk/samtools/BamFileIoUtils.java | 80 +- .../htsjdk/samtools/BamIndexValidator.java | 436 +++--- src/main/java/htsjdk/samtools/Bin.java | 31 +- src/main/java/htsjdk/samtools/BinList.java | 8 +- .../htsjdk/samtools/BinaryBAMIndexWriter.java | 35 +- .../java/htsjdk/samtools/BinaryTagCodec.java | 132 +- .../htsjdk/samtools/BinningIndexBuilder.java | 22 +- .../htsjdk/samtools/BinningIndexContent.java | 9 +- .../htsjdk/samtools/BrowseableBAMIndex.java | 4 +- .../java/htsjdk/samtools/CRAMBAIIndexer.java | 905 +++++------ .../java/htsjdk/samtools/CRAMCRAIIndexer.java | 36 +- .../samtools/CRAMContainerStreamWriter.java | 16 +- .../java/htsjdk/samtools/CRAMFileReader.java | 159 +- .../java/htsjdk/samtools/CRAMFileWriter.java | 46 +- .../java/htsjdk/samtools/CRAMIndexer.java | 1 - .../java/htsjdk/samtools/CRAMIterator.java | 68 +- src/main/java/htsjdk/samtools/CSIIndex.java | 122 +- .../htsjdk/samtools/CachingBAMFileIndex.java | 47 +- ...achingBamFileIndexOptimizedForMerging.java | 34 +- .../samtools/ChainedDownsamplingIterator.java | 8 +- src/main/java/htsjdk/samtools/Chunk.java | 43 +- src/main/java/htsjdk/samtools/Cigar.java | 139 +- .../java/htsjdk/samtools/CigarElement.java | 9 +- .../java/htsjdk/samtools/CigarOperator.java | 74 +- .../samtools/ComparableSamRecordIterator.java | 14 +- .../samtools/CompressedIndexFileBuffer.java | 10 +- .../ConstantMemoryDownsamplingIterator.java | 11 +- .../samtools/CoordinateSortedPairInfoMap.java | 21 +- .../htsjdk/samtools/CustomReaderFactory.java | 195 ++- .../samtools/DefaultSAMRecordFactory.java | 58 +- src/main/java/htsjdk/samtools/Defaults.java | 28 +- .../samtools/DiskBasedBAMFileIndex.java | 31 +- .../htsjdk/samtools/DownsamplingIterator.java | 37 +- .../samtools/DownsamplingIteratorFactory.java | 62 +- .../samtools/DuplicateScoringStrategy.java | 22 +- .../java/htsjdk/samtools/DuplicateSet.java | 23 +- .../htsjdk/samtools/DuplicateSetIterator.java | 46 +- .../samtools/FileTruncatedException.java | 3 +- .../htsjdk/samtools/GenomicIndexUtil.java | 69 +- .../HighAccuracyDownsamplingIterator.java | 35 +- .../htsjdk/samtools/HtsgetBAMFileReader.java | 207 +-- .../java/htsjdk/samtools/IndexFileBuffer.java | 8 +- .../samtools/IndexFileBufferFactory.java | 9 +- .../htsjdk/samtools/IndexStreamBuffer.java | 31 +- .../java/htsjdk/samtools/LinearIndex.java | 18 +- .../samtools/MemoryMappedFileBuffer.java | 4 +- .../samtools/MergingSamRecordIterator.java | 29 +- .../java/htsjdk/samtools/QueryInterval.java | 15 +- .../samtools/RandomAccessFileBuffer.java | 17 +- .../htsjdk/samtools/ReservedTagConstants.java | 139 +- .../SAMBinaryTagAndUnsignedArrayValue.java | 6 +- .../htsjdk/samtools/SAMBinaryTagAndValue.java | 101 +- .../java/htsjdk/samtools/SAMException.java | 3 +- .../java/htsjdk/samtools/SAMFileHeader.java | 40 +- .../java/htsjdk/samtools/SAMFileWriter.java | 26 +- .../htsjdk/samtools/SAMFileWriterFactory.java | 146 +- .../htsjdk/samtools/SAMFileWriterImpl.java | 77 +- src/main/java/htsjdk/samtools/SAMFlag.java | 39 +- .../htsjdk/samtools/SAMFormatException.java | 3 +- .../samtools/SAMHeaderRecordComparator.java | 49 +- .../java/htsjdk/samtools/SAMLineParser.java | 79 +- .../htsjdk/samtools/SAMProgramRecord.java | 26 +- .../htsjdk/samtools/SAMReadGroupRecord.java | 155 +- src/main/java/htsjdk/samtools/SAMRecord.java | 479 +++--- .../SAMRecordCoordinateComparator.java | 5 +- .../SAMRecordDuplicateComparator.java | 78 +- .../htsjdk/samtools/SAMRecordFactory.java | 27 +- .../htsjdk/samtools/SAMRecordIterator.java | 1 - .../SAMRecordQueryHashComparator.java | 4 +- .../SAMRecordQueryNameComparator.java | 6 +- .../htsjdk/samtools/SAMRecordSetBuilder.java | 223 ++- .../samtools/SAMSequenceDictionary.java | 114 +- .../samtools/SAMSequenceDictionaryCodec.java | 3 +- .../htsjdk/samtools/SAMSequenceRecord.java | 62 +- src/main/java/htsjdk/samtools/SAMTag.java | 8 +- src/main/java/htsjdk/samtools/SAMTagUtil.java | 187 ++- .../java/htsjdk/samtools/SAMTestUtil.java | 5 +- .../htsjdk/samtools/SAMTextHeaderCodec.java | 154 +- .../java/htsjdk/samtools/SAMTextReader.java | 22 +- .../java/htsjdk/samtools/SAMTextWriter.java | 11 +- src/main/java/htsjdk/samtools/SAMUtils.java | 204 ++- .../htsjdk/samtools/SAMValidationError.java | 25 +- src/main/java/htsjdk/samtools/SBIIndex.java | 58 +- .../java/htsjdk/samtools/SBIIndexMerger.java | 10 +- .../java/htsjdk/samtools/SBIIndexWriter.java | 14 +- src/main/java/htsjdk/samtools/SQTagUtil.java | 22 +- .../java/htsjdk/samtools/SRAFileReader.java | 74 +- src/main/java/htsjdk/samtools/SRAIndex.java | 72 +- .../java/htsjdk/samtools/SRAIterator.java | 79 +- .../htsjdk/samtools/SamFileHeaderMerger.java | 258 ++-- .../htsjdk/samtools/SamFileValidator.java | 197 ++- src/main/java/htsjdk/samtools/SamFiles.java | 18 +- .../java/htsjdk/samtools/SamFlagField.java | 101 +- src/main/java/htsjdk/samtools/SamIndexes.java | 15 +- .../htsjdk/samtools/SamInputResource.java | 79 +- .../java/htsjdk/samtools/SamPairUtil.java | 171 ++- src/main/java/htsjdk/samtools/SamReader.java | 37 +- .../htsjdk/samtools/SamReaderFactory.java | 199 ++- src/main/java/htsjdk/samtools/SamStreams.java | 64 +- .../SecondaryAlignmentSkippingIterator.java | 2 +- ...ondaryOrSupplementarySkippingIterator.java | 3 +- .../StreamInflatingIndexingOutputStream.java | 8 +- .../java/htsjdk/samtools/TextCigarCodec.java | 8 +- .../java/htsjdk/samtools/TextTagCodec.java | 48 +- .../samtools/TextualBAMIndexWriter.java | 47 +- .../samtools/apps/TimeRandomAccessFile.java | 3 +- .../java/htsjdk/samtools/cram/BAIEntry.java | 50 +- .../java/htsjdk/samtools/cram/CRAIEntry.java | 49 +- .../java/htsjdk/samtools/cram/CRAIIndex.java | 30 +- .../htsjdk/samtools/cram/CRAIIndexMerger.java | 56 +- .../htsjdk/samtools/cram/CRAMException.java | 2 +- .../htsjdk/samtools/cram/CramComparison.java | 72 +- .../htsjdk/samtools/cram/CramConverter.java | 34 +- .../java/htsjdk/samtools/cram/CramStats.java | 24 +- .../cram/build/CRAMReferenceRegion.java | 50 +- .../cram/build/CompressionHeaderFactory.java | 81 +- .../samtools/cram/build/ContainerFactory.java | 27 +- .../build/CramContainerHeaderIterator.java | 7 +- .../cram/build/CramContainerIterator.java | 1 - .../htsjdk/samtools/cram/build/CramIO.java | 81 +- .../cram/build/CramSpanContainerIterator.java | 7 +- .../samtools/cram/build/SliceFactory.java | 83 +- .../htsjdk/samtools/cram/build/Utils.java | 3 +- .../samtools/cram/common/CRAMVersion.java | 5 +- .../samtools/cram/common/CramVersions.java | 13 +- .../compression/BZIP2ExternalCompressor.java | 5 +- .../cram/compression/CompressionUtils.java | 60 +- .../cram/compression/ExternalCompressor.java | 36 +- .../compression/GZIPExternalCompressor.java | 8 +- .../compression/LZMAExternalCompressor.java | 12 +- .../RANS4x8ExternalCompressor.java | 19 +- .../RANSNx16ExternalCompressor.java | 12 +- .../cram/compression/TrialCompressor.java | 4 +- .../compression/fqzcomp/FQZCompDecode.java | 44 +- .../compression/fqzcomp/FQZCompEncode.java | 39 +- .../fqzcomp/FQZCompExternalCompressor.java | 10 +- .../compression/fqzcomp/FQZGlobalFlags.java | 15 +- .../cram/compression/fqzcomp/FQZModels.java | 10 +- .../cram/compression/fqzcomp/FQZParam.java | 5 +- .../cram/compression/fqzcomp/FQZParams.java | 7 +- .../cram/compression/fqzcomp/FQZState.java | 120 +- .../cram/compression/fqzcomp/FQZUtils.java | 6 +- .../NameTokenisationDecode.java | 81 +- .../NameTokenisationEncode.java | 164 +- .../NameTokeniserExternalCompressor.java | 7 +- .../nametokenisation/TokenStreams.java | 18 +- .../nametokenisation/tokens/EncodeToken.java | 12 +- .../cram/compression/range/ByteModel.java | 35 +- .../cram/compression/range/Constants.java | 6 +- .../cram/compression/range/RangeCoder.java | 26 +- .../cram/compression/range/RangeDecode.java | 96 +- .../cram/compression/range/RangeEncode.java | 22 +- .../range/RangeExternalCompressor.java | 15 +- .../cram/compression/range/RangeParams.java | 35 +- .../cram/compression/rans/Constants.java | 7 +- .../cram/compression/rans/RANS4x8Decode.java | 12 +- .../cram/compression/rans/RANS4x8Encode.java | 95 +- .../compression/rans/RANSEncodingSymbol.java | 4 +- .../cram/compression/rans/RANSNx16Decode.java | 65 +- .../cram/compression/rans/RANSNx16Encode.java | 50 +- .../cram/compression/rans/RANSParams.java | 8 +- .../cram/digest/AbstractSerialDigest.java | 6 +- .../samtools/cram/digest/ByteSumCombine.java | 4 +- .../samtools/cram/digest/ContentDigests.java | 76 +- .../samtools/cram/digest/Crc32Hasher.java | 1 - .../cram/digest/IntegerSumCombine.java | 1 - .../cram/digest/MessageDigestHasher.java | 4 +- .../htsjdk/samtools/cram/digest/SERIES.java | 3 +- .../cram/encoding/ByteArrayLenCodec.java | 4 +- .../cram/encoding/ByteArrayLenEncoding.java | 12 +- .../samtools/cram/encoding/CRAMCodec.java | 2 +- .../samtools/cram/encoding/CRAMEncoding.java | 5 +- .../cram/encoding/EncodingFactory.java | 16 +- .../cram/encoding/core/BetaIntegerCodec.java | 18 +- .../encoding/core/BetaIntegerEncoding.java | 6 +- .../core/CanonicalHuffmanByteCodec.java | 7 +- .../core/CanonicalHuffmanByteEncoding.java | 15 +- .../core/CanonicalHuffmanIntegerCodec.java | 7 +- .../core/CanonicalHuffmanIntegerEncoding.java | 17 +- .../cram/encoding/core/CoreCodec.java | 2 +- .../cram/encoding/core/GammaIntegerCodec.java | 10 +- .../encoding/core/GammaIntegerEncoding.java | 7 +- .../core/SubexponentialIntegerCodec.java | 13 +- .../core/SubexponentialIntegerEncoding.java | 5 +- .../core/experimental/ExperimentalCodec.java | 3 +- .../core/experimental/GolombIntegerCodec.java | 15 +- .../experimental/GolombIntegerEncoding.java | 8 +- .../core/experimental/GolombLongCodec.java | 12 +- .../core/experimental/GolombLongEncoding.java | 6 +- .../experimental/GolombRiceIntegerCodec.java | 10 +- .../GolombRiceIntegerEncoding.java | 5 +- .../core/huffmanUtils/HuffmanBitCode.java | 9 +- .../HuffmanCanoncialCodeGenerator.java | 54 +- .../core/huffmanUtils/HuffmanLeaf.java | 3 +- .../core/huffmanUtils/HuffmanNode.java | 2 +- .../core/huffmanUtils/HuffmanParams.java | 7 +- .../huffmanUtils/HuffmanParamsCalculator.java | 6 +- .../core/huffmanUtils/HuffmanTree.java | 4 +- .../encoding/external/ByteArrayStopCodec.java | 10 +- .../external/ByteArrayStopEncoding.java | 11 +- .../external/ExternalByteArrayCodec.java | 8 +- .../external/ExternalByteArrayEncoding.java | 16 +- .../encoding/external/ExternalByteCodec.java | 12 +- .../external/ExternalByteEncoding.java | 12 +- .../external/ExternalIntegerCodec.java | 12 +- .../external/ExternalIntegerEncoding.java | 13 +- .../encoding/external/ExternalLongCodec.java | 12 +- .../external/ExternalLongEncoding.java | 12 +- .../encoding/reader/CramRecordReader.java | 101 +- .../encoding/reader/DataSeriesReader.java | 9 +- .../readfeatures/BaseQualityScore.java | 12 +- .../cram/encoding/readfeatures/Bases.java | 3 +- .../cram/encoding/readfeatures/Deletion.java | 3 +- .../cram/encoding/readfeatures/HardClip.java | 3 +- .../encoding/readfeatures/InsertBase.java | 12 +- .../cram/encoding/readfeatures/Insertion.java | 3 +- .../cram/encoding/readfeatures/Padding.java | 3 +- .../cram/encoding/readfeatures/ReadBase.java | 17 +- .../cram/encoding/readfeatures/RefSkip.java | 3 +- .../cram/encoding/readfeatures/Scores.java | 4 +- .../cram/encoding/readfeatures/SoftClip.java | 3 +- .../encoding/readfeatures/Substitution.java | 6 +- .../encoding/writer/CramRecordWriter.java | 94 +- .../encoding/writer/DataSeriesWriter.java | 10 +- .../samtools/cram/io/BitInputStream.java | 1 - .../samtools/cram/io/BitOutputStream.java | 5 - .../samtools/cram/io/CRC32InputStream.java | 8 +- .../samtools/cram/io/CRC32OutputStream.java | 19 +- .../samtools/cram/io/CountingInputStream.java | 1 - .../java/htsjdk/samtools/cram/io/CramInt.java | 13 +- .../htsjdk/samtools/cram/io/CramIntArray.java | 3 +- .../cram/io/DefaultBitInputStream.java | 29 +- .../cram/io/DefaultBitOutputStream.java | 38 +- .../java/htsjdk/samtools/cram/io/ITF8.java | 49 +- .../samtools/cram/io/InputStreamUtils.java | 5 +- .../java/htsjdk/samtools/cram/io/LTF8.java | 22 +- .../cram/ref/CRAMLazyReferenceSource.java | 8 +- .../cram/ref/CRAMReferenceSource.java | 4 +- .../samtools/cram/ref/EnaRefService.java | 17 +- .../samtools/cram/ref/ReferenceContext.java | 6 +- .../samtools/cram/ref/ReferenceSource.java | 90 +- .../cram/structure/AlignmentContext.java | 58 +- .../cram/structure/AlignmentSpan.java | 13 +- .../structure/CRAMCompressionProfile.java | 157 +- .../cram/structure/CRAMCompressionRecord.java | 284 ++-- .../cram/structure/CRAMEncodingStrategy.java | 70 +- .../structure/CRAMRecordReadFeatures.java | 159 +- .../cram/structure/CompressionHeader.java | 31 +- .../CompressionHeaderEncodingMap.java | 147 +- .../cram/structure/CompressorCache.java | 48 +- .../samtools/cram/structure/Container.java | 93 +- .../cram/structure/ContainerHeader.java | 57 +- .../samtools/cram/structure/CramHeader.java | 6 +- .../samtools/cram/structure/DataSeries.java | 71 +- .../cram/structure/EncodingDescriptor.java | 6 +- .../samtools/cram/structure/ReadTag.java | 131 +- .../htsjdk/samtools/cram/structure/Slice.java | 336 ++-- .../samtools/cram/structure/SliceBlocks.java | 31 +- .../structure/SliceBlocksReadStreams.java | 7 +- .../structure/SliceBlocksWriteStreams.java | 16 +- .../cram/structure/SubstitutionBase.java | 8 +- .../cram/structure/SubstitutionMatrix.java | 45 +- .../samtools/cram/structure/TagKeyCache.java | 4 +- .../samtools/cram/structure/block/Block.java | 54 +- .../block/BlockCompressionMethod.java | 3 +- .../structure/block/BlockContentType.java | 1 - .../samtools/example/ExampleSamUsage.java | 38 +- .../samtools/example/PrintReadsExample.java | 31 +- .../samtools/fastq/AsyncFastqWriter.java | 17 +- .../samtools/fastq/BasicFastqWriter.java | 5 +- .../htsjdk/samtools/fastq/FastqConstants.java | 15 +- .../htsjdk/samtools/fastq/FastqEncoder.java | 27 +- .../htsjdk/samtools/fastq/FastqReader.java | 64 +- .../htsjdk/samtools/fastq/FastqRecord.java | 50 +- .../htsjdk/samtools/fastq/FastqWriter.java | 3 +- .../samtools/fastq/FastqWriterFactory.java | 14 +- .../filter/AbstractJavascriptFilter.java | 16 +- .../samtools/filter/AggregateFilter.java | 161 +- .../htsjdk/samtools/filter/AlignedFilter.java | 178 +-- .../samtools/filter/DuplicateReadFilter.java | 1 + .../filter/FailsVendorReadQualityFilter.java | 118 +- .../samtools/filter/FilteringIterator.java | 11 +- .../samtools/filter/FilteringSamIterator.java | 15 +- .../samtools/filter/InsertSizeFilter.java | 2 +- .../samtools/filter/IntervalFilter.java | 17 +- .../filter/IntervalKeepPairFilter.java | 10 +- .../htsjdk/samtools/filter/InvertFilter.java | 4 +- .../filter/JavascriptSamRecordFilter.java | 17 +- .../filter/NotPrimaryAlignmentFilter.java | 4 +- .../filter/OverclippedReadFilter.java | 16 +- .../samtools/filter/ReadNameFilter.java | 220 ++- .../samtools/filter/SamRecordFilter.java | 106 +- .../filter/SecondaryAlignmentFilter.java | 4 +- .../SecondaryOrSupplementaryFilter.java | 2 +- .../samtools/filter/SolexaNoiseFilter.java | 135 +- .../htsjdk/samtools/filter/TagFilter.java | 233 ++- .../filter/WholeReadClippedFilter.java | 4 +- .../java/htsjdk/samtools/liftover/Chain.java | 100 +- .../htsjdk/samtools/liftover/LiftOver.java | 82 +- .../java/htsjdk/samtools/metrics/Header.java | 1 - .../htsjdk/samtools/metrics/MetricBase.java | 36 +- .../htsjdk/samtools/metrics/MetricsFile.java | 199 +-- .../htsjdk/samtools/metrics/StringHeader.java | 24 +- .../samtools/metrics/VersionHeader.java | 10 +- .../reference/AbstractFastaSequenceFile.java | 28 +- .../AbstractIndexedFastaSequenceFile.java | 102 +- ...ockCompressedIndexedFastaSequenceFile.java | 19 +- .../reference/FastaReferenceWriter.java | 123 +- .../FastaReferenceWriterBuilder.java | 29 +- .../samtools/reference/FastaSequenceFile.java | 24 +- .../reference/FastaSequenceIndex.java | 53 +- .../reference/FastaSequenceIndexCreator.java | 34 +- .../reference/FastaSequenceIndexEntry.java | 30 +- .../reference/IndexedFastaSequenceFile.java | 9 +- .../samtools/reference/ReferenceSequence.java | 22 +- .../reference/ReferenceSequenceFile.java | 8 +- .../ReferenceSequenceFileFactory.java | 67 +- .../ReferenceSequenceFileWalker.java | 29 +- .../SamLocusAndReferenceIterator.java | 31 +- .../ISeekableStreamFactory.java | 5 +- .../SeekableBufferedStream.java | 7 +- .../seekablestream/SeekableFTPStream.java | 19 +- .../SeekableFTPStreamHelper.java | 11 +- .../seekablestream/SeekableFileStream.java | 22 +- .../seekablestream/SeekableHTTPStream.java | 32 +- .../seekablestream/SeekableMemoryStream.java | 1 - .../seekablestream/SeekablePathStream.java | 18 +- .../seekablestream/SeekableStream.java | 9 +- .../seekablestream/SeekableStreamFactory.java | 50 +- .../seekablestream/UserPasswordInput.java | 65 +- .../htsjdk/samtools/sra/ReferenceCache.java | 1 - .../htsjdk/samtools/sra/SRAAccession.java | 68 +- .../samtools/sra/SRAAlignmentIterator.java | 83 +- .../samtools/sra/SRAIndexedSequenceFile.java | 17 +- .../htsjdk/samtools/sra/SRALazyRecord.java | 106 +- .../samtools/sra/SRAUnalignmentIterator.java | 72 +- .../java/htsjdk/samtools/sra/SRAUtils.java | 53 +- .../samtools/util/AbstractAsyncWriter.java | 34 +- .../samtools/util/AbstractLocusInfo.java | 9 +- .../samtools/util/AbstractLocusIterator.java | 90 +- .../samtools/util/AbstractProgressLogger.java | 37 +- .../util/AbstractRecordAndOffset.java | 7 +- .../htsjdk/samtools/util/AsciiWriter.java | 1 - .../util/AsyncBlockCompressedInputStream.java | 41 +- .../samtools/util/AsyncBufferedIterator.java | 54 +- .../htsjdk/samtools/util/BinaryCodec.java | 1366 ++++++++--------- .../util/BlockCompressedFilePointerUtil.java | 11 +- .../util/BlockCompressedInputStream.java | 163 +- .../util/BlockCompressedOutputStream.java | 52 +- .../util/BlockCompressedStreamConstants.java | 75 +- .../htsjdk/samtools/util/BlockGunzipper.java | 32 +- .../samtools/util/BufferedLineReader.java | 17 +- .../java/htsjdk/samtools/util/CigarUtil.java | 204 +-- .../samtools/util/CloseableIterator.java | 2 +- .../java/htsjdk/samtools/util/CloserUtil.java | 161 +- .../htsjdk/samtools/util/CollectionUtil.java | 29 +- .../htsjdk/samtools/util/ComparableTuple.java | 3 +- .../java/htsjdk/samtools/util/CoordMath.java | 12 +- .../samtools/util/CoordSpanInputSteam.java | 7 +- .../samtools/util/CustomGzipOutputStream.java | 4 +- .../java/htsjdk/samtools/util/DateParser.java | 53 +- .../htsjdk/samtools/util/DiskBackedQueue.java | 64 +- .../samtools/util/EdgeReadIterator.java | 110 +- .../samtools/util/EdgingRecordAndOffset.java | 11 +- .../htsjdk/samtools/util/FastLineReader.java | 4 +- .../util/FileAppendStreamLRUCache.java | 10 +- .../htsjdk/samtools/util/FileExtensions.java | 30 +- .../java/htsjdk/samtools/util/FormatUtil.java | 117 +- .../java/htsjdk/samtools/util/GZIIndex.java | 53 +- .../java/htsjdk/samtools/util/GzipCodec.java | 65 +- .../java/htsjdk/samtools/util/Histogram.java | 101 +- .../java/htsjdk/samtools/util/HttpUtils.java | 23 +- .../java/htsjdk/samtools/util/IOUtil.java | 322 ++-- .../java/htsjdk/samtools/util/Interval.java | 24 +- .../htsjdk/samtools/util/IntervalCodec.java | 14 +- .../util/IntervalCoordinateComparator.java | 1 - .../htsjdk/samtools/util/IntervalList.java | 145 +- .../IntervalListReferenceSequenceMask.java | 5 +- .../samtools/util/IntervalListWriter.java | 3 - .../htsjdk/samtools/util/IntervalTree.java | 698 +++------ .../htsjdk/samtools/util/IntervalTreeMap.java | 62 +- .../htsjdk/samtools/util/IntervalUtil.java | 19 +- .../samtools/util/IterableOnceIterator.java | 6 +- .../java/htsjdk/samtools/util/Iterables.java | 4 +- src/main/java/htsjdk/samtools/util/Lazy.java | 6 +- .../java/htsjdk/samtools/util/ListMap.java | 2 +- .../java/htsjdk/samtools/util/Locatable.java | 4 +- .../htsjdk/samtools/util/LocationAware.java | 10 +- src/main/java/htsjdk/samtools/util/Locus.java | 2 +- src/main/java/htsjdk/samtools/util/Log.java | 7 +- .../util/Md5CalculatingInputStream.java | 32 +- .../util/Md5CalculatingOutputStream.java | 21 +- .../htsjdk/samtools/util/MergingIterator.java | 204 +-- .../java/htsjdk/samtools/util/Murmur3.java | 26 +- .../htsjdk/samtools/util/OverlapDetector.java | 13 +- .../htsjdk/samtools/util/PeekIterator.java | 4 +- .../samtools/util/PeekableIterator.java | 7 +- .../samtools/util/PositionalOutputStream.java | 55 +- .../htsjdk/samtools/util/ProcessExecutor.java | 85 +- .../htsjdk/samtools/util/ProgressLogger.java | 10 +- .../util/ProgressLoggerInterface.java | 13 +- .../util/QualityEncodingDetector.java | 70 +- .../htsjdk/samtools/util/QualityUtil.java | 6 +- .../samtools/util/ResourceLimitedMap.java | 23 +- .../samtools/util/RuntimeEOFException.java | 3 +- .../samtools/util/RuntimeIOException.java | 3 +- .../samtools/util/RuntimeScriptException.java | 4 +- .../util/SAMRecordPrefetchingIterator.java | 30 +- .../htsjdk/samtools/util/SamConstants.java | 7 +- .../samtools/util/SamLocusIterator.java | 39 +- .../SamRecordIntervalIteratorFactory.java | 23 +- .../util/SamRecordTrackingBuffer.java | 110 +- .../samtools/util/SamRecordWithOrdinal.java | 21 +- .../htsjdk/samtools/util/SequenceUtil.java | 199 +-- .../htsjdk/samtools/util/SnappyLoader.java | 25 +- .../samtools/util/SnappyLoaderInternal.java | 24 +- .../samtools/util/SolexaQualityConverter.java | 17 +- .../samtools/util/SortingCollection.java | 141 +- .../samtools/util/SortingLongCollection.java | 10 +- .../java/htsjdk/samtools/util/StopWatch.java | 5 +- .../java/htsjdk/samtools/util/StringUtil.java | 195 ++- .../samtools/util/TempStreamFactory.java | 1 - .../java/htsjdk/samtools/util/TestUtil.java | 15 +- .../htsjdk/samtools/util/TrimmingUtil.java | 2 +- .../htsjdk/samtools/util/ftp/FTPClient.java | 474 +++--- .../htsjdk/samtools/util/ftp/FTPReply.java | 220 ++- .../htsjdk/samtools/util/ftp/FTPStream.java | 105 +- .../htsjdk/samtools/util/ftp/FTPUtils.java | 66 +- .../util/htsget/HtsgetErrorResponse.java | 1 - .../HtsgetMalformedResponseException.java | 2 +- .../util/htsget/HtsgetPOSTRequest.java | 53 +- .../samtools/util/htsget/HtsgetRequest.java | 82 +- .../samtools/util/htsget/HtsgetResponse.java | 46 +- .../util/nio/DeleteOnExitPathHook.java | 5 +- .../samtools/util/zip/DeflaterFactory.java | 5 +- .../samtools/util/zip/InflaterFactory.java | 3 +- .../samtools/util/zip/LibdeflateDeflater.java | 9 +- .../samtools/util/zip/LibdeflateInflater.java | 1 - .../htsjdk/tribble/AbstractFeatureCodec.java | 5 +- .../htsjdk/tribble/AbstractFeatureReader.java | 110 +- .../htsjdk/tribble/AsciiFeatureCodec.java | 10 +- .../htsjdk/tribble/BinaryFeatureCodec.java | 6 +- src/main/java/htsjdk/tribble/Feature.java | 4 +- .../java/htsjdk/tribble/FeatureCodec.java | 14 +- .../htsjdk/tribble/FeatureCodecHeader.java | 6 +- .../java/htsjdk/tribble/FeatureReader.java | 1 - .../IntervalList/IntervalListCodec.java | 68 +- .../java/htsjdk/tribble/MutableFeature.java | 2 +- .../java/htsjdk/tribble/NameAwareCodec.java | 1 + .../java/htsjdk/tribble/NamedFeature.java | 1 - .../htsjdk/tribble/TabixFeatureReader.java | 43 +- src/main/java/htsjdk/tribble/Tribble.java | 6 +- .../java/htsjdk/tribble/TribbleException.java | 35 +- .../tribble/TribbleIndexedFeatureReader.java | 111 +- .../htsjdk/tribble/annotation/Strand.java | 8 +- .../java/htsjdk/tribble/bed/BEDCodec.java | 19 +- .../java/htsjdk/tribble/bed/BEDFeature.java | 1 - .../htsjdk/tribble/bed/FullBEDFeature.java | 21 +- .../htsjdk/tribble/bed/SimpleBEDFeature.java | 7 +- .../htsjdk/tribble/example/CountRecords.java | 29 +- .../tribble/example/ExampleBinaryCodec.java | 21 +- .../htsjdk/tribble/example/IndexToTable.java | 11 +- .../tribble/example/IndicesAreEqual.java | 6 +- .../tribble/example/ProfileIndexReading.java | 9 +- .../exception/CodecLineParsingException.java | 4 +- .../exception/UnsortedFileException.java | 5 +- .../java/htsjdk/tribble/gff/Gff3BaseData.java | 64 +- .../java/htsjdk/tribble/gff/Gff3Codec.java | 146 +- .../htsjdk/tribble/gff/Gff3Constants.java | 24 +- .../java/htsjdk/tribble/gff/Gff3Feature.java | 41 +- .../htsjdk/tribble/gff/Gff3FeatureImpl.java | 115 +- .../java/htsjdk/tribble/gff/Gff3Writer.java | 52 +- .../htsjdk/tribble/gff/SequenceRegion.java | 25 +- .../htsjdk/tribble/index/AbstractIndex.java | 40 +- src/main/java/htsjdk/tribble/index/Block.java | 12 +- .../java/htsjdk/tribble/index/ChrIndex.java | 2 - .../tribble/index/DynamicIndexCreator.java | 106 +- src/main/java/htsjdk/tribble/index/Index.java | 3 +- .../htsjdk/tribble/index/IndexCreator.java | 6 +- .../htsjdk/tribble/index/IndexFactory.java | 240 +-- .../tribble/index/TribbleIndexCreator.java | 3 +- .../tribble/index/interval/Interval.java | 33 +- .../index/interval/IntervalIndexCreator.java | 21 +- .../tribble/index/interval/IntervalTree.java | 85 +- .../index/interval/IntervalTreeIndex.java | 17 +- .../tribble/index/linear/LinearIndex.java | 74 +- .../index/linear/LinearIndexCreator.java | 32 +- .../index/tabix/AllRefsTabixIndexCreator.java | 38 +- .../tabix/StreamBasedTabixIndexCreator.java | 61 +- .../tribble/index/tabix/TabixFormat.java | 22 +- .../tribble/index/tabix/TabixIndex.java | 33 +- .../index/tabix/TabixIndexCreator.java | 32 +- .../tribble/index/tabix/TabixIndexMerger.java | 32 +- .../tribble/readers/AsciiLineReader.java | 46 +- .../readers/AsciiLineReaderIterator.java | 20 +- .../BlockCompressedAsciiLineReader.java | 9 +- .../tribble/readers/LineIteratorImpl.java | 5 +- .../htsjdk/tribble/readers/LineReader.java | 1 - .../readers/LongLineBufferedReader.java | 90 +- .../htsjdk/tribble/readers/Positional.java | 3 +- .../readers/PositionalBufferedStream.java | 49 +- .../readers/SynchronousLineReader.java | 11 +- .../readers/TabixIteratorLineReader.java | 4 +- .../htsjdk/tribble/readers/TabixReader.java | 152 +- .../java/htsjdk/tribble/util/FTPHelper.java | 4 +- .../java/htsjdk/tribble/util/HTTPHelper.java | 4 - .../tribble/util/LittleEndianInputStream.java | 42 +- .../util/LittleEndianOutputStream.java | 28 +- .../java/htsjdk/tribble/util/MathUtils.java | 25 +- .../htsjdk/tribble/util/ParsingUtils.java | 66 +- .../java/htsjdk/tribble/util/TabixUtils.java | 3 - .../java/htsjdk/tribble/util/URLHelper.java | 2 - .../htsjdk/tribble/util/URLHelperFactory.java | 1 - .../util/popgen/HardyWeinbergCalculation.java | 233 ++- src/main/java/htsjdk/utils/ClassFinder.java | 39 +- .../java/htsjdk/utils/ValidationUtils.java | 2 - .../java/htsjdk/variant/bcf2/BCF2Codec.java | 206 ++- .../java/htsjdk/variant/bcf2/BCF2Decoder.java | 131 +- .../bcf2/BCF2GenotypeFieldDecoders.java | 195 ++- .../bcf2/BCF2LazyGenotypesDecoder.java | 74 +- .../java/htsjdk/variant/bcf2/BCF2Type.java | 83 +- .../java/htsjdk/variant/bcf2/BCF2Utils.java | 175 ++- .../java/htsjdk/variant/bcf2/BCFVersion.java | 53 +- .../variant/example/PrintVariantsExample.java | 29 +- .../utils/BinomialCoefficientUtil.java | 27 +- .../htsjdk/variant/utils/GeneralUtils.java | 90 +- .../utils/SAMSequenceDictionaryExtractor.java | 25 +- .../htsjdk/variant/utils/VCFHeaderReader.java | 10 +- .../htsjdk/variant/variantcontext/Allele.java | 134 +- .../variant/variantcontext/CommonInfo.java | 180 +-- .../variant/variantcontext/FastGenotype.java | 95 +- .../variant/variantcontext/Genotype.java | 221 +-- .../variantcontext/GenotypeBuilder.java | 125 +- .../variantcontext/GenotypeJEXLContext.java | 16 +- .../variantcontext/GenotypeLikelihoods.java | 250 ++- .../GenotypeNumLikelihoodsCache.java | 46 +- .../variant/variantcontext/GenotypeType.java | 48 +- .../variantcontext/GenotypesContext.java | 138 +- .../variant/variantcontext/JEXLMap.java | 38 +- .../JexlMissingValueTreatment.java | 9 +- .../variantcontext/LazyGenotypesContext.java | 76 +- .../variant/variantcontext/SimpleAllele.java | 129 +- .../variantcontext/StructuralVariantType.java | 3 +- .../variantcontext/VariantContext.java | 657 ++++---- .../variantcontext/VariantContextBuilder.java | 98 +- .../VariantContextComparator.java | 157 +- .../variantcontext/VariantContextUtils.java | 222 +-- .../variantcontext/VariantJEXLContext.java | 58 +- .../variantcontext/filter/CompoundFilter.java | 1 - .../filter/FilteringIterator.java | 5 +- .../FilteringVariantContextIterator.java | 3 +- .../filter/GenotypeQualityFilter.java | 15 +- .../filter/HeterozygosityFilter.java | 13 +- .../filter/JavascriptVariantFilter.java | 91 +- .../filter/VariantContextFilter.java | 3 +- .../writer/AsyncVariantContextWriter.java | 18 +- .../variantcontext/writer/BCF2Encoder.java | 139 +- .../writer/BCF2FieldEncoder.java | 187 ++- .../writer/BCF2FieldWriter.java | 132 +- .../writer/BCF2FieldWriterManager.java | 115 +- .../variantcontext/writer/BCF2Writer.java | 204 +-- .../writer/IndexingVariantContextWriter.java | 112 +- .../writer/IntGenotypeFieldAccessors.java | 71 +- .../variantcontext/writer/Options.java | 50 +- .../writer/SortingVariantContextWriter.java | 51 +- .../SortingVariantContextWriterBase.java | 73 +- .../variantcontext/writer/VCFWriter.java | 184 ++- .../writer/VariantContextWriter.java | 55 +- .../writer/VariantContextWriterBuilder.java | 199 +-- .../htsjdk/variant/vcf/AbstractVCFCodec.java | 367 ++--- .../java/htsjdk/variant/vcf/VCF3Codec.java | 91 +- .../htsjdk/variant/vcf/VCFAltHeaderLine.java | 13 +- .../java/htsjdk/variant/vcf/VCFCodec.java | 107 +- .../variant/vcf/VCFCompoundHeaderLine.java | 167 +- .../java/htsjdk/variant/vcf/VCFConstants.java | 69 +- .../variant/vcf/VCFContigHeaderLine.java | 100 +- .../java/htsjdk/variant/vcf/VCFEncoder.java | 89 +- .../htsjdk/variant/vcf/VCFFileReader.java | 27 +- .../variant/vcf/VCFFilterHeaderLine.java | 54 +- .../variant/vcf/VCFFormatHeaderLine.java | 52 +- .../java/htsjdk/variant/vcf/VCFHeader.java | 129 +- .../htsjdk/variant/vcf/VCFHeaderLine.java | 87 +- .../variant/vcf/VCFHeaderLineCount.java | 52 +- .../variant/vcf/VCFHeaderLineTranslator.java | 168 +- .../htsjdk/variant/vcf/VCFHeaderLineType.java | 52 +- .../htsjdk/variant/vcf/VCFHeaderVersion.java | 64 +- .../htsjdk/variant/vcf/VCFIDHeaderLine.java | 46 +- .../htsjdk/variant/vcf/VCFInfoHeaderLine.java | 58 +- .../java/htsjdk/variant/vcf/VCFIterator.java | 44 +- .../variant/vcf/VCFIteratorBuilder.java | 90 +- .../htsjdk/variant/vcf/VCFMetaHeaderLine.java | 1 - .../variant/vcf/VCFPedigreeHeaderLine.java | 1 - .../vcf/VCFPercentEncodedTextTransformer.java | 14 +- .../java/htsjdk/variant/vcf/VCFReader.java | 7 +- .../htsjdk/variant/vcf/VCFRecordCodec.java | 75 +- .../variant/vcf/VCFSampleHeaderLine.java | 1 - .../variant/vcf/VCFSimpleHeaderLine.java | 102 +- .../variant/vcf/VCFStandardHeaderLines.java | 204 ++- .../variant/vcf/VCFTextTransformer.java | 2 - .../java/htsjdk/variant/vcf/VCFUtils.java | 167 +- src/test/java/htsjdk/HtsjdkTest.java | 4 +- .../java/htsjdk/TestClassDependenceTest.java | 48 +- src/test/java/htsjdk/TestDataProviders.java | 47 +- .../fasta/HaploidReferenceResolverTest.java | 95 +- .../hapref/fasta/HtsFASTACodecTest.java | 33 +- .../reads/bam/BAMDecoderOptionsTest.java | 1 - .../reads/bam/BAMEncoderOptionsTest.java | 1 - .../codecs/reads/bam/HtsBAMCodecTest.java | 56 +- .../reads/bam/HtsBAMDecoderQueryTest.java | 116 +- .../reads/cram/CRAMDecoderOptionsTest.java | 5 +- .../reads/cram/CRAMEncoderOptionsTest.java | 5 +- .../codecs/reads/cram/HtsCRAMCodec21Test.java | 30 +- .../cram/HtsCRAMCodec30And21QueryTest.java | 1176 ++++++++------ .../codecs/reads/cram/HtsCRAMCodec30Test.java | 39 +- .../codecs/reads/cram/HtsCRAMCodec31Test.java | 48 +- .../htsget/HtsgetBAM/HtsgetBAMCodecTest.java | 44 +- .../codecs/reads/sam/SAMCodecV1_0Test.java | 59 +- .../codecs/variants/vcf/HtsVCFCodecTest.java | 193 +-- .../htsjdk/beta/io/bundle/BundleJSONTest.java | 449 +++--- .../beta/io/bundle/BundleResourceTest.java | 320 ++-- .../io/bundle/BundleResourceTestData.java | 30 +- .../htsjdk/beta/io/bundle/BundleTest.java | 41 +- .../io/bundle/InputStreamResourceTest.java | 24 +- .../io/bundle/OutputStreamResourceTest.java | 16 +- .../io/bundle/SeekableStreamResourceTest.java | 31 +- .../beta/io/bundle/SignatureStreamTest.java | 6 +- .../htsjdk/beta/plugin/HtsVersionTest.java | 46 +- .../beta/plugin/reads/ReadsBundleTest.java | 142 +- .../plugin/reads/ReadsDecoderOptionsTest.java | 7 +- .../plugin/registry/HtsCodecRegistryTest.java | 46 +- .../plugin/registry/HtsCodecResolverTest.java | 1099 ++++++------- .../plugin/registry/HtsReadsCodecTest.java | 52 +- .../registry/testcodec/HtsTestCodec.java | 36 +- .../testcodec/HtsTestCodecFormats.java | 7 +- .../registry/testcodec/HtsTestDecoder.java | 9 +- .../registry/testcodec/HtsTestEncoder.java | 12 +- .../plugin/variants/VariantsBundleTest.java | 145 +- .../java/htsjdk/io/AsyncWriterPoolTest.java | 19 +- src/test/java/htsjdk/io/HtsPathUnitTest.java | 731 ++++----- src/test/java/htsjdk/io/IOPathUtilsTest.java | 42 +- .../samtools/AbstractBAMFileIndexTest.java | 23 +- .../htsjdk/samtools/BAMCigarOverflowTest.java | 19 +- .../htsjdk/samtools/BAMFileIndexTest.java | 160 +- .../htsjdk/samtools/BAMFileReaderTest.java | 106 +- .../java/htsjdk/samtools/BAMFileSpanTest.java | 111 +- .../htsjdk/samtools/BAMFileWriterTest.java | 220 ++- .../samtools/BAMIndexValidatorTest.java | 26 +- .../htsjdk/samtools/BAMIndexWriterTest.java | 464 +++--- .../java/htsjdk/samtools/BAMIteratorTest.java | 8 +- .../java/htsjdk/samtools/BAMMergerTest.java | 45 +- ...ryMultipleIntervalsIteratorFilterTest.java | 258 +++- .../htsjdk/samtools/BAMRemoteFileTest.java | 95 +- .../htsjdk/samtools/BAMSBIIndexerTest.java | 27 +- .../htsjdk/samtools/BaiEqualityChecker.java | 42 +- .../samtools/BamFileIoUtilsUnitTest.java | 60 +- src/test/java/htsjdk/samtools/BinTest.java | 10 +- .../samtools/BinningIndexBuilderTest.java | 74 +- .../CRAMAllEncodingStrategiesTest.java | 177 ++- .../htsjdk/samtools/CRAMBAIIndexerTest.java | 70 +- .../htsjdk/samtools/CRAMCRAIIndexerTest.java | 69 +- .../htsjdk/samtools/CRAMComplianceTest.java | 226 +-- .../CRAMContainerStreamWriterTest.java | 71 +- .../htsjdk/samtools/CRAMEdgeCasesTest.java | 51 +- .../htsjdk/samtools/CRAMFileBAIIndexTest.java | 174 +-- .../samtools/CRAMFileCRAIIndexTest.java | 158 +- .../htsjdk/samtools/CRAMFileReaderTest.java | 23 +- .../htsjdk/samtools/CRAMFileWriterTest.java | 104 +- .../samtools/CRAMFileWriterWithIndexTest.java | 52 +- .../samtools/CRAMIndexPermutationsTests.java | 280 ++-- .../htsjdk/samtools/CRAMIndexQueryTest.java | 1132 ++++++++------ .../htsjdk/samtools/CRAMIndexTestHelper.java | 112 +- .../htsjdk/samtools/CRAMIteratorTest.java | 5 +- .../java/htsjdk/samtools/CRAMMergerTest.java | 44 +- .../samtools/CRAMReferencelessTest.java | 47 +- .../htsjdk/samtools/CRAMSliceMD5Test.java | 37 +- .../java/htsjdk/samtools/CRAMTestUtils.java | 55 +- .../java/htsjdk/samtools/CSIIndexTest.java | 296 ++-- .../samtools/CachingBAMFileIndexTest.java | 60 +- src/test/java/htsjdk/samtools/ChunkTest.java | 75 +- .../java/htsjdk/samtools/CigarCodecTest.java | 52 +- .../samtools/CigarOperatorUnitTest.java | 77 +- src/test/java/htsjdk/samtools/CigarTest.java | 199 ++- .../CramContainerHeaderIteratorTest.java | 52 +- .../samtools/DownsamplingIteratorTests.java | 54 +- .../DuplicateScoringStrategyTest.java | 17 +- .../samtools/DuplicateSetIteratorTest.java | 29 +- .../htsjdk/samtools/GenomicIndexUtilTest.java | 79 +- .../samtools/HtsgetBAMFileReaderTest.java | 93 +- .../java/htsjdk/samtools/HtsjdkTestUtils.java | 4 +- .../java/htsjdk/samtools/LongReadsTest.java | 134 +- ...ngSamRecordIteratorGroupCollisionTest.java | 112 +- .../MergingSamRecordIteratorTest.java | 43 +- .../samtools/PathInputResourceTest.java | 70 +- .../samtools/ProgramRecordChainingTest.java | 1 - .../htsjdk/samtools/QueryIntervalTest.java | 30 +- .../SAMBinaryTagAndValueUnitTest.java | 295 ++-- .../htsjdk/samtools/SAMFileHeaderTest.java | 58 +- .../samtools/SAMFileWriterFactoryTest.java | 85 +- .../htsjdk/samtools/SAMFileWriterTest.java | 11 +- .../htsjdk/samtools/SAMIntegerTagTest.java | 183 ++- .../htsjdk/samtools/SAMProgramRecordTest.java | 3 +- .../samtools/SAMReadGroupRecordTest.java | 153 +- .../SAMRecordDuplicateComparatorTest.java | 69 +- .../SAMRecordQueryHashComparatorTest.java | 3 +- .../SAMRecordQueryNameComparatorTest.java | 107 +- .../samtools/SAMRecordSetBuilderTest.java | 44 +- .../htsjdk/samtools/SAMRecordUnitTest.java | 375 +++-- .../SAMSequenceDictionaryCodecTest.java | 13 +- .../samtools/SAMSequenceDictionaryTest.java | 73 +- .../samtools/SAMSequenceRecordTest.java | 140 +- .../htsjdk/samtools/SAMTextReaderTest.java | 59 +- .../htsjdk/samtools/SAMTextWriterTest.java | 17 +- .../java/htsjdk/samtools/SAMUtilsTest.java | 110 +- .../samtools/SamFileHeaderMergerTest.java | 104 +- .../java/htsjdk/samtools/SamFilesTest.java | 60 +- .../htsjdk/samtools/SamFlagFieldTest.java | 9 +- .../SamHeaderRecordComparatorTest.java | 71 +- .../java/htsjdk/samtools/SamIndexesTest.java | 58 +- .../java/htsjdk/samtools/SamPairUtilTest.java | 225 ++- .../htsjdk/samtools/SamReaderFactoryTest.java | 290 ++-- .../htsjdk/samtools/SamReaderSortTest.java | 47 +- .../java/htsjdk/samtools/SamReaderTest.java | 157 +- .../java/htsjdk/samtools/SamSpecIntTest.java | 24 +- .../java/htsjdk/samtools/SamStreamsTest.java | 117 +- ...quenceNameTruncationAndValidationTest.java | 47 +- .../htsjdk/samtools/TextTagCodecTest.java | 117 +- .../htsjdk/samtools/ValidateSamFileTest.java | 560 ++++--- .../htsjdk/samtools/cram/BAIEntryTest.java | 64 +- .../htsjdk/samtools/cram/CRAIEntryTest.java | 137 +- .../htsjdk/samtools/cram/CRAIIndexTest.java | 40 +- .../htsjdk/samtools/cram/CRAIQueryTest.java | 75 +- .../samtools/cram/CRAMInteropTestUtils.java | 18 +- .../htsjdk/samtools/cram/CRAMVersionTest.java | 11 +- .../samtools/cram/CramComparisonTest.java | 7 +- .../samtools/cram/FQZCompInteropTest.java | 111 +- .../samtools/cram/LosslessRoundTripTest.java | 147 +- .../cram/NameTokenizationInteropTest.java | 100 +- .../htsjdk/samtools/cram/RANSInteropTest.java | 120 +- .../samtools/cram/RangeInteropTest.java | 68 +- .../build/CompressionHeaderFactoryTest.java | 64 +- .../cram/build/ContainerFactoryTest.java | 734 +++++---- .../samtools/cram/build/CramIOTest.java | 29 +- .../samtools/cram/build/SliceFactoryTest.java | 432 ++++-- .../CodecRoundTripPropertyTest.java | 183 +-- .../compression/CompressionUtilsTest.java | 47 +- .../cram/compression/CompressorCacheTest.java | 109 +- .../compression/ExternalCompressionTest.java | 134 +- .../cram/compression/TrialCompressorTest.java | 38 +- .../NameTokenisationTest.java | 171 +-- .../cram/compression/range/RangeTest.java | 79 +- .../cram/compression/rans/RansTest.java | 136 +- .../cram31/CRAM31ArchiveFidelityTest.java | 7 +- .../cram/cram31/CRAM31FastFidelityTest.java | 7 +- .../cram/cram31/CRAM31FidelityTestBase.java | 69 +- .../cram/cram31/CRAM31NormalFidelityTest.java | 7 +- .../cram/cram31/CRAM31SmallFidelityTest.java | 7 +- .../cram/encoding/ByteArrayLenCodecTest.java | 9 +- .../encoding/ByteArrayLenEncodingTest.java | 77 +- .../encoding/CramRecordWriterReaderTest.java | 18 +- .../cram/encoding/DataSeriesReaderTest.java | 20 +- .../cram/encoding/DataSeriesWriterTest.java | 7 +- .../cram/encoding/ReadFeaturesTest.java | 9 +- .../encoding/core/BetaIntegerCodecTest.java | 69 +- .../core/BetaIntegerEncodingTest.java | 26 +- .../CanoncialHuffmanByteEncodingTest.java | 4 +- .../CanonicalHuffmanIntegerEncodingTest.java | 4 +- .../encoding/core/GammaIntegerCodecTest.java | 73 +- .../core/GammaIntegerEncodingTest.java | 16 +- .../cram/encoding/core/HuffmanTest.java | 280 ++-- .../core/SubexponentialIntegerCodecTest.java | 88 +- .../SubexponentialIntegerEncodingTest.java | 21 +- .../external/ByteArrayStopCodecTest.java | 3 +- .../external/ByteArrayStopEncodingTest.java | 16 +- .../external/ExternalByteArrayCodecTest.java | 3 +- .../external/ExternalByteCodecTest.java | 5 +- .../ExternalCodecEquivalenceTest.java | 32 +- .../external/ExternalEncodingTest.java | 10 +- .../external/ExternalIntegerCodecTest.java | 5 +- .../external/ExternalLongCodecTest.java | 5 +- .../cram/io/CRAMByteReaderWriterTest.java | 32 +- .../samtools/cram/io/CramIntArrayTest.java | 5 +- .../htsjdk/samtools/cram/io/CramIntTest.java | 5 +- .../htsjdk/samtools/cram/io/IOTestCases.java | 99 +- .../htsjdk/samtools/cram/io/ITF8Test.java | 52 +- .../cram/io/InputStreamUtilsTest.java | 9 +- .../htsjdk/samtools/cram/io/LTF8Test.java | 50 +- .../cram/ref/CRAMReferenceRegionTest.java | 306 ++-- .../samtools/cram/ref/EnaRefServiceTest.java | 8 +- .../cram/ref/ReferenceContextTest.java | 71 +- .../cram/ref/ReferenceSourceTest.java | 8 +- .../spec30/HtsSpecsComplianceTestBase.java | 35 +- .../cram/spec30/Spec30CompressionTest.java | 9 +- .../cram/spec30/Spec30ContainerTest.java | 3 +- .../cram/spec30/Spec30CornerCaseTest.java | 3 +- .../cram/spec30/Spec30DataLayoutTest.java | 3 +- .../cram/spec30/Spec30EmbeddedRefTest.java | 3 +- .../cram/spec30/Spec30FileDefinitionTest.java | 9 +- .../cram/spec30/Spec30HeaderTest.java | 3 +- .../samtools/cram/spec30/Spec30IndexTest.java | 24 +- .../samtools/cram/spec30/Spec30LevelTest.java | 3 +- .../samtools/cram/spec30/Spec30LossyTest.java | 14 +- .../cram/spec30/Spec30MappedNoRefTest.java | 3 +- .../cram/spec30/Spec30MappedWithRefTest.java | 3 +- .../cram/spec30/Spec30MultiContainerTest.java | 6 +- .../cram/spec30/Spec30RoundTripBasicTest.java | 107 +- .../cram/spec30/Spec30RoundTripIndexTest.java | 44 +- .../Spec30RoundTripTagsAndLayoutTest.java | 117 +- .../cram/spec30/Spec30SliceTagTest.java | 3 +- .../samtools/cram/spec30/Spec30TagTest.java | 3 +- .../cram/spec30/Spec30UnmappedTest.java | 3 +- .../cram/spec30/Spec31ComplianceTest.java | 32 +- .../cram/structure/AlignmentContextTest.java | 87 +- .../cram/structure/AlignmentSpanTest.java | 39 +- .../structure/CRAMCompressionProfileTest.java | 38 +- .../structure/CRAMCompressionRecordTest.java | 105 +- .../cram/structure/CRAMRecordTestHelper.java | 13 +- .../structure/CRAMStructureTestHelper.java | 163 +- .../CompressionHeaderEncodingMapTest.java | 48 +- .../cram/structure/ContainerTest.java | 289 ++-- .../cram/structure/DataSeriesTest.java | 13 +- .../samtools/cram/structure/ReadTagTest.java | 47 +- .../structure/SliceBlockReadStreamTest.java | 23 +- .../structure/SliceBlockWriteStreamTest.java | 15 +- .../cram/structure/SliceBlocksTest.java | 80 +- .../samtools/cram/structure/SliceTests.java | 281 ++-- .../cram/structure/StructureTestUtils.java | 25 +- .../structure/SubstitutionMatrixTest.java | 243 ++- .../cram/structure/TagKeyCacheTest.java | 34 +- .../cram/structure/block/BlockTest.java | 43 +- .../block/CRAMRecordReadFeaturesTest.java | 68 +- .../samtools/fastq/BasicFastqWriterTest.java | 9 +- .../samtools/fastq/FastqEncoderTest.java | 39 +- .../samtools/fastq/FastqRecordTest.java | 35 +- .../FailsVendorReadQualityFilterTest.java | 129 +- .../samtools/filter/InsertSizeFilterTest.java | 13 +- .../samtools/filter/IntervalFilterTest.java | 53 +- .../filter/IntervalKeepPairFilterTest.java | 26 +- .../filter/JavascriptSamRecordFilterTest.java | 16 +- .../filter/MappingQualityFilterTest.java | 8 +- .../filter/OverclippedReadFilterTest.java | 63 +- .../samtools/filter/ReadNameFilterTest.java | 30 +- .../filter/SecondaryAlignmentFilterTest.java | 103 +- .../SecondaryOrSupplementaryFilterTest.java | 114 +- .../filter/SolexaNoiseFilterTest.java | 151 +- .../htsjdk/samtools/filter/TagFilterTest.java | 253 ++- .../samtools/liftover/LiftOverTest.java | 924 ++++++----- .../samtools/metrics/MetricBaseTest.java | 50 +- .../samtools/metrics/MetricsFileTest.java | 115 +- .../samtools/metrics/StringHeaderTest.java | 5 +- .../samtools/metrics/VersionHeaderTest.java | 6 +- .../AbstractFastaSequenceFileTest.java | 27 +- .../AbstractIndexedFastaSequenceFileTest.java | 384 +++-- .../reference/FakeReferenceSequenceFile.java | 4 +- .../reference/FastaReferenceWriterTest.java | 503 ++++-- .../reference/FastaSequenceFileTest.java | 12 +- .../FastaSequenceIndexCreatorTest.java | 28 +- .../reference/FastaSequenceIndexTest.java | 365 ++--- .../InMemoryReferenceSequenceFile.java | 20 +- .../ReferenceSequenceFileFactoryTests.java | 172 ++- .../ReferenceSequenceFileWalkerTest.java | 57 +- .../reference/ReferenceSequenceTests.java | 36 +- .../SamLocusAndReferenceIteratorTest.java | 44 +- .../ByteArraySeekableStreamTest.java | 21 +- .../SeekableBufferedStreamTest.java | 63 +- .../seekablestream/SeekableFTPStreamTest.java | 16 +- .../SeekableFileStreamTest.java | 3 +- .../SeekableMemoryStreamTest.java | 10 +- .../SeekablePathStreamTest.java | 5 +- .../SeekableStreamFactoryTest.java | 78 +- ...eStreamGZIPinputStreamIntegrationTest.java | 28 +- .../seekablestream/SeekableStreamTest.java | 15 +- .../htsjdk/samtools/sra/AbstractSRATest.java | 22 +- .../htsjdk/samtools/sra/SRAAccessionTest.java | 11 +- .../htsjdk/samtools/sra/SRAIndexTest.java | 119 +- .../samtools/sra/SRALazyRecordTest.java | 10 +- .../htsjdk/samtools/sra/SRAQueryTest.java | 45 +- .../htsjdk/samtools/sra/SRAReferenceTest.java | 44 +- .../java/htsjdk/samtools/sra/SRATest.java | 405 +++-- .../samtools/util/AbstractLocusInfoTest.java | 9 +- .../AbstractLocusIteratorTestTemplate.java | 14 +- .../util/AbstractRecordAndOffsetTest.java | 13 +- .../AsyncBlockCompressedInputStreamTest.java | 106 +- .../util/AsyncBufferedIteratorTest.java | 35 +- .../htsjdk/samtools/util/AsyncWriterTest.java | 6 +- .../htsjdk/samtools/util/BinaryCodecTest.java | 67 +- .../BlockCompressedFilePointerUtilTest.java | 101 +- .../util/BlockCompressedInputStreamTest.java | 215 +-- .../util/BlockCompressedOutputStreamTest.java | 127 +- .../util/BlockCompressedTerminatorTest.java | 45 +- .../samtools/util/BufferedLineReaderTest.java | 19 +- .../samtools/util/CigarElementUnitTest.java | 24 +- .../htsjdk/samtools/util/CigarUtilTest.java | 634 ++++++-- .../samtools/util/CloseableIteratorTest.java | 13 +- .../htsjdk/samtools/util/CodeUtilTest.java | 7 +- .../samtools/util/ComparableTupleTest.java | 44 +- .../util/CoordSpanInputSteamTest.java | 16 +- .../htsjdk/samtools/util/DateParserTest.java | 22 +- .../samtools/util/DiskBackedQueueTest.java | 34 +- .../samtools/util/EdgeReadIteratorTest.java | 195 +-- .../util/EdgingRecordAndOffsetTest.java | 1 - .../htsjdk/samtools/util/GZIIndexTest.java | 50 +- .../htsjdk/samtools/util/GzipCodecTest.java | 27 +- .../htsjdk/samtools/util/HistogramTest.java | 192 ++- .../samtools/util/HtsgetRequestUnitTest.java | 121 +- .../samtools/util/HtsgetResponseUnitTest.java | 36 +- .../htsjdk/samtools/util/HttpUtilsTest.java | 11 +- .../java/htsjdk/samtools/util/IOUtilTest.java | 380 ++--- .../samtools/util/IntervalCodecTest.java | 10 +- .../samtools/util/IntervalListTest.java | 403 +++-- .../samtools/util/IntervalListWriterTest.java | 13 +- .../htsjdk/samtools/util/IntervalTest.java | 18 +- .../samtools/util/IntervalTreeMapTest.java | 24 +- .../samtools/util/IntervalTreeTest.java | 218 +-- .../samtools/util/IntervalUtilTest.java | 24 +- .../htsjdk/samtools/util/Iso8601DateTest.java | 3 +- .../java/htsjdk/samtools/util/IupacTest.java | 13 +- .../samtools/util/LocatableUnitTest.java | 174 ++- .../java/htsjdk/samtools/util/LogTest.java | 5 +- .../util/Md5CalculatingOutputStreamTest.java | 15 +- .../samtools/util/MergingIteratorTest.java | 338 ++-- .../samtools/util/OverlapDetectorTest.java | 205 +-- .../util/PositionalOutputStreamTest.java | 8 +- .../util/QualityEncodingDetectorTest.java | 68 +- .../samtools/util/QuietTestWrapper.java | 6 +- .../util/RelativeIso8601DateTest.java | 17 +- .../SAMRecordPrefetchingIteratorTest.java | 45 +- .../samtools/util/SamLocusIteratorTest.java | 168 +- .../samtools/util/SequenceUtilTest.java | 702 +++++---- .../samtools/util/SnappyLoaderUnitTest.java | 21 +- .../util/SolexaQualityConverterTest.java | 103 +- .../samtools/util/SortingCollectionTest.java | 59 +- .../util/SortingLongCollectionTest.java | 28 +- .../samtools/util/TrimmingUtilTest.java | 24 +- .../java/htsjdk/samtools/util/TupleTest.java | 16 +- .../samtools/util/zip/LibdeflateTest.java | 35 +- .../SeekableByteChannelFromBuffer.java | 120 +- .../tribble/AbstractFeatureReaderTest.java | 165 +- .../htsjdk/tribble/AsciiFeatureCodecTest.java | 5 +- .../htsjdk/tribble/BinaryFeaturesTest.java | 30 +- .../htsjdk/tribble/FeatureReaderTest.java | 82 +- .../IntervalList/IntervalListCodecTest.java | 64 +- src/test/java/htsjdk/tribble/TestUtils.java | 13 +- .../TribbleIndexedFeatureReaderTest.java | 54 +- src/test/java/htsjdk/tribble/TribbleTest.java | 22 +- .../java/htsjdk/tribble/VCFRedirectCodec.java | 7 +- .../htsjdk/tribble/annotation/StrandTest.java | 50 +- .../java/htsjdk/tribble/bed/BEDCodecTest.java | 42 +- .../htsjdk/tribble/gff/Gff3CodecTest.java | 826 ++++++++-- .../htsjdk/tribble/gff/Gff3FeatureTest.java | 624 +++++++- .../htsjdk/tribble/gff/Gff3WriterTest.java | 98 +- .../tribble/index/IndexFactoryTest.java | 99 +- .../java/htsjdk/tribble/index/IndexTest.java | 63 +- .../index/interval/IntervalTreeTest.java | 25 +- .../tribble/index/linear/LinearIndexTest.java | 55 +- .../tribble/index/tabix/TabixIndexTest.java | 121 +- .../index/tabix/TbiEqualityChecker.java | 29 +- .../tribble/readers/AsciiLineReaderTest.java | 38 +- .../BlockCompressedAsciiLineReaderTest.java | 10 +- .../readers/LongLineBufferedReaderTest.java | 10 +- .../readers/PositionalBufferedStreamTest.java | 53 +- .../htsjdk/tribble/readers/ReaderTest.java | 53 +- .../SynchronousLineReaderUnitTest.java | 11 +- .../tribble/readers/TabixReaderTest.java | 72 +- .../htsjdk/tribble/util/ParsingUtilsTest.java | 93 +- .../tribble/util/ftp/FTPClientTest.java | 32 +- .../htsjdk/tribble/util/ftp/FTPUtilsTest.java | 19 +- .../popgen/HardyWeinbergCalculationTest.java | 34 +- .../java/htsjdk/utils/ClassFinderTest.java | 16 +- .../java/htsjdk/utils/SamtoolsTestUtils.java | 34 +- .../htsjdk/utils/SamtoolsTestUtilsTest.java | 13 +- src/test/java/htsjdk/utils/TestNGUtils.java | 24 +- .../java/htsjdk/utils/TestNGUtilsTest.java | 150 +- .../variant/PrintVariantsExampleTest.java | 73 +- .../java/htsjdk/variant/VariantBaseTest.java | 143 +- .../bcf2/BCF2EncoderDecoderUnitTest.java | 291 ++-- .../variant/bcf2/BCF2UtilsUnitTest.java | 171 ++- .../htsjdk/variant/bcf2/BCF2VersionTest.java | 38 +- .../variant/bcf2/BCF2WriterUnitTest.java | 149 +- .../htsjdk/variant/bcf2/BCFCodecTest.java | 15 +- .../SAMSequenceDictionaryExtractorTest.java | 33 +- .../variant/utils/VCFHeaderReaderTest.java | 22 +- .../variantcontext/AlleleUnitTest.java | 126 +- .../variantcontext/GenotypeBuilderTest.java | 65 +- .../GenotypeLikelihoodsUnitTest.java | 315 ++-- .../variantcontext/GenotypeUnitTest.java | 189 ++- .../GenotypesContextUnitTest.java | 100 +- .../VariantContextBuilderTest.java | 159 +- .../VariantContextTestProvider.java | 613 ++++---- .../VariantContextUnitTest.java | 765 +++++---- .../VariantJEXLContextUnitTest.java | 192 +-- .../filter/CompoundFilterTest.java | 21 +- .../FilteringVariantContextIteratorTest.java | 34 +- .../filter/GenotypeQualityFilterTest.java | 61 +- .../filter/HeterozygosityFilterTest.java | 106 +- .../filter/JavascriptVariantFilterTest.java | 14 +- .../filter/PassingVariantFilterTest.java | 24 +- .../variantcontext/filter/SnpFilterTest.java | 32 +- .../AsyncVariantContextWriterUnitTest.java | 90 +- .../TabixOnTheFlyIndexCreationTest.java | 9 +- .../writer/VCFWriterUnitTest.java | 146 +- .../VariantContextWriterBuilderUnitTest.java | 212 ++- .../writer/VariantContextWritersUnitTest.java | 78 +- .../variant/vcf/AbstractVCFCodecTest.java | 41 +- .../variant/vcf/IndexFactoryUnitTest.java | 64 +- .../variant/vcf/VCFCodec42FeaturesTest.java | 11 +- .../variant/vcf/VCFCodec43FeaturesTest.java | 109 +- .../vcf/VCFCompoundHeaderLineUnitTest.java | 47 +- .../htsjdk/variant/vcf/VCFEncoderTest.java | 149 +- .../htsjdk/variant/vcf/VCFFileReaderTest.java | 113 +- .../vcf/VCFHeaderLineTranslatorUnitTest.java | 153 +- .../variant/vcf/VCFHeaderLineUnitTest.java | 48 +- .../htsjdk/variant/vcf/VCFHeaderUnitTest.java | 544 ++++--- .../variant/vcf/VCFHeaderVersionTest.java | 39 +- .../htsjdk/variant/vcf/VCFIteratorTest.java | 112 +- .../htsjdk/variant/vcf/VCFMergerTest.java | 46 +- .../vcf/VCFStandardHeaderLinesUnitTest.java | 288 ++-- .../variant/vcf/VCFTextTransformerTest.java | 58 +- .../java/htsjdk/variant/vcf/VCFUtilsTest.java | 63 +- 1155 files changed, 42518 insertions(+), 35586 deletions(-) diff --git a/src/main/java/htsjdk/annotations/BetaAPI.java b/src/main/java/htsjdk/annotations/BetaAPI.java index 1d4e5beaec..cee4709c45 100644 --- a/src/main/java/htsjdk/annotations/BetaAPI.java +++ b/src/main/java/htsjdk/annotations/BetaAPI.java @@ -1,13 +1,13 @@ package htsjdk.annotations; +import static java.lang.annotation.ElementType.*; + import java.lang.annotation.Documented; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import static java.lang.annotation.ElementType.*; - /** * Annotation indicating that a package, class, method, or type is release level "BETA", and is not part * of the stable public API. BETA APIs are published for evaluation, and may be changed or removed without a @@ -17,5 +17,4 @@ @Retention(RetentionPolicy.SOURCE) @Inherited @Documented -public @interface BetaAPI { -} +public @interface BetaAPI {} diff --git a/src/main/java/htsjdk/annotations/InternalAPI.java b/src/main/java/htsjdk/annotations/InternalAPI.java index faf0730a01..1eb73861c8 100644 --- a/src/main/java/htsjdk/annotations/InternalAPI.java +++ b/src/main/java/htsjdk/annotations/InternalAPI.java @@ -1,13 +1,13 @@ package htsjdk.annotations; +import static java.lang.annotation.ElementType.*; + import java.lang.annotation.Documented; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import static java.lang.annotation.ElementType.*; - /** * Annotation indicating that a package, class, method, or type is release level "internal", even if the * access modifier is "public". {@link InternalAPI} types are intended to be for internal use only, and @@ -18,5 +18,4 @@ @Retention(RetentionPolicy.SOURCE) @Inherited @Documented -public @interface InternalAPI { -} +public @interface InternalAPI {} diff --git a/src/main/java/htsjdk/beta/codecs/hapref/fasta/FASTACodecV1_0.java b/src/main/java/htsjdk/beta/codecs/hapref/fasta/FASTACodecV1_0.java index db3d633407..fc7a5f3d3f 100644 --- a/src/main/java/htsjdk/beta/codecs/hapref/fasta/FASTACodecV1_0.java +++ b/src/main/java/htsjdk/beta/codecs/hapref/fasta/FASTACodecV1_0.java @@ -1,22 +1,21 @@ package htsjdk.beta.codecs.hapref.fasta; +import htsjdk.beta.exception.HtsjdkIOException; +import htsjdk.beta.exception.HtsjdkUnsupportedOperationException; import htsjdk.beta.io.bundle.Bundle; +import htsjdk.beta.io.bundle.SignatureStream; +import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.hapref.HaploidReferenceCodec; import htsjdk.beta.plugin.hapref.HaploidReferenceDecoder; import htsjdk.beta.plugin.hapref.HaploidReferenceDecoderOptions; import htsjdk.beta.plugin.hapref.HaploidReferenceEncoder; -import htsjdk.beta.io.bundle.SignatureStream; -import htsjdk.beta.exception.HtsjdkIOException; -import htsjdk.beta.exception.HtsjdkUnsupportedOperationException; import htsjdk.beta.plugin.hapref.HaploidReferenceEncoderOptions; -import htsjdk.io.IOPath; -import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.hapref.HaploidReferenceFormats; +import htsjdk.io.IOPath; import htsjdk.samtools.util.BlockCompressedStreamConstants; import htsjdk.samtools.util.FileExtensions; import htsjdk.samtools.util.IOUtil; import htsjdk.utils.ValidationUtils; - import java.io.IOException; import java.io.InputStream; import java.util.zip.GZIPInputStream; @@ -38,7 +37,9 @@ public String getFileFormat() { } @Override - public int getSignatureLength() { return BlockCompressedStreamConstants.MAX_COMPRESSED_BLOCK_SIZE; } + public int getSignatureLength() { + return BlockCompressedStreamConstants.MAX_COMPRESSED_BLOCK_SIZE; + } @Override public boolean canDecodeSignature(final SignatureStream signatureStream, final String sourceName) { @@ -46,15 +47,14 @@ public boolean canDecodeSignature(final SignatureStream signatureStream, final S ValidationUtils.nonNull(sourceName, "sourceName"); try { - final InputStream wrappedInputStream = IOUtil.isGZIPInputStream(signatureStream) ? - new GZIPInputStream(signatureStream) : - signatureStream; + final InputStream wrappedInputStream = + IOUtil.isGZIPInputStream(signatureStream) ? new GZIPInputStream(signatureStream) : signatureStream; int ch = wrappedInputStream.read(); if (ch == -1) { - throw new HtsjdkIOException( - String.format("Codec %s failed probing signature for resource %s", this.getDisplayName(), sourceName)); + throw new HtsjdkIOException(String.format( + "Codec %s failed probing signature for resource %s", this.getDisplayName(), sourceName)); } - return ((char) ch) == '>'; // for FASTA, this is all we have to go on... + return ((char) ch) == '>'; // for FASTA, this is all we have to go on... } catch (IOException e) { throw new HtsjdkIOException(String.format("Failure reading signature from stream for %s", sourceName), e); } @@ -63,13 +63,13 @@ public boolean canDecodeSignature(final SignatureStream signatureStream, final S @Override public boolean canDecodeURI(final IOPath ioPath) { ValidationUtils.nonNull(ioPath, "ioPath"); - return FileExtensions.FASTA.stream().anyMatch(ext-> ioPath.hasExtension(ext)); + return FileExtensions.FASTA.stream().anyMatch(ext -> ioPath.hasExtension(ext)); } - @Override + @Override public HaploidReferenceDecoder getDecoder(final Bundle inputBundle, final HaploidReferenceDecoderOptions options) { - ValidationUtils.nonNull(inputBundle, "input bundle"); - ValidationUtils.nonNull(options, "reference encoder options"); + ValidationUtils.nonNull(inputBundle, "input bundle"); + ValidationUtils.nonNull(options, "reference encoder options"); return new FASTADecoderV1_0(inputBundle); } diff --git a/src/main/java/htsjdk/beta/codecs/hapref/fasta/FASTADecoderV1_0.java b/src/main/java/htsjdk/beta/codecs/hapref/fasta/FASTADecoderV1_0.java index 45b50eb35e..7aca489388 100644 --- a/src/main/java/htsjdk/beta/codecs/hapref/fasta/FASTADecoderV1_0.java +++ b/src/main/java/htsjdk/beta/codecs/hapref/fasta/FASTADecoderV1_0.java @@ -1,20 +1,19 @@ package htsjdk.beta.codecs.hapref.fasta; +import htsjdk.annotations.InternalAPI; +import htsjdk.beta.exception.HtsjdkIOException; import htsjdk.beta.io.bundle.Bundle; import htsjdk.beta.io.bundle.BundleResource; import htsjdk.beta.io.bundle.BundleResourceType; import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.hapref.HaploidReferenceDecoder; import htsjdk.beta.plugin.hapref.HaploidReferenceFormats; -import htsjdk.beta.exception.HtsjdkIOException; import htsjdk.samtools.SAMSequenceDictionary; import htsjdk.samtools.reference.ReferenceSequence; import htsjdk.samtools.reference.ReferenceSequenceFile; import htsjdk.samtools.reference.ReferenceSequenceFileFactory; import htsjdk.samtools.seekablestream.SeekableStream; import htsjdk.samtools.util.CloseableIterator; -import htsjdk.annotations.InternalAPI; - import java.io.IOException; /** @@ -25,7 +24,9 @@ public class FASTADecoderV1_0 implements HaploidReferenceDecoder { protected Bundle inputBundle; @Override - public String getDisplayName() { return displayName; } + public String getDisplayName() { + return displayName; + } private final ReferenceSequenceFile referenceSequenceFile; @@ -34,22 +35,23 @@ public FASTADecoderV1_0(final Bundle inputBundle) { this.displayName = inputBundle.getPrimaryResource().getDisplayName(); final BundleResource referenceResource = inputBundle.getOrThrow(BundleResourceType.CT_HAPLOID_REFERENCE); if (referenceResource.getIOPath().isPresent()) { - referenceSequenceFile = ReferenceSequenceFileFactory.getReferenceSequenceFileFromBundle(inputBundle, true, true); + referenceSequenceFile = + ReferenceSequenceFileFactory.getReferenceSequenceFileFromBundle(inputBundle, true, true); } else { - final SeekableStream seekableStream = referenceResource.getSeekableStream().orElseThrow( - () -> new IllegalArgumentException( - String.format("The reference resource %s is not able to supply the required seekable stream", - referenceResource.getDisplayName()))); + final SeekableStream seekableStream = referenceResource + .getSeekableStream() + .orElseThrow(() -> new IllegalArgumentException(String.format( + "The reference resource %s is not able to supply the required seekable stream", + referenceResource.getDisplayName()))); referenceSequenceFile = ReferenceSequenceFileFactory.getReferenceSequenceFile( - referenceResource.getDisplayName(), - seekableStream, - null - ); + referenceResource.getDisplayName(), seekableStream, null); } } @Override - final public String getFileFormat() { return HaploidReferenceFormats.FASTA; } + public final String getFileFormat() { + return HaploidReferenceFormats.FASTA; + } @Override public SAMSequenceDictionary getHeader() { @@ -83,7 +85,7 @@ public ReferenceSequence next() { public void close() { try { referenceSequenceFile.close(); - } catch(final IOException e) { + } catch (final IOException e) { throw new HtsjdkIOException(e); } } @@ -100,7 +102,7 @@ public boolean hasIndex() { return bundleContainsIndex(inputBundle) && referenceSequenceFile.isIndexed(); } - //TODO: we need a solution here that doesn't depend on this getter...its necessary because + // TODO: we need a solution here that doesn't depend on this getter...its necessary because // the generic decoder interface exports an iterable, but we need the native // (indexed by contig) interface implemented on ReferenceSequenceFile to create a ReferenceSource, // it might be possible to write a CRAMReferenceSource implementation that uses the HtsQuery @@ -130,5 +132,4 @@ public void close() { private static boolean bundleContainsIndex(final Bundle inputBundle) { return inputBundle.get(BundleResourceType.CT_READS_INDEX).isPresent(); } - } diff --git a/src/main/java/htsjdk/beta/codecs/reads/ReadsCodecUtils.java b/src/main/java/htsjdk/beta/codecs/reads/ReadsCodecUtils.java index 9e08c9559d..e1d337a3b8 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/ReadsCodecUtils.java +++ b/src/main/java/htsjdk/beta/codecs/reads/ReadsCodecUtils.java @@ -1,5 +1,6 @@ package htsjdk.beta.codecs.reads; +import htsjdk.annotations.InternalAPI; import htsjdk.beta.codecs.reads.bam.BAMDecoderOptions; import htsjdk.beta.io.bundle.Bundle; import htsjdk.beta.io.bundle.BundleResource; @@ -8,8 +9,6 @@ import htsjdk.samtools.SamInputResource; import htsjdk.samtools.SamReader; import htsjdk.samtools.SamReaderFactory; -import htsjdk.annotations.InternalAPI; - import java.util.Optional; /** @@ -18,7 +17,7 @@ * Utilities for use by reads encoder/decoder implementations. */ @InternalAPI -final public class ReadsCodecUtils { +public final class ReadsCodecUtils { /** * InternalAPI @@ -32,17 +31,10 @@ final public class ReadsCodecUtils { */ @InternalAPI public static SamInputResource bundleToSamInputResource( - final Bundle inputBundle, - final ReadsDecoderOptions readsDecoderOptions) { - final SamInputResource samInputResource = readsToSamInputResource( - inputBundle, - BundleResourceType.CT_ALIGNED_READS, - readsDecoderOptions); - indexToSamInputResource( - inputBundle, - BundleResourceType.CT_READS_INDEX, - readsDecoderOptions, - samInputResource); + final Bundle inputBundle, final ReadsDecoderOptions readsDecoderOptions) { + final SamInputResource samInputResource = + readsToSamInputResource(inputBundle, BundleResourceType.CT_ALIGNED_READS, readsDecoderOptions); + indexToSamInputResource(inputBundle, BundleResourceType.CT_READS_INDEX, readsDecoderOptions, samInputResource); return samInputResource; } @@ -56,15 +48,14 @@ public static SamInputResource bundleToSamInputResource( */ @InternalAPI public static void readsDecoderOptionsToSamReaderFactory( - final ReadsDecoderOptions readsDecoderOptions, - final SamReaderFactory samReaderFactory) { + final ReadsDecoderOptions readsDecoderOptions, final SamReaderFactory samReaderFactory) { samReaderFactory.validationStringency(readsDecoderOptions.getValidationStringency()); samReaderFactory.setOption(SamReaderFactory.Option.EAGERLY_DECODE, readsDecoderOptions.isDecodeEagerly()); - samReaderFactory.setOption(SamReaderFactory.Option.CACHE_FILE_BASED_INDEXES, - readsDecoderOptions.isFileBasedIndexCached()); + samReaderFactory.setOption( + SamReaderFactory.Option.CACHE_FILE_BASED_INDEXES, readsDecoderOptions.isFileBasedIndexCached()); // note that this option is the revers polarity from SamReaderFactory, so negate it - samReaderFactory.setOption(SamReaderFactory.Option.DONT_MEMORY_MAP_INDEX, - !readsDecoderOptions.isMemoryMapIndexes()); + samReaderFactory.setOption( + SamReaderFactory.Option.DONT_MEMORY_MAP_INDEX, !readsDecoderOptions.isMemoryMapIndexes()); } /** @@ -95,8 +86,7 @@ public static void assertBundleContainsIndex(final Bundle inputBundle) { if (!bundleContainsIndex(inputBundle)) { throw new IllegalArgumentException(String.format( "To make index queries, an index resource must be provided in the resource bundle: %s", - inputBundle - )); + inputBundle)); } } @@ -121,19 +111,16 @@ public static SamReader getSamReader( @InternalAPI public static void bamDecoderOptionsToSamReaderFactory( - final SamReaderFactory samReaderFactory, - final BAMDecoderOptions bamDecoderOptions) { + final SamReaderFactory samReaderFactory, final BAMDecoderOptions bamDecoderOptions) { samReaderFactory.inflaterFactory(bamDecoderOptions.getInflaterFactory()); samReaderFactory.setUseAsyncIo(bamDecoderOptions.isAsyncIO()); - samReaderFactory.setOption(SamReaderFactory.Option.VALIDATE_CRC_CHECKSUMS, - bamDecoderOptions.isValidateCRCChecksums()); + samReaderFactory.setOption( + SamReaderFactory.Option.VALIDATE_CRC_CHECKSUMS, bamDecoderOptions.isValidateCRCChecksums()); } // convert an input bundle to a SamInputResource private static SamInputResource readsToSamInputResource( - final Bundle inputBundle, - final String contentType, - final ReadsDecoderOptions readsDecoderOptions) { + final Bundle inputBundle, final String contentType, final ReadsDecoderOptions readsDecoderOptions) { final BundleResource readsInput = inputBundle.getOrThrow(contentType); if (!readsInput.hasInputType()) { throw new IllegalArgumentException(String.format( @@ -143,8 +130,9 @@ private static SamInputResource readsToSamInputResource( if (readsInput.hasSeekableStream()) { if (readsInput.getIOPath().isPresent()) { if (readsDecoderOptions.getReadsChannelTransformer().isPresent()) { - //TODO: use a local cloud channel wrapper instead of requiring the user to pass a lambda - return SamInputResource.of(readsInput.getIOPath().get().toPath(), + // TODO: use a local cloud channel wrapper instead of requiring the user to pass a lambda + return SamInputResource.of( + readsInput.getIOPath().get().toPath(), readsDecoderOptions.getReadsChannelTransformer().get()); } else { return SamInputResource.of(readsInput.getIOPath().get().toPath()); @@ -168,8 +156,9 @@ private static void indexToSamInputResource( if (indexResource.getIOPath().isPresent()) { if (indexResource.getIOPath().isPresent()) { if (readsDecoderOptions.getIndexChannelTransformer().isPresent()) { - //TODO: use a local cloud channel wrapper instead of requiring the user to pass a lambda - SamInputResource.of(indexResource.getIOPath().get().toPath(), + // TODO: use a local cloud channel wrapper instead of requiring the user to pass a lambda + SamInputResource.of( + indexResource.getIOPath().get().toPath(), readsDecoderOptions.getIndexChannelTransformer().get()); samInputResource.index(indexResource.getIOPath().get().toPath()); } else if (indexResource.getSeekableStream().isPresent()) { @@ -181,5 +170,4 @@ private static void indexToSamInputResource( } } } - } diff --git a/src/main/java/htsjdk/beta/codecs/reads/bam/BAMCodec.java b/src/main/java/htsjdk/beta/codecs/reads/bam/BAMCodec.java index f1e2c4b611..f3e306ace3 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/bam/BAMCodec.java +++ b/src/main/java/htsjdk/beta/codecs/reads/bam/BAMCodec.java @@ -1,14 +1,13 @@ package htsjdk.beta.codecs.reads.bam; +import htsjdk.annotations.InternalAPI; import htsjdk.beta.io.bundle.BundleResourceType; -import htsjdk.io.IOPath; import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.reads.ReadsCodec; import htsjdk.beta.plugin.reads.ReadsFormats; +import htsjdk.io.IOPath; import htsjdk.samtools.util.FileExtensions; -import htsjdk.annotations.InternalAPI; import htsjdk.utils.ValidationUtils; - import java.util.Arrays; import java.util.HashSet; import java.util.Set; @@ -20,17 +19,18 @@ */ @InternalAPI public abstract class BAMCodec implements ReadsCodec { - public static final HtsVersion BAM_DEFAULT_VERSION = new HtsVersion(1, 0,0); + public static final HtsVersion BAM_DEFAULT_VERSION = new HtsVersion(1, 0, 0); private static final Set extensionMap = new HashSet<>(Arrays.asList(FileExtensions.BAM)); @Override - public String getFileFormat() { return ReadsFormats.BAM; } + public String getFileFormat() { + return ReadsFormats.BAM; + } @Override public boolean canDecodeURI(final IOPath ioPath) { ValidationUtils.nonNull(ioPath, "ioPath"); - return extensionMap.stream().anyMatch(ext-> ioPath.hasExtension(ext)); + return extensionMap.stream().anyMatch(ext -> ioPath.hasExtension(ext)); } - } diff --git a/src/main/java/htsjdk/beta/codecs/reads/bam/BAMDecoder.java b/src/main/java/htsjdk/beta/codecs/reads/bam/BAMDecoder.java index 4190c3b8ba..34c0227ac6 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/bam/BAMDecoder.java +++ b/src/main/java/htsjdk/beta/codecs/reads/bam/BAMDecoder.java @@ -1,11 +1,11 @@ package htsjdk.beta.codecs.reads.bam; +import htsjdk.annotations.InternalAPI; import htsjdk.beta.io.bundle.Bundle; import htsjdk.beta.io.bundle.BundleResourceType; +import htsjdk.beta.plugin.reads.ReadsDecoder; import htsjdk.beta.plugin.reads.ReadsDecoderOptions; import htsjdk.beta.plugin.reads.ReadsFormats; -import htsjdk.beta.plugin.reads.ReadsDecoder; -import htsjdk.annotations.InternalAPI; import htsjdk.utils.ValidationUtils; /** @@ -30,19 +30,24 @@ public abstract class BAMDecoder implements ReadsDecoder { */ @InternalAPI public BAMDecoder(final Bundle inputBundle, final ReadsDecoderOptions readsDecoderOptions) { - ValidationUtils.nonNull(inputBundle,"inputBundle"); + ValidationUtils.nonNull(inputBundle, "inputBundle"); ValidationUtils.nonNull(readsDecoderOptions, "readsDecoderOptions"); this.inputBundle = inputBundle; - this.displayName = inputBundle.getOrThrow(BundleResourceType.CT_ALIGNED_READS).getDisplayName(); + this.displayName = + inputBundle.getOrThrow(BundleResourceType.CT_ALIGNED_READS).getDisplayName(); this.readsDecoderOptions = readsDecoderOptions; } @Override - final public String getFileFormat() { return ReadsFormats.BAM; } + public final String getFileFormat() { + return ReadsFormats.BAM; + } @Override - final public String getDisplayName() { return displayName; } + public final String getDisplayName() { + return displayName; + } /** * Get the input {@link Bundle} for this decoder. diff --git a/src/main/java/htsjdk/beta/codecs/reads/bam/BAMDecoderOptions.java b/src/main/java/htsjdk/beta/codecs/reads/bam/BAMDecoderOptions.java index 34b6e0307f..df04eb5cbc 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/bam/BAMDecoderOptions.java +++ b/src/main/java/htsjdk/beta/codecs/reads/bam/BAMDecoderOptions.java @@ -9,7 +9,7 @@ * Decoder options specific to BAM decoders. */ public class BAMDecoderOptions { - //SAMRecordFactory isn't carried over from SAMReaderFactory as an option, since it doesn't appear to + // SAMRecordFactory isn't carried over from SAMReaderFactory as an option, since it doesn't appear to // actually be used anywhere anymore (??) // // includeInSource isn't carried over since it populates SAMRecords with a SamReader, which the plugin @@ -19,8 +19,8 @@ public class BAMDecoderOptions { // (all, including splitting) index creation into htsjdk. private InflaterFactory inflaterFactory = BlockGunzipper.getDefaultInflaterFactory(); - private boolean asyncIO = Defaults.USE_ASYNC_IO_READ_FOR_SAMTOOLS; - private boolean validateCRCChecksums = false; + private boolean asyncIO = Defaults.USE_ASYNC_IO_READ_FOR_SAMTOOLS; + private boolean validateCRCChecksums = false; /** * Get the {@link InflaterFactory} used for these options. Defaults to @@ -85,5 +85,4 @@ public BAMDecoderOptions setValidateCRCChecksums(final boolean validateCRCChecks this.validateCRCChecksums = validateCRCChecksums; return this; } - } diff --git a/src/main/java/htsjdk/beta/codecs/reads/bam/BAMEncoder.java b/src/main/java/htsjdk/beta/codecs/reads/bam/BAMEncoder.java index dc9d5f7010..9b09f1d6d7 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/bam/BAMEncoder.java +++ b/src/main/java/htsjdk/beta/codecs/reads/bam/BAMEncoder.java @@ -2,9 +2,9 @@ import htsjdk.beta.io.bundle.Bundle; import htsjdk.beta.io.bundle.BundleResourceType; +import htsjdk.beta.plugin.reads.ReadsEncoder; import htsjdk.beta.plugin.reads.ReadsEncoderOptions; import htsjdk.beta.plugin.reads.ReadsFormats; -import htsjdk.beta.plugin.reads.ReadsEncoder; import htsjdk.utils.ValidationUtils; /** @@ -31,19 +31,24 @@ public abstract class BAMEncoder implements ReadsEncoder { * @param readsEncoderOptions {@link ReadsEncoderOptions} to use */ public BAMEncoder(final Bundle outputBundle, final ReadsEncoderOptions readsEncoderOptions) { - ValidationUtils.nonNull(outputBundle,"outputBundle"); + ValidationUtils.nonNull(outputBundle, "outputBundle"); ValidationUtils.nonNull(readsEncoderOptions, "readsEncoderOptions"); this.outputBundle = outputBundle; this.readsEncoderOptions = readsEncoderOptions; - this.displayName = outputBundle.getOrThrow(BundleResourceType.CT_ALIGNED_READS).getDisplayName(); + this.displayName = + outputBundle.getOrThrow(BundleResourceType.CT_ALIGNED_READS).getDisplayName(); } @Override - final public String getFileFormat() { return ReadsFormats.BAM; } + public final String getFileFormat() { + return ReadsFormats.BAM; + } @Override - final public String getDisplayName() { return displayName; } + public final String getDisplayName() { + return displayName; + } /** * Get the output {@link Bundle} for this encoder. @@ -62,5 +67,4 @@ public Bundle getOutputBundle() { public ReadsEncoderOptions getReadsEncoderOptions() { return readsEncoderOptions; } - } diff --git a/src/main/java/htsjdk/beta/codecs/reads/bam/BAMEncoderOptions.java b/src/main/java/htsjdk/beta/codecs/reads/bam/BAMEncoderOptions.java index 30ae57424f..3ceb40bb9d 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/bam/BAMEncoderOptions.java +++ b/src/main/java/htsjdk/beta/codecs/reads/bam/BAMEncoderOptions.java @@ -15,13 +15,13 @@ public class BAMEncoderOptions { public static final int DEAFULT_MAX_RECORDS_IN_RAM = 500000; - private int outputBufferSize = Defaults.BUFFER_SIZE; - private boolean asyncIO = Defaults.USE_ASYNC_IO_WRITE_FOR_SAMTOOLS; - private int asyncOutputBufferSize = AbstractAsyncWriter.DEFAULT_QUEUE_SIZE; - private IOPath tempDirPath = new HtsPath(IOUtil.getDefaultTmpDirPath().toString()); - private int compressionLevel = BlockCompressedOutputStream.getDefaultCompressionLevel(); - private Integer maxRecordsInRAM = DEAFULT_MAX_RECORDS_IN_RAM; - private DeflaterFactory deflaterFactory = BlockCompressedOutputStream.getDefaultDeflaterFactory(); + private int outputBufferSize = Defaults.BUFFER_SIZE; + private boolean asyncIO = Defaults.USE_ASYNC_IO_WRITE_FOR_SAMTOOLS; + private int asyncOutputBufferSize = AbstractAsyncWriter.DEFAULT_QUEUE_SIZE; + private IOPath tempDirPath = new HtsPath(IOUtil.getDefaultTmpDirPath().toString()); + private int compressionLevel = BlockCompressedOutputStream.getDefaultCompressionLevel(); + private Integer maxRecordsInRAM = DEAFULT_MAX_RECORDS_IN_RAM; + private DeflaterFactory deflaterFactory = BlockCompressedOutputStream.getDefaultDeflaterFactory(); // SAM only ?: private SamFlagField samFlagFieldOutput = SamFlagField.NONE; /** @@ -194,5 +194,4 @@ public BAMEncoderOptions setDeflaterFactory(DeflaterFactory deflaterFactory) { this.deflaterFactory = deflaterFactory; return this; } - } diff --git a/src/main/java/htsjdk/beta/codecs/reads/bam/bamV1_0/BAMCodecV1_0.java b/src/main/java/htsjdk/beta/codecs/reads/bam/bamV1_0/BAMCodecV1_0.java index 1f13c92672..18fac5c1e9 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/bam/bamV1_0/BAMCodecV1_0.java +++ b/src/main/java/htsjdk/beta/codecs/reads/bam/bamV1_0/BAMCodecV1_0.java @@ -3,17 +3,16 @@ import htsjdk.beta.codecs.reads.bam.BAMCodec; import htsjdk.beta.codecs.reads.bam.BAMDecoder; import htsjdk.beta.codecs.reads.bam.BAMEncoder; +import htsjdk.beta.exception.HtsjdkIOException; +import htsjdk.beta.exception.HtsjdkUnsupportedOperationException; import htsjdk.beta.io.bundle.Bundle; import htsjdk.beta.io.bundle.SignatureStream; -import htsjdk.beta.exception.HtsjdkIOException; import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.reads.ReadsDecoderOptions; import htsjdk.beta.plugin.reads.ReadsEncoderOptions; -import htsjdk.beta.exception.HtsjdkUnsupportedOperationException; import htsjdk.samtools.SamStreams; import htsjdk.samtools.util.BlockCompressedStreamConstants; import htsjdk.utils.ValidationUtils; - import java.io.IOException; /** @@ -28,7 +27,9 @@ public HtsVersion getVersion() { } @Override - public int getSignatureProbeLength() { return BlockCompressedStreamConstants.MAX_COMPRESSED_BLOCK_SIZE; } + public int getSignatureProbeLength() { + return BlockCompressedStreamConstants.MAX_COMPRESSED_BLOCK_SIZE; + } @Override public int getSignatureLength() { @@ -62,5 +63,4 @@ public BAMEncoder getEncoder(final Bundle outputBundle, final ReadsEncoderOption public boolean runVersionUpgrade(final HtsVersion sourceCodecVersion, final HtsVersion targetCodecVersion) { throw new HtsjdkUnsupportedOperationException("Upgrade not yet implemented"); } - } diff --git a/src/main/java/htsjdk/beta/codecs/reads/bam/bamV1_0/BAMDecoderV1_0.java b/src/main/java/htsjdk/beta/codecs/reads/bam/bamV1_0/BAMDecoderV1_0.java index f802fc0797..e4a1fb275e 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/bam/bamV1_0/BAMDecoderV1_0.java +++ b/src/main/java/htsjdk/beta/codecs/reads/bam/bamV1_0/BAMDecoderV1_0.java @@ -2,14 +2,13 @@ import htsjdk.beta.codecs.reads.ReadsCodecUtils; import htsjdk.beta.codecs.reads.bam.BAMDecoder; +import htsjdk.beta.exception.HtsjdkIOException; import htsjdk.beta.io.bundle.Bundle; import htsjdk.beta.io.bundle.BundleResourceType; -import htsjdk.beta.plugin.interval.HtsIntervalUtils; -import htsjdk.beta.exception.HtsjdkIOException; import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.interval.HtsInterval; +import htsjdk.beta.plugin.interval.HtsIntervalUtils; import htsjdk.beta.plugin.interval.HtsQueryRule; - import htsjdk.beta.plugin.reads.ReadsDecoderOptions; import htsjdk.samtools.QueryInterval; import htsjdk.samtools.SAMFileHeader; @@ -18,13 +17,12 @@ import htsjdk.samtools.SamReaderFactory; import htsjdk.samtools.util.CloseableIterator; import htsjdk.utils.ValidationUtils; - import java.io.IOException; import java.util.List; import java.util.Optional; /** - * BAM v1.0 decoder. + * BAM v1.0 decoder. */ public class BAMDecoderV1_0 extends BAMDecoder { private final SamReader samReader; @@ -78,9 +76,8 @@ public CloseableIterator query(final List intervals, fin ValidationUtils.nonNull(queryRule, "queryRule"); ReadsCodecUtils.assertBundleContainsIndex(getInputBundle()); - final QueryInterval[] queryIntervals = HtsIntervalUtils.toQueryIntervalArray( - intervals, - samFileHeader.getSequenceDictionary()); + final QueryInterval[] queryIntervals = + HtsIntervalUtils.toQueryIntervalArray(intervals, samFileHeader.getSequenceDictionary()); return samReader.query(queryIntervals, queryRule == HtsQueryRule.CONTAINED); } @@ -116,5 +113,4 @@ public void close() { throw new HtsjdkIOException(String.format("Exception closing reader for %s", getInputBundle()), e); } } - } diff --git a/src/main/java/htsjdk/beta/codecs/reads/bam/bamV1_0/BAMEncoderV1_0.java b/src/main/java/htsjdk/beta/codecs/reads/bam/bamV1_0/BAMEncoderV1_0.java index b0fa567229..fd2230250d 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/bam/bamV1_0/BAMEncoderV1_0.java +++ b/src/main/java/htsjdk/beta/codecs/reads/bam/bamV1_0/BAMEncoderV1_0.java @@ -4,16 +4,15 @@ import htsjdk.beta.codecs.reads.bam.BAMEncoderOptions; import htsjdk.beta.exception.HtsjdkUnsupportedOperationException; import htsjdk.beta.io.bundle.Bundle; -import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.io.bundle.BundleResource; import htsjdk.beta.io.bundle.BundleResourceType; +import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.reads.ReadsEncoderOptions; import htsjdk.samtools.SAMFileHeader; import htsjdk.samtools.SAMFileWriter; import htsjdk.samtools.SAMFileWriterFactory; import htsjdk.samtools.SAMRecord; import htsjdk.utils.ValidationUtils; - import java.util.Optional; /** @@ -50,8 +49,7 @@ public void write(final SAMRecord record) { ValidationUtils.nonNull(record, "record"); if (samFileWriter == null) { throw new IllegalStateException(String.format( - "A SAMFileHeader must be established before records can be written for %s", - getDisplayName())); + "A SAMFileHeader must be established before records can be written for %s", getDisplayName())); } samFileWriter.addAlignment(record); } @@ -67,11 +65,11 @@ public void close() { * Propagate BAMEncoderOptions to a SAMFileWriterFactory. */ private static void bamEncoderOptionsToSamWriterFactory( - final BAMEncoderOptions bamEncoderOptions, - final SAMFileWriterFactory samFileWriterFactory) { + final BAMEncoderOptions bamEncoderOptions, final SAMFileWriterFactory samFileWriterFactory) { samFileWriterFactory.setDeflaterFactory(bamEncoderOptions.getDeflaterFactory()); samFileWriterFactory.setCompressionLevel(bamEncoderOptions.getCompressionLevel()); - samFileWriterFactory.setTempDirectory(bamEncoderOptions.getTemporaryDirectory().toPath().toFile()); + samFileWriterFactory.setTempDirectory( + bamEncoderOptions.getTemporaryDirectory().toPath().toFile()); samFileWriterFactory.setBufferSize(bamEncoderOptions.getOutputBufferSize()); samFileWriterFactory.setUseAsyncIo(bamEncoderOptions.isAsyncIO()); samFileWriterFactory.setAsyncOutputBufferSize(bamEncoderOptions.getAsyncOutputBufferSize()); @@ -79,8 +77,7 @@ private static void bamEncoderOptionsToSamWriterFactory( } private SAMFileWriter getBAMFileWriter( - final ReadsEncoderOptions readsEncoderOptions, - final SAMFileHeader samFileHeader) { + final ReadsEncoderOptions readsEncoderOptions, final SAMFileHeader samFileHeader) { final BAMEncoderOptions bamEncoderOptions = readsEncoderOptions.getBAMEncoderOptions(); final SAMFileWriterFactory samFileWriterFactory = new SAMFileWriterFactory(); bamEncoderOptionsToSamWriterFactory(bamEncoderOptions, samFileWriterFactory); @@ -91,7 +88,7 @@ private SAMFileWriter getBAMFileWriter( final Optional optIndexResource = getOutputBundle().get(BundleResourceType.CT_READS_INDEX); final Optional optMD5Resource = getOutputBundle().get(BundleResourceType.CT_MD5); - //TODO: BAMFileWriter currently only supports writing an index to a plain file, so for now + // TODO: BAMFileWriter currently only supports writing an index to a plain file, so for now // throw if an index is requested on any other type if (optIndexResource.isPresent()) { final BundleResource indexResource = optIndexResource.get(); @@ -102,25 +99,20 @@ private SAMFileWriter getBAMFileWriter( } } - //TODO: BAMFileWriter currently only supports writing an md5 to a plain file with a name that + // TODO: BAMFileWriter currently only supports writing an md5 to a plain file with a name that // it chooses, so throw if an md5 resource is specified since we can't direct it to the specified // resource if (optMD5Resource.isPresent()) { - throw new HtsjdkUnsupportedOperationException(String.format( - "Specifying an an MD5 resource name not yet implemented on %s", getDisplayName())); + throw new HtsjdkUnsupportedOperationException( + String.format("Specifying an an MD5 resource name not yet implemented on %s", getDisplayName())); } if (readsResource.getIOPath().isPresent()) { return samFileWriterFactory.makeBAMWriter( - samFileHeader, - preSorted, - readsResource.getIOPath().get().toPath()); + samFileHeader, preSorted, readsResource.getIOPath().get().toPath()); } else { return samFileWriterFactory.makeBAMWriter( - samFileHeader, - preSorted, - readsResource.getOutputStream().get()); + samFileHeader, preSorted, readsResource.getOutputStream().get()); } } - } diff --git a/src/main/java/htsjdk/beta/codecs/reads/cram/CRAMCodec.java b/src/main/java/htsjdk/beta/codecs/reads/cram/CRAMCodec.java index 1e56bf7bc0..2899e69b0e 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/cram/CRAMCodec.java +++ b/src/main/java/htsjdk/beta/codecs/reads/cram/CRAMCodec.java @@ -1,23 +1,22 @@ package htsjdk.beta.codecs.reads.cram; +import htsjdk.annotations.InternalAPI; import htsjdk.beta.codecs.hapref.fasta.FASTADecoderV1_0; +import htsjdk.beta.exception.HtsjdkException; import htsjdk.beta.exception.HtsjdkIOException; import htsjdk.beta.exception.HtsjdkUnsupportedOperationException; -import htsjdk.beta.exception.HtsjdkException; import htsjdk.beta.io.bundle.BundleResourceType; import htsjdk.beta.io.bundle.SignatureStream; -import htsjdk.io.IOPath; import htsjdk.beta.plugin.HtsVersion; -import htsjdk.beta.plugin.registry.HtsDefaultRegistry; import htsjdk.beta.plugin.reads.ReadsCodec; import htsjdk.beta.plugin.reads.ReadsFormats; +import htsjdk.beta.plugin.registry.HtsDefaultRegistry; +import htsjdk.io.IOPath; import htsjdk.samtools.cram.ref.CRAMReferenceSource; import htsjdk.samtools.cram.ref.ReferenceSource; import htsjdk.samtools.reference.ReferenceSequenceFile; import htsjdk.samtools.util.FileExtensions; -import htsjdk.annotations.InternalAPI; import htsjdk.utils.ValidationUtils; - import java.io.IOException; import java.util.Arrays; import java.util.HashSet; @@ -33,13 +32,15 @@ public abstract class CRAMCodec implements ReadsCodec { protected static final Set extensionMap = new HashSet<>(Arrays.asList(FileExtensions.CRAM)); @Override - public String getFileFormat() { return ReadsFormats.CRAM; } + public String getFileFormat() { + return ReadsFormats.CRAM; + } @Override public boolean canDecodeURI(final IOPath ioPath) { ValidationUtils.nonNull(ioPath, "ioPath"); - return extensionMap.stream().anyMatch(ext-> ioPath.hasExtension(ext)); + return extensionMap.stream().anyMatch(ext -> ioPath.hasExtension(ext)); } @Override @@ -74,7 +75,7 @@ static CRAMReferenceSource getCRAMReferenceSource(final IOPath referencePath) { throw new HtsjdkException(String.format("Unable to get reference codec for %s", referencePath)); } - //TODO: we need a solution here doesn't require access to this getter...its necessary because + // TODO: we need a solution here doesn't require access to this getter...its necessary because // the generic decoder interface is an iterable, but we need the native (indexed // by contig) interface implemented on ReferenceSequenceFile to create a ReferenceSource, so we // need to cast the decoder to get access to the ReferenceSequenceFile; it might be possible to @@ -89,5 +90,4 @@ static CRAMReferenceSource getCRAMReferenceSource(final IOPath referencePath) { * @return the signature string for this codec */ protected abstract String getSignatureString(); - } diff --git a/src/main/java/htsjdk/beta/codecs/reads/cram/CRAMDecoder.java b/src/main/java/htsjdk/beta/codecs/reads/cram/CRAMDecoder.java index 86136f96f7..c8e2365403 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/cram/CRAMDecoder.java +++ b/src/main/java/htsjdk/beta/codecs/reads/cram/CRAMDecoder.java @@ -1,5 +1,6 @@ package htsjdk.beta.codecs.reads.cram; +import htsjdk.annotations.InternalAPI; import htsjdk.beta.codecs.reads.ReadsCodecUtils; import htsjdk.beta.exception.HtsjdkIOException; import htsjdk.beta.io.bundle.Bundle; @@ -7,9 +8,9 @@ import htsjdk.beta.plugin.interval.HtsInterval; import htsjdk.beta.plugin.interval.HtsIntervalUtils; import htsjdk.beta.plugin.interval.HtsQueryRule; +import htsjdk.beta.plugin.reads.ReadsDecoder; import htsjdk.beta.plugin.reads.ReadsDecoderOptions; import htsjdk.beta.plugin.reads.ReadsFormats; -import htsjdk.beta.plugin.reads.ReadsDecoder; import htsjdk.samtools.QueryInterval; import htsjdk.samtools.SAMFileHeader; import htsjdk.samtools.SAMFormatException; @@ -20,9 +21,7 @@ import htsjdk.samtools.cram.ref.CRAMReferenceSource; import htsjdk.samtools.cram.ref.ReferenceSource; import htsjdk.samtools.util.CloseableIterator; -import htsjdk.annotations.InternalAPI; import htsjdk.utils.ValidationUtils; - import java.io.IOException; import java.util.List; import java.util.Optional; @@ -57,17 +56,22 @@ public CRAMDecoder(final Bundle inputBundle, final ReadsDecoderOptions readsDeco this.inputBundle = inputBundle; this.readsDecoderOptions = readsDecoderOptions; - this.displayName = inputBundle.getOrThrow(BundleResourceType.CT_ALIGNED_READS).getDisplayName(); + this.displayName = + inputBundle.getOrThrow(BundleResourceType.CT_ALIGNED_READS).getDisplayName(); samReader = getSamReaderForCRAM(inputBundle, readsDecoderOptions); samFileHeader = samReader.getFileHeader(); } @Override - final public String getFileFormat() { return ReadsFormats.CRAM; } + public final String getFileFormat() { + return ReadsFormats.CRAM; + } @Override - final public String getDisplayName() { return displayName; } + public final String getDisplayName() { + return displayName; + } @Override public SAMFileHeader getHeader() { @@ -84,7 +88,9 @@ public void close() { } @Override - public CloseableIterator iterator() { return getIteratorMonitor(() -> samReader.iterator()); } + public CloseableIterator iterator() { + return getIteratorMonitor(() -> samReader.iterator()); + } @Override public boolean isQueryable() { @@ -101,16 +107,16 @@ public CloseableIterator query(final List intervals, fin ValidationUtils.nonNull(intervals, "intervals"); ValidationUtils.nonNull(queryRule, "queryRule"); - final QueryInterval[] queryIntervals = HtsIntervalUtils.toQueryIntervalArray( - intervals, - samFileHeader.getSequenceDictionary()); + final QueryInterval[] queryIntervals = + HtsIntervalUtils.toQueryIntervalArray(intervals, samFileHeader.getSequenceDictionary()); return getIteratorMonitor(() -> samReader.query(queryIntervals, queryRule == HtsQueryRule.CONTAINED)); } @Override public CloseableIterator queryStart(final String queryName, final long start) { ValidationUtils.nonNull(queryName, "queryName"); - return getIteratorMonitor(() -> samReader.queryAlignmentStart(queryName, HtsIntervalUtils.toIntegerSafe(start))); + return getIteratorMonitor( + () -> samReader.queryAlignmentStart(queryName, HtsIntervalUtils.toIntegerSafe(start))); } @Override @@ -126,27 +132,28 @@ public Optional queryMate(SAMRecord rec) { ValidationUtils.nonNull(rec, "rec"); if (!rec.getReadPairedFlag()) { - throw new IllegalArgumentException(String.format("queryMate called for unpaired read on %s.", getDisplayName())); + throw new IllegalArgumentException( + String.format("queryMate called for unpaired read on %s.", getDisplayName())); } if (rec.getFirstOfPairFlag() == rec.getSecondOfPairFlag()) { - throw new IllegalArgumentException(String.format("SAMRecord must be either first and second of pair, but not both (%s).", - getDisplayName())); + throw new IllegalArgumentException(String.format( + "SAMRecord must be either first and second of pair, but not both (%s).", getDisplayName())); } final boolean firstOfPair = rec.getFirstOfPairFlag(); // its important that this method closes the iterators it creates, since otherwise the caller // will never be able to create another iterator after calling this method try (final CloseableIterator it = - rec.getMateReferenceIndex() == SAMRecord.NO_ALIGNMENT_REFERENCE_INDEX ? - queryUnmapped() : - queryStart(rec.getMateReferenceName(), rec.getMateAlignmentStart())) { + rec.getMateReferenceIndex() == SAMRecord.NO_ALIGNMENT_REFERENCE_INDEX + ? queryUnmapped() + : queryStart(rec.getMateReferenceName(), rec.getMateAlignmentStart())) { SAMRecord mateRec = null; while (it.hasNext()) { final SAMRecord next = it.next(); if (!next.getReadPairedFlag()) { if (rec.getReadName().equals(next.getReadName())) { - throw new SAMFormatException(String.format("Paired and unpaired reads with same name: %s (on %s)", - rec.getReadName(), - getInputBundle())); + throw new SAMFormatException(String.format( + "Paired and unpaired reads with same name: %s (on %s)", + rec.getReadName(), getInputBundle())); } continue; } @@ -157,11 +164,9 @@ public Optional queryMate(SAMRecord rec) { } if (rec.getReadName().equals(next.getReadName())) { if (mateRec != null) { - throw new SAMFormatException( - String.format("Multiple SAMRecord with read name %s for %s end on %s.", - rec.getReadName(), - (firstOfPair ? "second" : "first"), - getInputBundle())); + throw new SAMFormatException(String.format( + "Multiple SAMRecord with read name %s for %s end on %s.", + rec.getReadName(), (firstOfPair ? "second" : "first"), getInputBundle())); } mateRec = next; } @@ -190,7 +195,7 @@ public ReadsDecoderOptions getReadsDecoderOptions() { // TODO: If we've been handed a CRAMReferenceSource from the caller, then we don't want to close it // when the decoder is closed, but if we create it, then we need to close it. - //TODO: creation of the source should be separate from the getting of the source, and the result + // TODO: creation of the source should be separate from the getting of the source, and the result // cached, so we don't create multiple reference Sources @InternalAPI public static CRAMReferenceSource getCRAMReferenceSource(final CRAMDecoderOptions cramDecoderOptions) { @@ -199,7 +204,8 @@ public static CRAMReferenceSource getCRAMReferenceSource(final CRAMDecoderOption if (cramDecoderOptions.getReferenceSource().isPresent()) { return cramDecoderOptions.getReferenceSource().get(); } else if (cramDecoderOptions.getReferencePath().isPresent()) { - return CRAMCodec.getCRAMReferenceSource(cramDecoderOptions.getReferencePath().get()); + return CRAMCodec.getCRAMReferenceSource( + cramDecoderOptions.getReferencePath().get()); } // if none is specified, get the default "lazy" reference source that throws when queried, to allow // operations that don't require a reference @@ -220,7 +226,8 @@ private void toggleIteratorExists(final boolean newState) { "The previous iterator must be closed before starting a new iterator on %s", getDisplayName())); } else { // this indicates a problem with this codec - throw new IllegalStateException(String.format("No outstanding iterator exists for %s", getDisplayName())); + throw new IllegalStateException( + String.format("No outstanding iterator exists for %s", getDisplayName())); } } // reset the iterator monitor @@ -244,7 +251,9 @@ public void close() { } @Override - public boolean hasNext() { return wrappedIterator.hasNext(); } + public boolean hasNext() { + return wrappedIterator.hasNext(); + } @Override public T next() { @@ -255,8 +264,7 @@ public T next() { // Propagate all reads decoder options and all bam decoder options to either a SamReaderFactory // or a SamInputResource, and return the resulting SamReader private static SamReader getSamReaderForCRAM( - final Bundle inputBundle, - final ReadsDecoderOptions readsDecoderOptions) { + final Bundle inputBundle, final ReadsDecoderOptions readsDecoderOptions) { // note that some reads decoder options, such as cloud wrapper values, need to be propagated // to the samInputResource, not to the SamReaderFactory final SamInputResource samInputResource = @@ -269,11 +277,9 @@ private static SamReader getSamReaderForCRAM( } private static void cramDecoderOptionsToSamReaderFactory( - final SamReaderFactory samReaderFactory, - final CRAMDecoderOptions cramDecoderOptions) { - //TODO: CRAMFileReader doesn't honor the requested inflater, but it should - //samReaderFactory.inflaterFactory(cramDecoderOptions.getInflaterFactory()); + final SamReaderFactory samReaderFactory, final CRAMDecoderOptions cramDecoderOptions) { + // TODO: CRAMFileReader doesn't honor the requested inflater, but it should + // samReaderFactory.inflaterFactory(cramDecoderOptions.getInflaterFactory()); samReaderFactory.referenceSource(getCRAMReferenceSource(cramDecoderOptions)); } - } diff --git a/src/main/java/htsjdk/beta/codecs/reads/cram/CRAMDecoderOptions.java b/src/main/java/htsjdk/beta/codecs/reads/cram/CRAMDecoderOptions.java index 798ef70181..b989330a65 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/cram/CRAMDecoderOptions.java +++ b/src/main/java/htsjdk/beta/codecs/reads/cram/CRAMDecoderOptions.java @@ -2,7 +2,6 @@ import htsjdk.io.IOPath; import htsjdk.samtools.cram.ref.CRAMReferenceSource; - import java.util.Optional; /** @@ -32,8 +31,8 @@ public Optional getReferenceSource() { public CRAMDecoderOptions setReferenceSource(final CRAMReferenceSource referenceSource) { if (referencePath != null) { throw new IllegalStateException(String.format( - "Reference source and reference path are mutually exclusive. Reference path already has value %s.", - referencePath.getRawInputString())); + "Reference source and reference path are mutually exclusive. Reference path already has value %s.", + referencePath.getRawInputString())); } this.referencePath = null; this.referenceSource = referenceSource; @@ -67,5 +66,4 @@ public CRAMDecoderOptions setReferencePath(final IOPath referencePath) { this.referencePath = referencePath; return this; } - } diff --git a/src/main/java/htsjdk/beta/codecs/reads/cram/CRAMEncoder.java b/src/main/java/htsjdk/beta/codecs/reads/cram/CRAMEncoder.java index 7a4f6caa58..5e7581fdc2 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/cram/CRAMEncoder.java +++ b/src/main/java/htsjdk/beta/codecs/reads/cram/CRAMEncoder.java @@ -1,21 +1,20 @@ package htsjdk.beta.codecs.reads.cram; +import htsjdk.annotations.InternalAPI; import htsjdk.beta.exception.HtsjdkUnsupportedOperationException; import htsjdk.beta.io.bundle.Bundle; import htsjdk.beta.io.bundle.BundleResource; import htsjdk.beta.io.bundle.BundleResourceType; +import htsjdk.beta.plugin.reads.ReadsEncoder; import htsjdk.beta.plugin.reads.ReadsEncoderOptions; import htsjdk.beta.plugin.reads.ReadsFormats; -import htsjdk.beta.plugin.reads.ReadsEncoder; import htsjdk.samtools.CRAMFileWriter; import htsjdk.samtools.SAMFileHeader; import htsjdk.samtools.SAMFileWriterFactory; import htsjdk.samtools.SAMRecord; import htsjdk.samtools.cram.ref.CRAMReferenceSource; import htsjdk.samtools.cram.ref.ReferenceSource; -import htsjdk.annotations.InternalAPI; import htsjdk.utils.ValidationUtils; - import java.util.Optional; /** @@ -47,14 +46,19 @@ public CRAMEncoder(final Bundle outputBundle, final ReadsEncoderOptions readsEnc this.outputBundle = outputBundle; this.readsEncoderOptions = readsEncoderOptions; - this.displayName = outputBundle.getOrThrow(BundleResourceType.CT_ALIGNED_READS).getDisplayName(); + this.displayName = + outputBundle.getOrThrow(BundleResourceType.CT_ALIGNED_READS).getDisplayName(); } @Override - final public String getFileFormat() { return ReadsFormats.CRAM; } + public final String getFileFormat() { + return ReadsFormats.CRAM; + } @Override - final public String getDisplayName() { return displayName; } + public final String getDisplayName() { + return displayName; + } @Override public void setHeader(final SAMFileHeader samFileHeader) { @@ -116,7 +120,8 @@ public static CRAMReferenceSource getCRAMReferenceSource(final CRAMEncoderOption if (cramEncoderOptions.getReferenceSource().isPresent()) { return cramEncoderOptions.getReferenceSource().get(); } else if (cramEncoderOptions.getReferencePath().isPresent()) { - return CRAMCodec.getCRAMReferenceSource(cramEncoderOptions.getReferencePath().get()); + return CRAMCodec.getCRAMReferenceSource( + cramEncoderOptions.getReferencePath().get()); } // if none is specified, get the default "lazy" reference source that throws when queried, to allow @@ -124,7 +129,8 @@ public static CRAMReferenceSource getCRAMReferenceSource(final CRAMEncoderOption return ReferenceSource.getDefaultCRAMReferenceSource(); } - private CRAMFileWriter getCRAMWriter(final SAMFileHeader samFileHeader, final ReadsEncoderOptions readsEncoderOptions) { + private CRAMFileWriter getCRAMWriter( + final SAMFileHeader samFileHeader, final ReadsEncoderOptions readsEncoderOptions) { // the CRAMFileWriter constructors assume presorted; so if we're presorted, use the CRAMFileWriters // directly so we can support writing to a stream if (readsEncoderOptions.isPreSorted()) { @@ -153,18 +159,19 @@ private CRAMFileWriter getCRAMWriter(final SAMFileHeader samFileHeader, final Re final Optional optIndexResource = getOutputBundle().get(BundleResourceType.CT_READS_INDEX); final Optional optMD5Resource = getOutputBundle().get(BundleResourceType.CT_MD5); - //TODO: SamFileWriterFactory code paths currently only support writing an index to a plain file, so + // TODO: SamFileWriterFactory code paths currently only support writing an index to a plain file, so // for now throw if an index is requested on any other type if (optIndexResource.isPresent()) { final BundleResource indexResource = optIndexResource.get(); if (indexResource.getIOPath().isPresent()) { samFileWriterFactory.setCreateIndex(true); } else { - throw new HtsjdkUnsupportedOperationException("Writing a CRAM index to a stream is not yet supported"); + throw new HtsjdkUnsupportedOperationException( + "Writing a CRAM index to a stream is not yet supported"); } } - //TODO: CRAMFileWriter currently only supports writing an md5 to a plain file with a name that + // TODO: CRAMFileWriter currently only supports writing an md5 to a plain file with a name that // it chooses, so throw if an md5 resource is specified since we can't direct it to the specified // resource if (optMD5Resource.isPresent()) { @@ -187,5 +194,4 @@ private CRAMFileWriter getCRAMWriter(final SAMFileHeader samFileHeader, final Re } } } - } diff --git a/src/main/java/htsjdk/beta/codecs/reads/cram/CRAMEncoderOptions.java b/src/main/java/htsjdk/beta/codecs/reads/cram/CRAMEncoderOptions.java index a64bae5c4b..3a7b1d4e30 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/cram/CRAMEncoderOptions.java +++ b/src/main/java/htsjdk/beta/codecs/reads/cram/CRAMEncoderOptions.java @@ -2,8 +2,6 @@ import htsjdk.io.IOPath; import htsjdk.samtools.cram.ref.CRAMReferenceSource; -import htsjdk.utils.ValidationUtils; - import java.util.Optional; /** @@ -68,5 +66,4 @@ public CRAMEncoderOptions setReferencePath(final IOPath referencePath) { this.referencePath = referencePath; return this; } - } diff --git a/src/main/java/htsjdk/beta/codecs/reads/cram/cramV2_1/CRAMCodecV2_1.java b/src/main/java/htsjdk/beta/codecs/reads/cram/cramV2_1/CRAMCodecV2_1.java index a3b4a8c5ef..a53c3faa6a 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/cram/cramV2_1/CRAMCodecV2_1.java +++ b/src/main/java/htsjdk/beta/codecs/reads/cram/cramV2_1/CRAMCodecV2_1.java @@ -3,8 +3,8 @@ import htsjdk.beta.codecs.reads.cram.CRAMCodec; import htsjdk.beta.codecs.reads.cram.CRAMDecoder; import htsjdk.beta.codecs.reads.cram.CRAMEncoder; -import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.io.bundle.Bundle; +import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.reads.ReadsDecoderOptions; import htsjdk.beta.plugin.reads.ReadsEncoderOptions; import htsjdk.samtools.cram.structure.CramHeader; @@ -44,6 +44,7 @@ public CRAMEncoder getEncoder(final Bundle outputBundle, final ReadsEncoderOptio } @Override - protected String getSignatureString() { return CRAM_MAGIC_2_1; } - + protected String getSignatureString() { + return CRAM_MAGIC_2_1; + } } diff --git a/src/main/java/htsjdk/beta/codecs/reads/cram/cramV2_1/CRAMDecoderV2_1.java b/src/main/java/htsjdk/beta/codecs/reads/cram/cramV2_1/CRAMDecoderV2_1.java index c91d381208..2b29ff3b32 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/cram/cramV2_1/CRAMDecoderV2_1.java +++ b/src/main/java/htsjdk/beta/codecs/reads/cram/cramV2_1/CRAMDecoderV2_1.java @@ -1,9 +1,9 @@ package htsjdk.beta.codecs.reads.cram.cramV2_1; import htsjdk.beta.codecs.reads.cram.CRAMDecoder; -import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.io.bundle.Bundle; import htsjdk.beta.io.bundle.BundleResourceType; +import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.reads.ReadsDecoderOptions; /** @@ -27,5 +27,4 @@ public CRAMDecoderV2_1(final Bundle bundle, final ReadsDecoderOptions readsDecod public HtsVersion getVersion() { return CRAMCodecV2_1.VERSION_2_1; } - } diff --git a/src/main/java/htsjdk/beta/codecs/reads/cram/cramV2_1/CRAMEncoderV2_1.java b/src/main/java/htsjdk/beta/codecs/reads/cram/cramV2_1/CRAMEncoderV2_1.java index bae7c8a87b..57c57c8b2c 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/cram/cramV2_1/CRAMEncoderV2_1.java +++ b/src/main/java/htsjdk/beta/codecs/reads/cram/cramV2_1/CRAMEncoderV2_1.java @@ -1,9 +1,9 @@ package htsjdk.beta.codecs.reads.cram.cramV2_1; import htsjdk.beta.codecs.reads.cram.CRAMEncoder; -import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.io.bundle.Bundle; import htsjdk.beta.io.bundle.BundleResourceType; +import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.reads.ReadsEncoderOptions; /** @@ -27,5 +27,4 @@ public CRAMEncoderV2_1(final Bundle outputBundle, final ReadsEncoderOptions read public HtsVersion getVersion() { return CRAMCodecV2_1.VERSION_2_1; } - } diff --git a/src/main/java/htsjdk/beta/codecs/reads/cram/cramV3_0/CRAMCodecV3_0.java b/src/main/java/htsjdk/beta/codecs/reads/cram/cramV3_0/CRAMCodecV3_0.java index bcb4fba356..d907cdb668 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/cram/cramV3_0/CRAMCodecV3_0.java +++ b/src/main/java/htsjdk/beta/codecs/reads/cram/cramV3_0/CRAMCodecV3_0.java @@ -3,14 +3,13 @@ import htsjdk.beta.codecs.reads.cram.CRAMCodec; import htsjdk.beta.codecs.reads.cram.CRAMDecoder; import htsjdk.beta.codecs.reads.cram.CRAMEncoder; +import htsjdk.beta.exception.HtsjdkIOException; import htsjdk.beta.io.bundle.Bundle; import htsjdk.beta.io.bundle.SignatureStream; -import htsjdk.beta.exception.HtsjdkIOException; import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.reads.ReadsDecoderOptions; import htsjdk.beta.plugin.reads.ReadsEncoderOptions; import htsjdk.samtools.cram.structure.CramHeader; - import java.io.IOException; import java.util.Arrays; @@ -56,6 +55,7 @@ public CRAMEncoder getEncoder(final Bundle outputBundle, final ReadsEncoderOptio } @Override - protected String getSignatureString() { return CRAM_MAGIC_3_0; } - + protected String getSignatureString() { + return CRAM_MAGIC_3_0; + } } diff --git a/src/main/java/htsjdk/beta/codecs/reads/cram/cramV3_0/CRAMDecoderV3_0.java b/src/main/java/htsjdk/beta/codecs/reads/cram/cramV3_0/CRAMDecoderV3_0.java index ff86467844..ebc57bce3a 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/cram/cramV3_0/CRAMDecoderV3_0.java +++ b/src/main/java/htsjdk/beta/codecs/reads/cram/cramV3_0/CRAMDecoderV3_0.java @@ -27,5 +27,4 @@ public CRAMDecoderV3_0(final Bundle bundle, final ReadsDecoderOptions readsDecod public HtsVersion getVersion() { return CRAMCodecV3_0.VERSION_3_0; } - } diff --git a/src/main/java/htsjdk/beta/codecs/reads/cram/cramV3_0/CRAMEncoderV3_0.java b/src/main/java/htsjdk/beta/codecs/reads/cram/cramV3_0/CRAMEncoderV3_0.java index 19dfade893..cbb6639ddd 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/cram/cramV3_0/CRAMEncoderV3_0.java +++ b/src/main/java/htsjdk/beta/codecs/reads/cram/cramV3_0/CRAMEncoderV3_0.java @@ -27,5 +27,4 @@ public CRAMEncoderV3_0(final Bundle outputBundle, final ReadsEncoderOptions read public HtsVersion getVersion() { return CRAMCodecV3_0.VERSION_3_0; } - } diff --git a/src/main/java/htsjdk/beta/codecs/reads/cram/cramV3_1/CRAMCodecV3_1.java b/src/main/java/htsjdk/beta/codecs/reads/cram/cramV3_1/CRAMCodecV3_1.java index 5f0606d069..e221188015 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/cram/cramV3_1/CRAMCodecV3_1.java +++ b/src/main/java/htsjdk/beta/codecs/reads/cram/cramV3_1/CRAMCodecV3_1.java @@ -10,7 +10,6 @@ import htsjdk.beta.plugin.reads.ReadsDecoderOptions; import htsjdk.beta.plugin.reads.ReadsEncoderOptions; import htsjdk.samtools.cram.structure.CramHeader; - import java.io.IOException; import java.util.Arrays; @@ -56,6 +55,7 @@ public CRAMEncoder getEncoder(final Bundle outputBundle, final ReadsEncoderOptio } @Override - protected String getSignatureString() { return CRAM_MAGIC_3_1; } - + protected String getSignatureString() { + return CRAM_MAGIC_3_1; + } } diff --git a/src/main/java/htsjdk/beta/codecs/reads/cram/cramV3_1/CRAMDecoderV3_1.java b/src/main/java/htsjdk/beta/codecs/reads/cram/cramV3_1/CRAMDecoderV3_1.java index ccfd90a141..895589dab5 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/cram/cramV3_1/CRAMDecoderV3_1.java +++ b/src/main/java/htsjdk/beta/codecs/reads/cram/cramV3_1/CRAMDecoderV3_1.java @@ -27,5 +27,4 @@ public CRAMDecoderV3_1(final Bundle bundle, final ReadsDecoderOptions readsDecod public HtsVersion getVersion() { return CRAMCodecV3_1.VERSION_3_1; } - } diff --git a/src/main/java/htsjdk/beta/codecs/reads/cram/cramV3_1/CRAMEncoderV3_1.java b/src/main/java/htsjdk/beta/codecs/reads/cram/cramV3_1/CRAMEncoderV3_1.java index 4ae82e91e1..0d2618fc2e 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/cram/cramV3_1/CRAMEncoderV3_1.java +++ b/src/main/java/htsjdk/beta/codecs/reads/cram/cramV3_1/CRAMEncoderV3_1.java @@ -5,7 +5,6 @@ import htsjdk.beta.io.bundle.BundleResourceType; import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.reads.ReadsEncoderOptions; -import htsjdk.samtools.cram.CRAMException; /** * CRAM v3.1 encoder. @@ -28,5 +27,4 @@ public CRAMEncoderV3_1(final Bundle outputBundle, final ReadsEncoderOptions read public HtsVersion getVersion() { return CRAMCodecV3_1.VERSION_3_1; } - } diff --git a/src/main/java/htsjdk/beta/codecs/reads/htsget/HtsgetBAMCodec.java b/src/main/java/htsjdk/beta/codecs/reads/htsget/HtsgetBAMCodec.java index c8adccbf7a..f2934f1579 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/htsget/HtsgetBAMCodec.java +++ b/src/main/java/htsjdk/beta/codecs/reads/htsget/HtsgetBAMCodec.java @@ -10,12 +10,10 @@ import htsjdk.samtools.util.FileExtensions; import htsjdk.samtools.util.htsget.HtsgetFormat; import htsjdk.samtools.util.htsget.HtsgetRequest; - import java.util.Arrays; import java.util.HashSet; import java.util.Set; - /** * Base class for concrete implementations of reads codecs that handle * {@link BundleResourceType#FMT_READS_HTSGET_BAM} codecs. @@ -31,10 +29,14 @@ public abstract class HtsgetBAMCodec implements ReadsCodec { /** * The HtsGet protocol doesn't seem to have a version number ? */ - public HtsVersion getVersion() { return HTSGET_VERSION; } + public HtsVersion getVersion() { + return HTSGET_VERSION; + } @Override - public String getFileFormat() { return ReadsFormats.HTSGET_BAM; } + public String getFileFormat() { + return ReadsFormats.HTSGET_BAM; + } @Override public int getSignatureLength() { @@ -48,25 +50,26 @@ public boolean ownsURI(final IOPath ioPath) { private boolean matchesScheme(final IOPath ioPath) { final String scheme = ioPath.getScheme(); - return scheme.equals(HtsgetBAMFileReader.HTSGET_SCHEME) || - scheme.equals("https") || - scheme.equals("http"); + return scheme.equals(HtsgetBAMFileReader.HTSGET_SCHEME) || scheme.equals("https") || scheme.equals("http"); } public boolean handlesURI(final IOPath ioPath) { - final boolean hasExtension = extensionMap.stream().anyMatch(ext-> ioPath.hasExtension(ext)); + final boolean hasExtension = extensionMap.stream().anyMatch(ext -> ioPath.hasExtension(ext)); final boolean hasScheme = matchesScheme(ioPath); - //TODO: does this check for "/reads/" at the start of the path ? should it ? + // TODO: does this check for "/reads/" at the start of the path ? should it ? final HtsgetRequest htsgetRequest = new HtsgetRequest(ioPath.getURI()); // no format == default == BAM - final boolean matchesRequestType = htsgetRequest.getFormat() == null || htsgetRequest.getFormat() == HtsgetFormat.BAM; + final boolean matchesRequestType = + htsgetRequest.getFormat() == null || htsgetRequest.getFormat() == HtsgetFormat.BAM; return hasExtension && hasScheme && matchesRequestType; } @Override - public boolean canDecodeURI(final IOPath ioPath) { return handlesURI(ioPath); } + public boolean canDecodeURI(final IOPath ioPath) { + return handlesURI(ioPath); + } @Override public boolean canDecodeSignature(final SignatureStream probingInputStream, final String sourceName) { @@ -74,11 +77,13 @@ public boolean canDecodeSignature(final SignatureStream probingInputStream, fina } boolean isQueryable() { - //is this correct ?? + // is this correct ?? return true; } - boolean hasIndex() { return false; } + boolean hasIndex() { + return false; + } @Override public boolean runVersionUpgrade(final HtsVersion sourceCodecVersion, final HtsVersion targetCodecVersion) { diff --git a/src/main/java/htsjdk/beta/codecs/reads/htsget/HtsgetBAMDecoder.java b/src/main/java/htsjdk/beta/codecs/reads/htsget/HtsgetBAMDecoder.java index 59bc35e6a1..ebb71992f9 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/htsget/HtsgetBAMDecoder.java +++ b/src/main/java/htsjdk/beta/codecs/reads/htsget/HtsgetBAMDecoder.java @@ -19,11 +19,14 @@ public abstract class HtsgetBAMDecoder implements ReadsDecoder { public HtsgetBAMDecoder(final Bundle inputBundle, final ReadsDecoderOptions readsDecoderOptions) { this.inputBundle = inputBundle; this.readsDecoderOptions = readsDecoderOptions; - this.displayName = inputBundle.getOrThrow(BundleResourceType.CT_ALIGNED_READS).getDisplayName(); + this.displayName = + inputBundle.getOrThrow(BundleResourceType.CT_ALIGNED_READS).getDisplayName(); } @Override - public String getFileFormat() { return ReadsFormats.HTSGET_BAM; } + public String getFileFormat() { + return ReadsFormats.HTSGET_BAM; + } @Override public HtsVersion getVersion() { @@ -31,7 +34,9 @@ public HtsVersion getVersion() { } @Override - final public String getDisplayName() { return displayName; } + public final String getDisplayName() { + return displayName; + } /** * Get the input {@link Bundle} for this decoder. diff --git a/src/main/java/htsjdk/beta/codecs/reads/htsget/htsgetBAMV1_2/HtsgetBAMCodecV1_2.java b/src/main/java/htsjdk/beta/codecs/reads/htsget/htsgetBAMV1_2/HtsgetBAMCodecV1_2.java index 2a870beab7..4560d9c8ee 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/htsget/htsgetBAMV1_2/HtsgetBAMCodecV1_2.java +++ b/src/main/java/htsjdk/beta/codecs/reads/htsget/htsgetBAMV1_2/HtsgetBAMCodecV1_2.java @@ -2,15 +2,14 @@ import htsjdk.beta.codecs.reads.htsget.HtsgetBAMCodec; import htsjdk.beta.codecs.reads.htsget.HtsgetBAMDecoder; -import htsjdk.beta.plugin.HtsEncoder; -import htsjdk.beta.plugin.HtsRecord; import htsjdk.beta.io.bundle.Bundle; import htsjdk.beta.io.bundle.BundleResource; import htsjdk.beta.io.bundle.BundleResourceType; -import htsjdk.io.IOPath; -import htsjdk.beta.plugin.reads.ReadsEncoderOptions; +import htsjdk.beta.plugin.HtsEncoder; +import htsjdk.beta.plugin.HtsRecord; import htsjdk.beta.plugin.reads.ReadsDecoderOptions; - +import htsjdk.beta.plugin.reads.ReadsEncoderOptions; +import htsjdk.io.IOPath; import java.util.Optional; /** @@ -19,8 +18,7 @@ public class HtsgetBAMCodecV1_2 extends HtsgetBAMCodec { @Override - public HtsgetBAMDecoder getDecoder(final Bundle inputBundle, - final ReadsDecoderOptions decodeOptions) { + public HtsgetBAMDecoder getDecoder(final Bundle inputBundle, final ReadsDecoderOptions decodeOptions) { final BundleResource readsResource = inputBundle.getOrThrow(BundleResourceType.CT_ALIGNED_READS); final Optional inputPath = readsResource.getIOPath(); if (!inputPath.isPresent()) { @@ -33,5 +31,4 @@ public HtsgetBAMDecoder getDecoder(final Bundle inputBundle, public HtsEncoder getEncoder(Bundle outputBundle, ReadsEncoderOptions encodeOptions) { throw new IllegalArgumentException("Htsget is read only - no Htsget BAM encoder component is available."); } - } diff --git a/src/main/java/htsjdk/beta/codecs/reads/htsget/htsgetBAMV1_2/HtsgetBAMDecoderV1_2.java b/src/main/java/htsjdk/beta/codecs/reads/htsget/htsgetBAMV1_2/HtsgetBAMDecoderV1_2.java index e3593ea5f1..3bb51eff7a 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/htsget/htsgetBAMV1_2/HtsgetBAMDecoderV1_2.java +++ b/src/main/java/htsjdk/beta/codecs/reads/htsget/htsgetBAMV1_2/HtsgetBAMDecoderV1_2.java @@ -1,6 +1,8 @@ package htsjdk.beta.codecs.reads.htsget.htsgetBAMV1_2; import htsjdk.beta.codecs.reads.htsget.HtsgetBAMDecoder; +import htsjdk.beta.exception.HtsjdkIOException; +import htsjdk.beta.exception.HtsjdkUnsupportedOperationException; import htsjdk.beta.io.bundle.Bundle; import htsjdk.beta.io.bundle.BundleResource; import htsjdk.beta.io.bundle.BundleResourceType; @@ -8,15 +10,12 @@ import htsjdk.beta.plugin.interval.HtsIntervalUtils; import htsjdk.beta.plugin.interval.HtsQueryRule; import htsjdk.beta.plugin.reads.ReadsDecoderOptions; -import htsjdk.beta.exception.HtsjdkIOException; -import htsjdk.beta.exception.HtsjdkUnsupportedOperationException; import htsjdk.samtools.DefaultSAMRecordFactory; import htsjdk.samtools.HtsgetBAMFileReader; import htsjdk.samtools.SAMFileHeader; import htsjdk.samtools.SAMRecord; import htsjdk.samtools.ValidationStringency; import htsjdk.samtools.util.CloseableIterator; - import java.io.IOException; import java.util.List; import java.util.Optional; @@ -45,7 +44,10 @@ public HtsgetBAMDecoderV1_2(final Bundle inputBundle, final ReadsDecoderOptions false); } catch (IOException e) { throw new HtsjdkIOException( - String.format("Failure opening Htsget reader on %s", readsResource.getIOPath().get()), e); + String.format( + "Failure opening Htsget reader on %s", + readsResource.getIOPath().get()), + e); } } @@ -84,8 +86,7 @@ public CloseableIterator query(final String queryString) { @Override public CloseableIterator query(final List intervals, final HtsQueryRule queryRule) { return htsgetReader.query( - HtsIntervalUtils.toLocatableList(intervals), - (queryRule == HtsQueryRule.CONTAINED) == true); + HtsIntervalUtils.toLocatableList(intervals), (queryRule == HtsQueryRule.CONTAINED) == true); } @Override @@ -100,7 +101,7 @@ public CloseableIterator queryUnmapped() { @Override public Optional queryMate(final SAMRecord rec) { - //reader doesn't support this + // reader doesn't support this throw new HtsjdkUnsupportedOperationException("queryMate not implemented for htsget BAM reader"); } } diff --git a/src/main/java/htsjdk/beta/codecs/reads/sam/SAMCodec.java b/src/main/java/htsjdk/beta/codecs/reads/sam/SAMCodec.java index 7e88ddac2b..580c5d9a47 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/sam/SAMCodec.java +++ b/src/main/java/htsjdk/beta/codecs/reads/sam/SAMCodec.java @@ -1,14 +1,13 @@ package htsjdk.beta.codecs.reads.sam; +import htsjdk.annotations.InternalAPI; import htsjdk.beta.exception.HtsjdkIOException; import htsjdk.beta.io.bundle.BundleResourceType; import htsjdk.beta.io.bundle.SignatureStream; import htsjdk.beta.plugin.reads.ReadsCodec; import htsjdk.beta.plugin.reads.ReadsFormats; import htsjdk.io.IOPath; -import htsjdk.annotations.InternalAPI; import htsjdk.utils.ValidationUtils; - import java.io.IOException; import java.util.Arrays; @@ -23,7 +22,9 @@ public abstract class SAMCodec implements ReadsCodec { private static String SAM_EXTENSION = ".sam"; @Override - public String getFileFormat() { return ReadsFormats.SAM; } + public String getFileFormat() { + return ReadsFormats.SAM; + } @Override public String getDisplayName() { @@ -31,7 +32,9 @@ public String getDisplayName() { } @Override - public boolean ownsURI(IOPath ioPath) { return false; } + public boolean ownsURI(IOPath ioPath) { + return false; + } @Override public boolean canDecodeURI(IOPath ioPath) { @@ -53,11 +56,12 @@ public boolean canDecodeSignature(final SignatureStream probingInputStream, fina } @Override - public int getSignatureProbeLength() { return SAM_HEADER_SENTINEL.length(); } + public int getSignatureProbeLength() { + return SAM_HEADER_SENTINEL.length(); + } @Override public int getSignatureLength() { return SAM_HEADER_SENTINEL.length(); } - } diff --git a/src/main/java/htsjdk/beta/codecs/reads/sam/SAMDecoder.java b/src/main/java/htsjdk/beta/codecs/reads/sam/SAMDecoder.java index 32aca0067c..411de1f397 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/sam/SAMDecoder.java +++ b/src/main/java/htsjdk/beta/codecs/reads/sam/SAMDecoder.java @@ -1,11 +1,11 @@ package htsjdk.beta.codecs.reads.sam; +import htsjdk.annotations.InternalAPI; import htsjdk.beta.io.bundle.Bundle; import htsjdk.beta.io.bundle.BundleResourceType; import htsjdk.beta.plugin.reads.ReadsDecoder; import htsjdk.beta.plugin.reads.ReadsDecoderOptions; import htsjdk.beta.plugin.reads.ReadsFormats; -import htsjdk.annotations.InternalAPI; import htsjdk.utils.ValidationUtils; /** @@ -30,18 +30,23 @@ public abstract class SAMDecoder implements ReadsDecoder { */ @InternalAPI public SAMDecoder(final Bundle inputBundle, final ReadsDecoderOptions readsDecoderOptions) { - ValidationUtils.nonNull(inputBundle,"inputBundle"); + ValidationUtils.nonNull(inputBundle, "inputBundle"); ValidationUtils.nonNull(readsDecoderOptions, "readsDecoderOptions"); this.inputBundle = inputBundle; - this.displayName = inputBundle.getOrThrow(BundleResourceType.CT_ALIGNED_READS).getDisplayName(); + this.displayName = + inputBundle.getOrThrow(BundleResourceType.CT_ALIGNED_READS).getDisplayName(); this.readsDecoderOptions = readsDecoderOptions; } @Override - final public String getFileFormat() { return ReadsFormats.SAM; } + public final String getFileFormat() { + return ReadsFormats.SAM; + } @Override - final public String getDisplayName() { return displayName; } + public final String getDisplayName() { + return displayName; + } /** * Get the input {@link Bundle} for this decoder. diff --git a/src/main/java/htsjdk/beta/codecs/reads/sam/SAMEncoder.java b/src/main/java/htsjdk/beta/codecs/reads/sam/SAMEncoder.java index 2eda3fcf69..d0bea8bc59 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/sam/SAMEncoder.java +++ b/src/main/java/htsjdk/beta/codecs/reads/sam/SAMEncoder.java @@ -32,14 +32,19 @@ public abstract class SAMEncoder implements ReadsEncoder { public SAMEncoder(final Bundle outputBundle, final ReadsEncoderOptions readsEncoderOptions) { this.outputBundle = outputBundle; this.readsEncoderOptions = readsEncoderOptions; - this.displayName = outputBundle.getOrThrow(BundleResourceType.CT_ALIGNED_READS).getDisplayName(); + this.displayName = + outputBundle.getOrThrow(BundleResourceType.CT_ALIGNED_READS).getDisplayName(); } @Override - final public String getFileFormat() { return ReadsFormats.SAM; } + public final String getFileFormat() { + return ReadsFormats.SAM; + } @Override - final public String getDisplayName() { return displayName; } + public final String getDisplayName() { + return displayName; + } /** * Get the output {@link Bundle} for this encoder. @@ -58,5 +63,4 @@ public Bundle getOutputBundle() { public ReadsEncoderOptions getReadsEncoderOptions() { return readsEncoderOptions; } - } diff --git a/src/main/java/htsjdk/beta/codecs/reads/sam/samV1_0/SAMCodecV1_0.java b/src/main/java/htsjdk/beta/codecs/reads/sam/samV1_0/SAMCodecV1_0.java index e858734f66..5ef9849858 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/sam/samV1_0/SAMCodecV1_0.java +++ b/src/main/java/htsjdk/beta/codecs/reads/sam/samV1_0/SAMCodecV1_0.java @@ -4,8 +4,8 @@ import htsjdk.beta.codecs.reads.sam.SAMDecoder; import htsjdk.beta.codecs.reads.sam.SAMEncoder; import htsjdk.beta.exception.HtsjdkUnsupportedOperationException; -import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.io.bundle.Bundle; +import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.reads.ReadsDecoderOptions; import htsjdk.beta.plugin.reads.ReadsEncoderOptions; @@ -16,7 +16,9 @@ public class SAMCodecV1_0 extends SAMCodec { public static final HtsVersion VERSION_1 = new HtsVersion(1, 0, 0); @Override - public HtsVersion getVersion() { return VERSION_1; } + public HtsVersion getVersion() { + return VERSION_1; + } @Override public SAMDecoder getDecoder(final Bundle inputBundle, final ReadsDecoderOptions decoderOptions) { @@ -32,5 +34,4 @@ public SAMEncoder getEncoder(final Bundle outputBundle, final ReadsEncoderOption public boolean runVersionUpgrade(final HtsVersion sourceCodecVersion, final HtsVersion targetCodecVersion) { throw new HtsjdkUnsupportedOperationException("Version upgrade not yet implemented"); } - } diff --git a/src/main/java/htsjdk/beta/codecs/reads/sam/samV1_0/SAMDecoderV1_0.java b/src/main/java/htsjdk/beta/codecs/reads/sam/samV1_0/SAMDecoderV1_0.java index 9fad68240b..e87e3e9d74 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/sam/samV1_0/SAMDecoderV1_0.java +++ b/src/main/java/htsjdk/beta/codecs/reads/sam/samV1_0/SAMDecoderV1_0.java @@ -3,16 +3,15 @@ import htsjdk.beta.codecs.reads.ReadsCodecUtils; import htsjdk.beta.codecs.reads.sam.SAMDecoder; import htsjdk.beta.exception.HtsjdkIOException; -import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.io.bundle.Bundle; import htsjdk.beta.io.bundle.BundleResourceType; +import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.reads.ReadsDecoderOptions; import htsjdk.samtools.SAMFileHeader; import htsjdk.samtools.SAMRecord; import htsjdk.samtools.SamReader; import htsjdk.samtools.SamReaderFactory; import htsjdk.samtools.util.CloseableIterator; - import java.io.IOException; import java.util.Optional; @@ -56,7 +55,9 @@ public CloseableIterator iterator() { } @Override - public boolean isQueryable() { return false; } + public boolean isQueryable() { + return false; + } @Override public boolean hasIndex() { diff --git a/src/main/java/htsjdk/beta/codecs/reads/sam/samV1_0/SAMEncoderV1_0.java b/src/main/java/htsjdk/beta/codecs/reads/sam/samV1_0/SAMEncoderV1_0.java index 0274a49d54..4b1f4e231e 100644 --- a/src/main/java/htsjdk/beta/codecs/reads/sam/samV1_0/SAMEncoderV1_0.java +++ b/src/main/java/htsjdk/beta/codecs/reads/sam/samV1_0/SAMEncoderV1_0.java @@ -1,18 +1,17 @@ package htsjdk.beta.codecs.reads.sam.samV1_0; +import htsjdk.annotations.InternalAPI; import htsjdk.beta.codecs.reads.sam.SAMEncoder; import htsjdk.beta.exception.HtsjdkUnsupportedOperationException; -import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.io.bundle.Bundle; import htsjdk.beta.io.bundle.BundleResource; import htsjdk.beta.io.bundle.BundleResourceType; +import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.reads.ReadsEncoderOptions; import htsjdk.samtools.SAMFileHeader; import htsjdk.samtools.SAMFileWriter; import htsjdk.samtools.SAMFileWriterFactory; import htsjdk.samtools.SAMRecord; -import htsjdk.annotations.InternalAPI; - import java.util.Optional; /** @@ -48,8 +47,7 @@ public void setHeader(final SAMFileHeader samFileHeader) { public void write(final SAMRecord record) { if (samFileWriter == null) { throw new IllegalStateException(String.format( - "A SAMFileHeader must be established before a SAM writer can be established %s", - getDisplayName())); + "A SAMFileHeader must be established before a SAM writer can be established %s", getDisplayName())); } samFileWriter.addAlignment(record); } @@ -62,8 +60,7 @@ public void close() { } private SAMFileWriter getSAMFileWriter( - final ReadsEncoderOptions readsEncoderOptions, - final SAMFileHeader samFileHeader) { + final ReadsEncoderOptions readsEncoderOptions, final SAMFileHeader samFileHeader) { final SAMFileWriterFactory samFileWriterFactory = new SAMFileWriterFactory(); final boolean preSorted = readsEncoderOptions.isPreSorted(); @@ -72,7 +69,7 @@ private SAMFileWriter getSAMFileWriter( final Optional optIndexResource = getOutputBundle().get(BundleResourceType.CT_READS_INDEX); final Optional optMD5Resource = getOutputBundle().get(BundleResourceType.CT_MD5); - //TODO: BAMFileWriter currently only supports writing an index to a plain file, so for now + // TODO: BAMFileWriter currently only supports writing an index to a plain file, so for now // throw if an index is requested on any other type if (optIndexResource.isPresent()) { final BundleResource indexResource = optIndexResource.get(); @@ -83,24 +80,20 @@ private SAMFileWriter getSAMFileWriter( } } - //TODO: BAMFileWriter currently only supports writing an md5 to a plain file with a name that + // TODO: BAMFileWriter currently only supports writing an md5 to a plain file with a name that // it chooses, so throw if an md5 resource is specified since we can't direct it to the specified // resource if (optMD5Resource.isPresent()) { - throw new HtsjdkUnsupportedOperationException(String.format( - "Specifying an an MD5 resource name not yet implemented on %s", getDisplayName())); + throw new HtsjdkUnsupportedOperationException( + String.format("Specifying an an MD5 resource name not yet implemented on %s", getDisplayName())); } if (readsResource.getIOPath().isPresent()) { return samFileWriterFactory.makeSAMWriter( - samFileHeader, - preSorted, - readsResource.getIOPath().get().toPath()); + samFileHeader, preSorted, readsResource.getIOPath().get().toPath()); } else { return samFileWriterFactory.makeSAMWriter( - samFileHeader, - preSorted, - readsResource.getOutputStream().get()); + samFileHeader, preSorted, readsResource.getOutputStream().get()); } } } diff --git a/src/main/java/htsjdk/beta/codecs/variants/vcf/VCFCodec.java b/src/main/java/htsjdk/beta/codecs/variants/vcf/VCFCodec.java index c18a60b34e..adc17f8689 100644 --- a/src/main/java/htsjdk/beta/codecs/variants/vcf/VCFCodec.java +++ b/src/main/java/htsjdk/beta/codecs/variants/vcf/VCFCodec.java @@ -1,17 +1,16 @@ package htsjdk.beta.codecs.variants.vcf; +import htsjdk.annotations.InternalAPI; import htsjdk.beta.exception.HtsjdkIOException; -import htsjdk.beta.plugin.HtsContentType; import htsjdk.beta.io.bundle.SignatureStream; -import htsjdk.io.IOPath; +import htsjdk.beta.plugin.HtsContentType; import htsjdk.beta.plugin.variants.VariantsCodec; import htsjdk.beta.plugin.variants.VariantsFormats; +import htsjdk.io.IOPath; import htsjdk.samtools.util.BlockCompressedStreamConstants; import htsjdk.samtools.util.FileExtensions; import htsjdk.samtools.util.IOUtil; -import htsjdk.annotations.InternalAPI; import htsjdk.utils.ValidationUtils; - import java.io.IOException; import java.io.InputStream; import java.util.Arrays; @@ -29,6 +28,7 @@ public abstract class VCFCodec implements VariantsCodec { // FileExtensions.VCF_LIST includes BCF, which we don't want included here private static final Set extensionMap = new HashSet() { private static final long serialVersionUID = 1L; + { add(FileExtensions.VCF); add(FileExtensions.COMPRESSED_VCF); @@ -37,13 +37,15 @@ public abstract class VCFCodec implements VariantsCodec { }; @Override - public String getFileFormat() { return VariantsFormats.VCF; } + public String getFileFormat() { + return VariantsFormats.VCF; + } @Override public boolean canDecodeURI(final IOPath ioPath) { ValidationUtils.nonNull(ioPath, "ioPath"); - return extensionMap.stream().anyMatch(ext-> ioPath.hasExtension(ext)); + return extensionMap.stream().anyMatch(ext -> ioPath.hasExtension(ext)); } @Override @@ -52,7 +54,9 @@ public int getSignatureLength() { } @Override - public int getSignatureProbeLength() { return BlockCompressedStreamConstants.MAX_COMPRESSED_BLOCK_SIZE; } + public int getSignatureProbeLength() { + return BlockCompressedStreamConstants.MAX_COMPRESSED_BLOCK_SIZE; + } @Override public boolean canDecodeSignature(final SignatureStream probingInputStream, final String sourceName) { @@ -61,9 +65,9 @@ public boolean canDecodeSignature(final SignatureStream probingInputStream, fina final byte[] signatureBytes = new byte[getSignatureLength()]; try { - final InputStream wrappedInputStream = IOUtil.isGZIPInputStream(probingInputStream) ? - new GZIPInputStream(probingInputStream) : - probingInputStream; + final InputStream wrappedInputStream = IOUtil.isGZIPInputStream(probingInputStream) + ? new GZIPInputStream(probingInputStream) + : probingInputStream; final int numRead = wrappedInputStream.read(signatureBytes); if (numRead < 0) { throw new HtsjdkIOException(String.format("0 bytes read from input stream for %s", sourceName)); @@ -80,5 +84,4 @@ public boolean canDecodeSignature(final SignatureStream probingInputStream, fina * @return the signature string for this codec */ protected abstract String getSignatureString(); - } diff --git a/src/main/java/htsjdk/beta/codecs/variants/vcf/VCFDecoder.java b/src/main/java/htsjdk/beta/codecs/variants/vcf/VCFDecoder.java index 31674fa064..82e80e28a5 100644 --- a/src/main/java/htsjdk/beta/codecs/variants/vcf/VCFDecoder.java +++ b/src/main/java/htsjdk/beta/codecs/variants/vcf/VCFDecoder.java @@ -1,12 +1,13 @@ package htsjdk.beta.codecs.variants.vcf; +import htsjdk.annotations.InternalAPI; import htsjdk.beta.exception.HtsjdkException; import htsjdk.beta.exception.HtsjdkIOException; import htsjdk.beta.exception.HtsjdkUnsupportedOperationException; -import htsjdk.beta.plugin.HtsContentType; import htsjdk.beta.io.bundle.Bundle; import htsjdk.beta.io.bundle.BundleResource; import htsjdk.beta.io.bundle.BundleResourceType; +import htsjdk.beta.plugin.HtsContentType; import htsjdk.beta.plugin.interval.HtsInterval; import htsjdk.beta.plugin.interval.HtsIntervalUtils; import htsjdk.beta.plugin.interval.HtsQueryRule; @@ -19,17 +20,13 @@ import htsjdk.samtools.util.CloseableIterator; import htsjdk.tribble.AbstractFeatureReader; import htsjdk.tribble.FeatureReader; -import htsjdk.annotations.InternalAPI; import htsjdk.utils.ValidationUtils; import htsjdk.variant.variantcontext.VariantContext; import htsjdk.variant.vcf.AbstractVCFCodec; import htsjdk.variant.vcf.VCFHeader; - import java.io.IOException; -import java.nio.channels.SeekableByteChannel; import java.util.List; import java.util.Optional; -import java.util.function.Function; /** * InternalAPII @@ -65,16 +62,21 @@ public VCFDecoder( this.inputBundle = inputBundle; this.variantsDecoderOptions = variantsDecoderOptions; - this.displayName = inputBundle.getOrThrow(BundleResourceType.CT_VARIANT_CONTEXTS).getDisplayName(); + this.displayName = + inputBundle.getOrThrow(BundleResourceType.CT_VARIANT_CONTEXTS).getDisplayName(); vcfReader = getVCFReader(inputBundle, vcfCodec, variantsDecoderOptions); vcfHeader = (VCFHeader) vcfReader.getHeader(); } @Override - final public String getFileFormat() { return VariantsFormats.VCF; } + public final String getFileFormat() { + return VariantsFormats.VCF; + } @Override - final public String getDisplayName() { return displayName; } + public final String getDisplayName() { + return displayName; + } @Override public VCFHeader getHeader() { @@ -86,7 +88,8 @@ public CloseableIterator iterator() { try { return vcfReader.iterator(); } catch (IOException e) { - throw new HtsjdkIOException(String.format("Exception creating variant context iterator for %s", displayName), e); + throw new HtsjdkIOException( + String.format("Exception creating variant context iterator for %s", displayName), e); } } @@ -108,13 +111,15 @@ public CloseableIterator query(final List intervals VariantsCodecUtils.assertBundleContainsIndex(getInputBundle()); if (intervals.size() > 1) { - //TODO: implement lists, sorting, merging, and ensuring that features that overlap more than one interval + // TODO: implement lists, sorting, merging, and ensuring that features that overlap more than one interval // are only returned once - throw new HtsjdkUnsupportedOperationException(String.format("query for lists not yet implemented for decoder %s", displayName)); + throw new HtsjdkUnsupportedOperationException( + String.format("query for lists not yet implemented for decoder %s", displayName)); } if (queryRule != HtsQueryRule.OVERLAPPING) { - //TODO: implement overlapping - throw new HtsjdkUnsupportedOperationException(String.format("query for contained intervals not implemented for this decoder %s", displayName)); + // TODO: implement overlapping + throw new HtsjdkUnsupportedOperationException( + String.format("query for contained intervals not implemented for this decoder %s", displayName)); } try { @@ -140,19 +145,18 @@ public CloseableIterator queryStart(final String queryName, fina if (vcfHeader == null) { throw new HtsjdkException(String.format( - "A valid VCF header is required to execute a query, but is not present: %s.", - displayName)); + "A valid VCF header is required to execute a query, but is not present: %s.", displayName)); } final SAMSequenceDictionary seqDict = vcfHeader.getSequenceDictionary(); if (seqDict == null) { - throw new HtsjdkException(String.format("No sequence dictionary is present in the input: %s.", displayName)); + throw new HtsjdkException( + String.format("No sequence dictionary is present in the input: %s.", displayName)); } final SAMSequenceRecord samSequenceRecord = seqDict.getSequence(queryName); if (samSequenceRecord == null) { throw new HtsjdkException(String.format( "The query name %s is not present in the dictionary provided in the input: %s.", - queryName, - displayName)); + queryName, displayName)); } final int length = samSequenceRecord.getSequenceLength(); try { @@ -190,22 +194,19 @@ public VariantsDecoderOptions getReadsDecoderOptions() { } private static FeatureReader getVCFReader( - final Bundle inputBundle, - final AbstractVCFCodec vcfCodec, - final VariantsDecoderOptions decoderOptions) { + final Bundle inputBundle, final AbstractVCFCodec vcfCodec, final VariantsDecoderOptions decoderOptions) { final BundleResource variantsResource = inputBundle.getOrThrow(BundleResourceType.CT_VARIANT_CONTEXTS); if (!variantsResource.hasInputType()) { throw new IllegalArgumentException(String.format( "The provided %s resource (%s) must be a readable/input resource", - BundleResourceType.CT_VARIANT_CONTEXTS, - variantsResource)); + BundleResourceType.CT_VARIANT_CONTEXTS, variantsResource)); } else if (variantsResource.getIOPath().isEmpty()) { throw new HtsjdkUnsupportedOperationException("VCF reader from stream not implemented"); } final IOPath variantsIOPath = variantsResource.getIOPath().get(); final Optional indexIOPath = getIndexIOPath(inputBundle); - //TODO: this resolves the index automatically. it should check to make sure the provided index + // TODO: this resolves the index automatically. it should check to make sure the provided index // matches the one that is automatically resolved, otherwise throw since the request will not be honored return AbstractFeatureReader.getFeatureReader( variantsIOPath.getURIString(), @@ -213,8 +214,7 @@ private static FeatureReader getVCFReader( vcfCodec, indexIOPath.isPresent(), decoderOptions.getVariantsChannelTransformer().orElse(null), - decoderOptions.getIndexChannelTransformer().orElse(null) - ); + decoderOptions.getIndexChannelTransformer().orElse(null)); } // the underlying readers can't handle index streams, so for now we can only handle IOPaths @@ -226,14 +226,12 @@ private static Optional getIndexIOPath(final Bundle inputBundle) { final BundleResource indexResource = optIndexResource.get(); if (!indexResource.hasInputType()) { throw new IllegalArgumentException(String.format( - "The provided %s index resource (%s) must be a readable/input resource", - BundleResourceType.CT_VARIANTS_INDEX, - indexResource)); + "The provided %s index resource (%s) must be a readable/input resource", + BundleResourceType.CT_VARIANTS_INDEX, indexResource)); } if (indexResource.getIOPath().isEmpty()) { throw new HtsjdkUnsupportedOperationException("Reading a VCF index from a stream not implemented"); } return indexResource.getIOPath(); } - } diff --git a/src/main/java/htsjdk/beta/codecs/variants/vcf/VCFEncoder.java b/src/main/java/htsjdk/beta/codecs/variants/vcf/VCFEncoder.java index ab17269024..a30a40c29e 100644 --- a/src/main/java/htsjdk/beta/codecs/variants/vcf/VCFEncoder.java +++ b/src/main/java/htsjdk/beta/codecs/variants/vcf/VCFEncoder.java @@ -1,26 +1,24 @@ package htsjdk.beta.codecs.variants.vcf; +import htsjdk.annotations.InternalAPI; import htsjdk.beta.exception.HtsjdkPluginException; import htsjdk.beta.exception.HtsjdkUnsupportedOperationException; -import htsjdk.beta.plugin.HtsContentType; import htsjdk.beta.io.bundle.Bundle; import htsjdk.beta.io.bundle.BundleResource; import htsjdk.beta.io.bundle.BundleResourceType; +import htsjdk.beta.plugin.HtsContentType; import htsjdk.beta.plugin.variants.VariantsEncoder; import htsjdk.beta.plugin.variants.VariantsEncoderOptions; import htsjdk.beta.plugin.variants.VariantsFormats; import htsjdk.io.IOPath; -import htsjdk.annotations.InternalAPI; import htsjdk.utils.ValidationUtils; import htsjdk.variant.variantcontext.VariantContext; import htsjdk.variant.variantcontext.writer.Options; import htsjdk.variant.variantcontext.writer.VariantContextWriter; import htsjdk.variant.variantcontext.writer.VariantContextWriterBuilder; import htsjdk.variant.vcf.VCFHeader; - import java.util.Optional; - /** * InternalAPI * @@ -51,14 +49,19 @@ public VCFEncoder(final Bundle outputBundle, final VariantsEncoderOptions varian this.outputBundle = outputBundle; this.variantsEncoderOptions = variantsEncoderOptions; - this.displayName = outputBundle.getOrThrow(BundleResourceType.CT_VARIANT_CONTEXTS).getDisplayName(); + this.displayName = + outputBundle.getOrThrow(BundleResourceType.CT_VARIANT_CONTEXTS).getDisplayName(); } - @Override - final public String getFileFormat() { return VariantsFormats.VCF; } + @Override + public final String getFileFormat() { + return VariantsFormats.VCF; + } @Override - final public String getDisplayName() { return displayName; } + public final String getDisplayName() { + return displayName; + } @Override public void setHeader(final VCFHeader vcfHeader) { @@ -104,21 +107,17 @@ public VariantsEncoderOptions getVariantsEncoderOptions() { } private static VariantContextWriter getVCFWriter( - final Bundle outputBundle, - final VariantsEncoderOptions variantsEncoderOptions) { - final VariantContextWriterBuilder writerBuilder = - variantsEncoderOptionsToVariantContextWriterBuilder( - variantsEncoderOptions, - outputBundle.get(BundleResourceType.CT_VARIANTS_INDEX).isPresent() - ); + final Bundle outputBundle, final VariantsEncoderOptions variantsEncoderOptions) { + final VariantContextWriterBuilder writerBuilder = variantsEncoderOptionsToVariantContextWriterBuilder( + variantsEncoderOptions, + outputBundle.get(BundleResourceType.CT_VARIANTS_INDEX).isPresent()); setWriterBuilderOutputs(writerBuilder, outputBundle); return writerBuilder.build(); } // propagate VariantsEncoderOptions -> VariantContextWriterBuilder private static VariantContextWriterBuilder variantsEncoderOptionsToVariantContextWriterBuilder( - final VariantsEncoderOptions variantsEncoderOptions, - final boolean createIndex) { + final VariantsEncoderOptions variantsEncoderOptions, final boolean createIndex) { final VariantContextWriterBuilder vcWriterBuilder = new VariantContextWriterBuilder(); vcWriterBuilder.clearOptions(); @@ -152,21 +151,19 @@ private static VariantContextWriterBuilder variantsEncoderOptionsToVariantContex } private static void setWriterBuilderOutputs( - final VariantContextWriterBuilder writerBuilder, - final Bundle outputBundle) { + final VariantContextWriterBuilder writerBuilder, final Bundle outputBundle) { final BundleResource variantsResource = outputBundle.getOrThrow(BundleResourceType.CT_VARIANT_CONTEXTS); if (!variantsResource.hasOutputType()) { throw new IllegalArgumentException(String.format( "The provided %s resource (%s) must be a writeable/output resource", - BundleResourceType.CT_VARIANT_CONTEXTS, - variantsResource)); + BundleResourceType.CT_VARIANT_CONTEXTS, variantsResource)); } final Optional optIndexIOPath = getIndexIOPath(outputBundle); if (variantsResource.getIOPath().isPresent()) { final IOPath variantsIOPath = variantsResource.getIOPath().get(); if (optIndexIOPath.isPresent()) { - //TODO: this resolves the index automatically. it should check to make sure the provided index + // TODO: this resolves the index automatically. it should check to make sure the provided index // matches the one that is automatically resolved, otherwise throw since the request will not be honored } writerBuilder.setOutputPath(variantsIOPath.toPath()); @@ -175,8 +172,7 @@ private static void setWriterBuilderOutputs( if (optIndexIOPath.isPresent()) { throw new HtsjdkUnsupportedOperationException(String.format( "Can't write a VCF index to file %s when output is written to a stream %s", - optIndexIOPath.get(), - variantsResource)); + optIndexIOPath.get(), variantsResource)); } // VariantContextWriterBuilder doesn't provide any buffering, but if we were to wrap the provided // stream in a buffered stream here, we wouldn't be able to properly control the flushing or lifetime @@ -197,13 +193,11 @@ private static void setWriterBuilderOutputs( private static void validateImputedOutputType(final IOPath variantsIOPath) { final VariantContextWriterBuilder.OutputType imputedOutputType = VariantContextWriterBuilder.determineOutputTypeFromFile(variantsIOPath.toPath()); - if (imputedOutputType != VariantContextWriterBuilder.OutputType.VCF && - imputedOutputType != VariantContextWriterBuilder.OutputType.BLOCK_COMPRESSED_VCF) { + if (imputedOutputType != VariantContextWriterBuilder.OutputType.VCF + && imputedOutputType != VariantContextWriterBuilder.OutputType.BLOCK_COMPRESSED_VCF) { throw new HtsjdkPluginException(String.format( "An unsupported output type %s was derived for the resource %s ", - imputedOutputType, - variantsIOPath.getRawInputString() - )); + imputedOutputType, variantsIOPath.getRawInputString())); } } @@ -216,13 +210,11 @@ private static Optional getIndexIOPath(final Bundle outputBundle) { if (!indexResource.hasOutputType()) { throw new IllegalArgumentException(String.format( "The provided %s index resource (%s) must be a writeable/output resource", - BundleResourceType.CT_VARIANTS_INDEX, - indexResource)); + BundleResourceType.CT_VARIANTS_INDEX, indexResource)); } if (!indexResource.getIOPath().isPresent()) { throw new HtsjdkUnsupportedOperationException("Writing a VCF index to a stream not implemented"); } return indexResource.getIOPath(); } - } diff --git a/src/main/java/htsjdk/beta/codecs/variants/vcf/VariantsCodecUtils.java b/src/main/java/htsjdk/beta/codecs/variants/vcf/VariantsCodecUtils.java index ecf5375f42..82410b37f9 100644 --- a/src/main/java/htsjdk/beta/codecs/variants/vcf/VariantsCodecUtils.java +++ b/src/main/java/htsjdk/beta/codecs/variants/vcf/VariantsCodecUtils.java @@ -1,8 +1,8 @@ package htsjdk.beta.codecs.variants.vcf; +import htsjdk.annotations.InternalAPI; import htsjdk.beta.io.bundle.Bundle; import htsjdk.beta.io.bundle.BundleResourceType; -import htsjdk.annotations.InternalAPI; /** * Utilities for VCF codec implementations. @@ -38,8 +38,7 @@ public static void assertBundleContainsIndex(final Bundle inputBundle) { if (!bundleContainsIndex(inputBundle)) { throw new IllegalArgumentException(String.format( "To make index queries, an index resource must be provided in the resource bundle: %s", - inputBundle - )); + inputBundle)); } } } diff --git a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv3_2/VCFCodecV3_2.java b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv3_2/VCFCodecV3_2.java index 5956aedc0a..711e32c0cc 100644 --- a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv3_2/VCFCodecV3_2.java +++ b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv3_2/VCFCodecV3_2.java @@ -4,8 +4,8 @@ import htsjdk.beta.codecs.variants.vcf.VCFDecoder; import htsjdk.beta.codecs.variants.vcf.VCFEncoder; import htsjdk.beta.exception.HtsjdkUnsupportedOperationException; -import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.io.bundle.Bundle; +import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.variants.VariantsDecoderOptions; import htsjdk.beta.plugin.variants.VariantsEncoderOptions; import htsjdk.utils.ValidationUtils; @@ -14,12 +14,14 @@ * VCF V3.2 codec. */ public class VCFCodecV3_2 extends VCFCodec { - public static final HtsVersion VCF_V32_VERSION = new HtsVersion(3,2,0); + public static final HtsVersion VCF_V32_VERSION = new HtsVersion(3, 2, 0); private static final String VCF_V32_MAGIC = "##format=VCRv3.2"; @Override - public HtsVersion getVersion() { return VCF_V32_VERSION; } + public HtsVersion getVersion() { + return VCF_V32_VERSION; + } @Override public VCFDecoder getDecoder(final Bundle inputBundle, final VariantsDecoderOptions decoderOptions) { @@ -43,6 +45,7 @@ public boolean runVersionUpgrade(final HtsVersion sourceCodecVersion, final HtsV } @Override - protected String getSignatureString() { return VCF_V32_MAGIC; } - + protected String getSignatureString() { + return VCF_V32_MAGIC; + } } diff --git a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv3_2/VCFDecoderV3_2.java b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv3_2/VCFDecoderV3_2.java index 8b692266fd..b4547b9cfd 100644 --- a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv3_2/VCFDecoderV3_2.java +++ b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv3_2/VCFDecoderV3_2.java @@ -1,8 +1,8 @@ package htsjdk.beta.codecs.variants.vcf.vcfv3_2; import htsjdk.beta.codecs.variants.vcf.VCFDecoder; -import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.io.bundle.Bundle; +import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.variants.VariantsDecoderOptions; import htsjdk.variant.vcf.VCF3Codec; @@ -25,5 +25,4 @@ public VCFDecoderV3_2(final Bundle inputBundle, final VariantsDecoderOptions var public HtsVersion getVersion() { return VCFCodecV3_2.VCF_V32_VERSION; } - } diff --git a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv3_2/VCFEncoderV3_2.java b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv3_2/VCFEncoderV3_2.java index 3367de3f17..967e618cd6 100644 --- a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv3_2/VCFEncoderV3_2.java +++ b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv3_2/VCFEncoderV3_2.java @@ -1,8 +1,8 @@ package htsjdk.beta.codecs.variants.vcf.vcfv3_2; import htsjdk.beta.codecs.variants.vcf.VCFEncoder; -import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.io.bundle.Bundle; +import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.variants.VariantsEncoderOptions; /** @@ -17,12 +17,11 @@ public class VCFEncoderV3_2 extends VCFEncoder { * @param variantsEncoderOptions the {@link VariantsEncoderOptions} to use */ public VCFEncoderV3_2(final Bundle outputBundle, final VariantsEncoderOptions variantsEncoderOptions) { - super(outputBundle,variantsEncoderOptions); + super(outputBundle, variantsEncoderOptions); } @Override public HtsVersion getVersion() { return VCFCodecV3_2.VCF_V32_VERSION; } - } diff --git a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv3_3/VCFCodecV3_3.java b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv3_3/VCFCodecV3_3.java index df865c0208..64072b7af0 100644 --- a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv3_3/VCFCodecV3_3.java +++ b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv3_3/VCFCodecV3_3.java @@ -4,8 +4,8 @@ import htsjdk.beta.codecs.variants.vcf.VCFDecoder; import htsjdk.beta.codecs.variants.vcf.VCFEncoder; import htsjdk.beta.exception.HtsjdkUnsupportedOperationException; -import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.io.bundle.Bundle; +import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.variants.VariantsDecoderOptions; import htsjdk.beta.plugin.variants.VariantsEncoderOptions; import htsjdk.utils.ValidationUtils; @@ -14,12 +14,14 @@ * VCF V3.3 codec. */ public class VCFCodecV3_3 extends VCFCodec { - public static final HtsVersion VCF_V33_VERSION = new HtsVersion(3,3,0); + public static final HtsVersion VCF_V33_VERSION = new HtsVersion(3, 3, 0); private static final String VCF_V33_MAGIC = "##fileformat=VCFv3.3"; @Override - public HtsVersion getVersion() { return VCF_V33_VERSION; } + public HtsVersion getVersion() { + return VCF_V33_VERSION; + } @Override public VCFDecoder getDecoder(final Bundle inputBundle, final VariantsDecoderOptions decoderOptions) { @@ -43,6 +45,7 @@ public boolean runVersionUpgrade(final HtsVersion sourceCodecVersion, final HtsV } @Override - protected String getSignatureString() { return VCF_V33_MAGIC; } - + protected String getSignatureString() { + return VCF_V33_MAGIC; + } } diff --git a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv3_3/VCFDecoderV3_3.java b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv3_3/VCFDecoderV3_3.java index 69a1485009..43a1700f9b 100644 --- a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv3_3/VCFDecoderV3_3.java +++ b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv3_3/VCFDecoderV3_3.java @@ -1,8 +1,8 @@ package htsjdk.beta.codecs.variants.vcf.vcfv3_3; import htsjdk.beta.codecs.variants.vcf.VCFDecoder; -import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.io.bundle.Bundle; +import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.variants.VariantsDecoderOptions; import htsjdk.variant.vcf.VCF3Codec; @@ -25,5 +25,4 @@ public VCFDecoderV3_3(final Bundle inputBundle, final VariantsDecoderOptions var public HtsVersion getVersion() { return VCFCodecV3_3.VCF_V33_VERSION; } - } diff --git a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv3_3/VCFEncoderV3_3.java b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv3_3/VCFEncoderV3_3.java index 2e848ab4fd..82e57f63cc 100644 --- a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv3_3/VCFEncoderV3_3.java +++ b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv3_3/VCFEncoderV3_3.java @@ -1,8 +1,8 @@ package htsjdk.beta.codecs.variants.vcf.vcfv3_3; import htsjdk.beta.codecs.variants.vcf.VCFEncoder; -import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.io.bundle.Bundle; +import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.variants.VariantsEncoderOptions; /** @@ -17,12 +17,11 @@ public class VCFEncoderV3_3 extends VCFEncoder { * @param variantsEncoderOptions the {@link VariantsEncoderOptions} to use */ public VCFEncoderV3_3(final Bundle outputBundle, final VariantsEncoderOptions variantsEncoderOptions) { - super(outputBundle,variantsEncoderOptions); + super(outputBundle, variantsEncoderOptions); } @Override public HtsVersion getVersion() { return VCFCodecV3_3.VCF_V33_VERSION; } - } diff --git a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_0/VCFCodecV4_0.java b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_0/VCFCodecV4_0.java index 88d1453f1f..b7ccc4bab3 100644 --- a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_0/VCFCodecV4_0.java +++ b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_0/VCFCodecV4_0.java @@ -4,8 +4,8 @@ import htsjdk.beta.codecs.variants.vcf.VCFDecoder; import htsjdk.beta.codecs.variants.vcf.VCFEncoder; import htsjdk.beta.exception.HtsjdkUnsupportedOperationException; -import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.io.bundle.Bundle; +import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.variants.VariantsDecoderOptions; import htsjdk.beta.plugin.variants.VariantsEncoderOptions; import htsjdk.utils.ValidationUtils; @@ -14,12 +14,14 @@ * VCF V4.0 codec. */ public class VCFCodecV4_0 extends VCFCodec { - public static final HtsVersion VCF_V40_VERSION = new HtsVersion(4,0,0); + public static final HtsVersion VCF_V40_VERSION = new HtsVersion(4, 0, 0); private static final String VCF_V40_MAGIC = "##fileformat=VCFv4.0"; @Override - public HtsVersion getVersion() { return VCF_V40_VERSION; } + public HtsVersion getVersion() { + return VCF_V40_VERSION; + } @Override public VCFDecoder getDecoder(final Bundle inputBundle, final VariantsDecoderOptions decoderOptions) { @@ -43,6 +45,7 @@ public boolean runVersionUpgrade(final HtsVersion sourceCodecVersion, final HtsV } @Override - protected String getSignatureString() { return VCF_V40_MAGIC; } - + protected String getSignatureString() { + return VCF_V40_MAGIC; + } } diff --git a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_0/VCFDecoderV4_0.java b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_0/VCFDecoderV4_0.java index fb0e57facc..459fc249cb 100644 --- a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_0/VCFDecoderV4_0.java +++ b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_0/VCFDecoderV4_0.java @@ -1,8 +1,8 @@ package htsjdk.beta.codecs.variants.vcf.vcfv4_0; import htsjdk.beta.codecs.variants.vcf.VCFDecoder; -import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.io.bundle.Bundle; +import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.variants.VariantsDecoderOptions; /** @@ -24,5 +24,4 @@ public VCFDecoderV4_0(final Bundle inputBundle, final VariantsDecoderOptions var public HtsVersion getVersion() { return VCFCodecV4_0.VCF_V40_VERSION; } - } diff --git a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_0/VCFEncoderV4_0.java b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_0/VCFEncoderV4_0.java index 77b42a5318..a68b0b7ad4 100644 --- a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_0/VCFEncoderV4_0.java +++ b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_0/VCFEncoderV4_0.java @@ -1,8 +1,8 @@ package htsjdk.beta.codecs.variants.vcf.vcfv4_0; import htsjdk.beta.codecs.variants.vcf.VCFEncoder; -import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.io.bundle.Bundle; +import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.variants.VariantsEncoderOptions; /** @@ -17,12 +17,11 @@ public class VCFEncoderV4_0 extends VCFEncoder { * @param variantsEncoderOptions the {@link VariantsEncoderOptions} to use */ public VCFEncoderV4_0(final Bundle outputBundle, final VariantsEncoderOptions variantsEncoderOptions) { - super(outputBundle,variantsEncoderOptions); + super(outputBundle, variantsEncoderOptions); } @Override public HtsVersion getVersion() { return VCFCodecV4_0.VCF_V40_VERSION; } - } diff --git a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_1/VCFCodecV4_1.java b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_1/VCFCodecV4_1.java index 6b114fad34..adbc44d000 100644 --- a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_1/VCFCodecV4_1.java +++ b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_1/VCFCodecV4_1.java @@ -4,8 +4,8 @@ import htsjdk.beta.codecs.variants.vcf.VCFDecoder; import htsjdk.beta.codecs.variants.vcf.VCFEncoder; import htsjdk.beta.exception.HtsjdkUnsupportedOperationException; -import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.io.bundle.Bundle; +import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.variants.VariantsDecoderOptions; import htsjdk.beta.plugin.variants.VariantsEncoderOptions; import htsjdk.utils.ValidationUtils; @@ -14,12 +14,14 @@ * VCF V4.1 codec. */ public class VCFCodecV4_1 extends VCFCodec { - public static final HtsVersion VCF_V41_VERSION = new HtsVersion(4,1,0); + public static final HtsVersion VCF_V41_VERSION = new HtsVersion(4, 1, 0); private static final String VCF_V41_MAGIC = "##fileformat=VCFv4.1"; @Override - public HtsVersion getVersion() { return VCF_V41_VERSION; } + public HtsVersion getVersion() { + return VCF_V41_VERSION; + } @Override public VCFDecoder getDecoder(final Bundle inputBundle, final VariantsDecoderOptions decoderOptions) { @@ -43,6 +45,7 @@ public boolean runVersionUpgrade(final HtsVersion sourceCodecVersion, final HtsV } @Override - protected String getSignatureString() { return VCF_V41_MAGIC; } - + protected String getSignatureString() { + return VCF_V41_MAGIC; + } } diff --git a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_1/VCFDecoderV4_1.java b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_1/VCFDecoderV4_1.java index 9651ba11e0..8c85525f8e 100644 --- a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_1/VCFDecoderV4_1.java +++ b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_1/VCFDecoderV4_1.java @@ -1,8 +1,8 @@ package htsjdk.beta.codecs.variants.vcf.vcfv4_1; import htsjdk.beta.codecs.variants.vcf.VCFDecoder; -import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.io.bundle.Bundle; +import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.variants.VariantsDecoderOptions; /** @@ -24,5 +24,4 @@ public VCFDecoderV4_1(final Bundle inputBundle, final VariantsDecoderOptions var public HtsVersion getVersion() { return VCFCodecV4_1.VCF_V41_VERSION; } - } diff --git a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_1/VCFEncoderV4_1.java b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_1/VCFEncoderV4_1.java index 0418befb3e..b7db01c2fe 100644 --- a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_1/VCFEncoderV4_1.java +++ b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_1/VCFEncoderV4_1.java @@ -1,8 +1,8 @@ package htsjdk.beta.codecs.variants.vcf.vcfv4_1; import htsjdk.beta.codecs.variants.vcf.VCFEncoder; -import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.io.bundle.Bundle; +import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.variants.VariantsEncoderOptions; /** @@ -17,12 +17,11 @@ public class VCFEncoderV4_1 extends VCFEncoder { * @param variantsEncoderOptions the {@link VariantsEncoderOptions} to use */ public VCFEncoderV4_1(final Bundle outputBundle, final VariantsEncoderOptions variantsEncoderOptions) { - super(outputBundle,variantsEncoderOptions); + super(outputBundle, variantsEncoderOptions); } @Override public HtsVersion getVersion() { return VCFCodecV4_1.VCF_V41_VERSION; } - } diff --git a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_2/VCFCodecV4_2.java b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_2/VCFCodecV4_2.java index 30214c4dc1..3eaf1d26a7 100644 --- a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_2/VCFCodecV4_2.java +++ b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_2/VCFCodecV4_2.java @@ -14,12 +14,14 @@ * VCF V4.2 codec. */ public class VCFCodecV4_2 extends VCFCodec { - public static final HtsVersion VCF_V42_VERSION = new HtsVersion(4,2,0); + public static final HtsVersion VCF_V42_VERSION = new HtsVersion(4, 2, 0); private static final String VCF_V42_MAGIC = "##fileformat=VCFv4.2"; @Override - public HtsVersion getVersion() { return VCF_V42_VERSION; } + public HtsVersion getVersion() { + return VCF_V42_VERSION; + } @Override public VCFDecoder getDecoder(final Bundle inputBundle, final VariantsDecoderOptions decoderOptions) { @@ -43,6 +45,7 @@ public boolean runVersionUpgrade(final HtsVersion sourceCodecVersion, final HtsV } @Override - protected String getSignatureString() { return VCF_V42_MAGIC; } - + protected String getSignatureString() { + return VCF_V42_MAGIC; + } } diff --git a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_2/VCFDecoderV4_2.java b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_2/VCFDecoderV4_2.java index 097a7a3d74..e30e376df3 100644 --- a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_2/VCFDecoderV4_2.java +++ b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_2/VCFDecoderV4_2.java @@ -24,5 +24,4 @@ public VCFDecoderV4_2(final Bundle inputBundle, final VariantsDecoderOptions var public HtsVersion getVersion() { return VCFCodecV4_2.VCF_V42_VERSION; } - } diff --git a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_2/VCFEncoderV4_2.java b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_2/VCFEncoderV4_2.java index e23d976aaf..622acb37e1 100644 --- a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_2/VCFEncoderV4_2.java +++ b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_2/VCFEncoderV4_2.java @@ -17,12 +17,11 @@ public class VCFEncoderV4_2 extends VCFEncoder { * @param variantsEncoderOptions the {@link VariantsEncoderOptions} to use */ public VCFEncoderV4_2(final Bundle outputBundle, final VariantsEncoderOptions variantsEncoderOptions) { - super(outputBundle,variantsEncoderOptions); + super(outputBundle, variantsEncoderOptions); } @Override public HtsVersion getVersion() { return VCFCodecV4_2.VCF_V42_VERSION; } - } diff --git a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_3/VCFCodecV4_3.java b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_3/VCFCodecV4_3.java index 44516b4a72..7593928df0 100644 --- a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_3/VCFCodecV4_3.java +++ b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_3/VCFCodecV4_3.java @@ -4,8 +4,8 @@ import htsjdk.beta.codecs.variants.vcf.VCFDecoder; import htsjdk.beta.codecs.variants.vcf.VCFEncoder; import htsjdk.beta.exception.HtsjdkUnsupportedOperationException; -import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.io.bundle.Bundle; +import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.variants.VariantsDecoderOptions; import htsjdk.beta.plugin.variants.VariantsEncoderOptions; import htsjdk.utils.ValidationUtils; @@ -14,12 +14,14 @@ * VCF V4.3 codec. */ public class VCFCodecV4_3 extends VCFCodec { - public static final HtsVersion VCF_V43_VERSION = new HtsVersion(4,3,0); + public static final HtsVersion VCF_V43_VERSION = new HtsVersion(4, 3, 0); private static final String VCF_V43_MAGIC = "##fileformat=VCFv4.3"; @Override - public HtsVersion getVersion() { return VCF_V43_VERSION; } + public HtsVersion getVersion() { + return VCF_V43_VERSION; + } @Override public VCFDecoder getDecoder(final Bundle inputBundle, final VariantsDecoderOptions decoderOptions) { @@ -40,6 +42,7 @@ public boolean runVersionUpgrade(final HtsVersion sourceCodecVersion, final HtsV } @Override - protected String getSignatureString() { return VCF_V43_MAGIC; } - + protected String getSignatureString() { + return VCF_V43_MAGIC; + } } diff --git a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_3/VCFDecoderV4_3.java b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_3/VCFDecoderV4_3.java index 32de5539fa..92a9051a3d 100644 --- a/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_3/VCFDecoderV4_3.java +++ b/src/main/java/htsjdk/beta/codecs/variants/vcf/vcfv4_3/VCFDecoderV4_3.java @@ -1,8 +1,8 @@ package htsjdk.beta.codecs.variants.vcf.vcfv4_3; import htsjdk.beta.codecs.variants.vcf.VCFDecoder; -import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.io.bundle.Bundle; +import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.variants.VariantsDecoderOptions; /** @@ -24,5 +24,4 @@ public VCFDecoderV4_3(final Bundle inputBundle, final VariantsDecoderOptions var public HtsVersion getVersion() { return VCFCodecV4_3.VCF_V43_VERSION; } - } diff --git a/src/main/java/htsjdk/beta/exception/HtsjdkPluginException.java b/src/main/java/htsjdk/beta/exception/HtsjdkPluginException.java index 470b0eb96c..1adebb012b 100644 --- a/src/main/java/htsjdk/beta/exception/HtsjdkPluginException.java +++ b/src/main/java/htsjdk/beta/exception/HtsjdkPluginException.java @@ -14,5 +14,4 @@ public class HtsjdkPluginException extends HtsjdkException { public HtsjdkPluginException(String message) { super(message); } - } diff --git a/src/main/java/htsjdk/beta/io/IOPathUtils.java b/src/main/java/htsjdk/beta/io/IOPathUtils.java index 965c850a59..fe5476af6a 100644 --- a/src/main/java/htsjdk/beta/io/IOPathUtils.java +++ b/src/main/java/htsjdk/beta/io/IOPathUtils.java @@ -3,8 +3,6 @@ import htsjdk.beta.exception.HtsjdkIOException; import htsjdk.io.HtsPath; import htsjdk.io.IOPath; -import htsjdk.utils.ValidationUtils; - import java.io.BufferedOutputStream; import java.io.File; import java.io.IOException; @@ -42,17 +40,14 @@ public static IOPath createTempPath(final String prefix, final String suffix) { public static String getStringFromPath(final IOPath ioPath) { try { final StringWriter stringWriter = new StringWriter(); - //TODO: the UTF-8 encoding of these should be codified somewhere else... - Files.lines(ioPath.toPath(), StandardCharsets.UTF_8).forEach( - line -> { - stringWriter.write(line); - stringWriter.append("\n"); - }); + // TODO: the UTF-8 encoding of these should be codified somewhere else... + Files.lines(ioPath.toPath(), StandardCharsets.UTF_8).forEach(line -> { + stringWriter.write(line); + stringWriter.append("\n"); + }); return stringWriter.toString(); } catch (final IOException e) { - throw new HtsjdkIOException( - String.format("Failed to read from: %s", ioPath.getRawInputString()), - e); + throw new HtsjdkIOException(String.format("Failed to read from: %s", ioPath.getRawInputString()), e); } } @@ -66,9 +61,7 @@ public static void writeStringToPath(final IOPath ioPath, final String contents) try (final BufferedOutputStream bos = new BufferedOutputStream(ioPath.getOutputStream())) { bos.write(contents.getBytes()); } catch (final IOException e) { - throw new HtsjdkIOException( - String.format("Failed to write to: %s", ioPath.getRawInputString()), - e); + throw new HtsjdkIOException(String.format("Failed to write to: %s", ioPath.getRawInputString()), e); } } @@ -91,19 +84,16 @@ public static void writeStringToPath(final IOPath ioPath, final String contents) * @return A new IOPath object with the new extension */ public static T replaceExtension( - final IOPath path, - final String newExtension, - final Function ioPathConstructor){ - final String extensionToUse = newExtension.startsWith(".") ? - newExtension : - "." + newExtension; + final IOPath path, final String newExtension, final Function ioPathConstructor) { + final String extensionToUse = newExtension.startsWith(".") ? newExtension : "." + newExtension; final Optional oldExtension = path.getExtension(); - if (oldExtension.isEmpty()){ + if (oldExtension.isEmpty()) { throw new RuntimeException("The original path has no extension to replace" + path.getURIString()); } final String oldFileName = path.toPath().getFileName().toString(); final String newFileName = oldFileName.replaceAll(oldExtension.get() + "$", extensionToUse); - return ioPathConstructor.apply(path.toPath().resolveSibling(newFileName).toUri().toString()); + return ioPathConstructor.apply( + path.toPath().resolveSibling(newFileName).toUri().toString()); } /** @@ -123,13 +113,10 @@ public static T replaceExtension( * @return A new IOPath object with the new extension */ public static T appendExtension( - final IOPath path, - final String extension, - final Function ioPathConstructor){ + final IOPath path, final String extension, final Function ioPathConstructor) { final String oldFileName = path.toPath().getFileName().toString(); - final String newExtension = extension.startsWith(".") ? - extension : - "." + extension; - return ioPathConstructor.apply(path.toPath().resolveSibling(oldFileName + newExtension).toUri().toString()); + final String newExtension = extension.startsWith(".") ? extension : "." + extension; + return ioPathConstructor.apply( + path.toPath().resolveSibling(oldFileName + newExtension).toUri().toString()); } } diff --git a/src/main/java/htsjdk/beta/io/bundle/Bundle.java b/src/main/java/htsjdk/beta/io/bundle/Bundle.java index 06ef7d12dd..9b7187401c 100644 --- a/src/main/java/htsjdk/beta/io/bundle/Bundle.java +++ b/src/main/java/htsjdk/beta/io/bundle/Bundle.java @@ -2,7 +2,6 @@ import htsjdk.io.IOPath; import htsjdk.utils.ValidationUtils; - import java.io.Serializable; import java.util.*; @@ -50,8 +49,8 @@ public class Bundle implements Iterable, Serializable { */ public Bundle(final String primaryContentType, final Collection resources) { ValidationUtils.nonNull(primaryContentType, "primary content type"); - ValidationUtils.validateArg(primaryContentType.length() > 0, - "A non-zero length primary resource content type must be provided"); + ValidationUtils.validateArg( + primaryContentType.length() > 0, "A non-zero length primary resource content type must be provided"); ValidationUtils.nonNull(resources, "resource collection"); if (resources.isEmpty()) { throw new IllegalArgumentException("A bundle must contain at least one resource"); @@ -67,9 +66,8 @@ public Bundle(final String primaryContentType, final Collection // validate that the primary resource actually exists in the resources if (!this.resources.containsKey(primaryContentType)) { - throw new IllegalArgumentException( - String.format("Primary resource content type %s is not present in the bundle's resources", - primaryContentType)); + throw new IllegalArgumentException(String.format( + "Primary resource content type %s is not present in the bundle's resources", primaryContentType)); } } @@ -94,12 +92,9 @@ public Optional get(final String targetContentType) { */ public BundleResource getOrThrow(final String requiredContentType) { ValidationUtils.nonNull(requiredContentType, "target content string"); - return get(requiredContentType).orElseThrow( - () -> new IllegalArgumentException( - String.format("No resource found in bundle %s with content type %s", - this, - requiredContentType - ))); + return get(requiredContentType) + .orElseThrow(() -> new IllegalArgumentException(String.format( + "No resource found in bundle %s with content type %s", this, requiredContentType))); } /** @@ -107,7 +102,9 @@ public BundleResource getOrThrow(final String requiredContentType) { * * @return the primary content type for this bundle */ - public String getPrimaryContentType() { return primaryContentType; } + public String getPrimaryContentType() { + return primaryContentType; + } /** * Get the primary {@link BundleResource} for this bundle. @@ -131,7 +128,9 @@ public Collection getResources() { * @return iterator of BundleResources for this bundle. */ @Override - public Iterator iterator() { return resources.values().iterator(); } + public Iterator iterator() { + return resources.values().iterator(); + } @Override public boolean equals(Object o) { diff --git a/src/main/java/htsjdk/beta/io/bundle/BundleBuilder.java b/src/main/java/htsjdk/beta/io/bundle/BundleBuilder.java index 4affc3dbfb..139eba5958 100644 --- a/src/main/java/htsjdk/beta/io/bundle/BundleBuilder.java +++ b/src/main/java/htsjdk/beta/io/bundle/BundleBuilder.java @@ -1,7 +1,6 @@ package htsjdk.beta.io.bundle; import htsjdk.utils.ValidationUtils; - import java.util.ArrayList; import java.util.List; @@ -16,7 +15,7 @@ public final class BundleBuilder { /** * Start a new bundle builder. */ - public BundleBuilder() { } + public BundleBuilder() {} /** * Add the primary resource to the bundle. The content type of resource will be the bundle's primary key. @@ -27,10 +26,9 @@ public BundleBuilder() { } public BundleBuilder addPrimary(final BundleResource resource) { ValidationUtils.nonNull(resource, "resource"); if (primaryResource != null) { - throw new IllegalStateException(String.format( - "Can't add primary resource %s to a bundle that already has primary resource %s", - resource.getContentType(), - primaryResource)); + throw new IllegalStateException(String.format( + "Can't add primary resource %s to a bundle that already has primary resource %s", + resource.getContentType(), primaryResource)); } primaryResource = resource.getContentType(); addSecondary(resource); @@ -66,5 +64,3 @@ public Bundle build() { return bundle; } } - - diff --git a/src/main/java/htsjdk/beta/io/bundle/BundleJSON.java b/src/main/java/htsjdk/beta/io/bundle/BundleJSON.java index 95d4d7aaac..f367e9516e 100644 --- a/src/main/java/htsjdk/beta/io/bundle/BundleJSON.java +++ b/src/main/java/htsjdk/beta/io/bundle/BundleJSON.java @@ -4,10 +4,6 @@ import htsjdk.io.IOPath; import htsjdk.samtools.util.Log; import htsjdk.utils.ValidationUtils; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -15,8 +11,11 @@ import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; -//TODO: Once the schema is finalized, we need to bump the version # to 1.0, and publish it. +// TODO: Once the schema is finalized, we need to bump the version # to 1.0, and publish it. /** * Methods for serializing and deserializing Bundles to and from JSON strings. @@ -25,17 +24,17 @@ public class BundleJSON { public static final String BUNDLE_EXTENSION = ".json"; private static final Log LOG = Log.getInstance(BundleJSON.class); - public static final String JSON_PROPERTY_SCHEMA = "schema"; - public static final String JSON_PROPERTY_SCHEMA_NAME = "schemaName"; - public static final String JSON_PROPERTY_SCHEMA_VERSION = "schemaVersion"; - public static final String JSON_PROPERTY_PRIMARY = "primary"; - public static final String JSON_PROPERTY_PATH = "path"; - public static final String JSON_PROPERTY_FORMAT = "format"; + public static final String JSON_PROPERTY_SCHEMA = "schema"; + public static final String JSON_PROPERTY_SCHEMA_NAME = "schemaName"; + public static final String JSON_PROPERTY_SCHEMA_VERSION = "schemaVersion"; + public static final String JSON_PROPERTY_PRIMARY = "primary"; + public static final String JSON_PROPERTY_PATH = "path"; + public static final String JSON_PROPERTY_FORMAT = "format"; - public static final String JSON_SCHEMA_NAME = "htsbundle"; - public static final String JSON_SCHEMA_VERSION = "0.1.0"; // TODO: bump this to 1.0.0 + public static final String JSON_SCHEMA_NAME = "htsbundle"; + public static final String JSON_SCHEMA_VERSION = "0.1.0"; // TODO: bump this to 1.0.0 - final private static Set TOP_LEVEL_PROPERTIES = Set.of(JSON_PROPERTY_SCHEMA, JSON_PROPERTY_PRIMARY); + private static final Set TOP_LEVEL_PROPERTIES = Set.of(JSON_PROPERTY_SCHEMA, JSON_PROPERTY_PRIMARY); /** * Serialize a bundle to a JSON string representation. All resources in the bundle must @@ -53,8 +52,8 @@ public static String toJSON(final Bundle bundle) { .put(JSON_PROPERTY_SCHEMA_NAME, JSON_SCHEMA_NAME) .put(JSON_PROPERTY_SCHEMA_VERSION, JSON_SCHEMA_VERSION); final JSONObject outerJSON = new JSONObject() - .put(JSON_PROPERTY_SCHEMA, schemaMap) - .put(JSON_PROPERTY_PRIMARY, bundle.getPrimaryContentType()); + .put(JSON_PROPERTY_SCHEMA, schemaMap) + .put(JSON_PROPERTY_PRIMARY, bundle.getPrimaryContentType()); bundle.forEach(bundleResource -> { final Optional resourcePath = bundleResource.getIOPath(); @@ -63,9 +62,11 @@ public static String toJSON(final Bundle bundle) { } // generate JSON for each bundle resource - final JSONObject resourceJSON = new JSONObject().put(JSON_PROPERTY_PATH, resourcePath.get().getURIString()); + final JSONObject resourceJSON = + new JSONObject().put(JSON_PROPERTY_PATH, resourcePath.get().getURIString()); if (bundleResource.getFileFormat().isPresent()) { - resourceJSON.put(JSON_PROPERTY_FORMAT, bundleResource.getFileFormat().get()); + resourceJSON.put( + JSON_PROPERTY_FORMAT, bundleResource.getFileFormat().get()); } outerJSON.put(bundleResource.getContentType(), resourceJSON); }); @@ -83,21 +84,19 @@ public static String toJSON(final List bundles) { if (bundles.isEmpty()) { throw new IllegalArgumentException("A bundle list must contain at least one bundle"); } - return bundles.stream() - .map(BundleJSON::toJSON) - .collect(Collectors.joining(",\n", "[", "]")); + return bundles.stream().map(BundleJSON::toJSON).collect(Collectors.joining(",\n", "[", "]")); } - /** - * Create a Bundle from a jsonString. - * - * @param jsonString a valid JSON string conforming to the bundle schema (for compatibility, a bundle list is also - * accepted, as long as it only contains a single bundle) - * @return a {@link Bundle} created from jsonString - */ - public static Bundle toBundle(final String jsonString) { + /** + * Create a Bundle from a jsonString. + * + * @param jsonString a valid JSON string conforming to the bundle schema (for compatibility, a bundle list is also + * accepted, as long as it only contains a single bundle) + * @return a {@link Bundle} created from jsonString + */ + public static Bundle toBundle(final String jsonString) { return toBundle(ValidationUtils.nonEmpty(jsonString, "resource list"), HtsPath::new); - } + } /** * Create a Bundle from jsonString using a custom class that implements {@link IOPath} for all resources. @@ -109,8 +108,7 @@ public static Bundle toBundle(final String jsonString) { * @return a newly created {@link Bundle} */ public static Bundle toBundle( - final String jsonString, - final Function ioPathConstructor) { + final String jsonString, final Function ioPathConstructor) { ValidationUtils.nonEmpty(jsonString, "JSON string"); ValidationUtils.nonNull(ioPathConstructor, "IOPath-derived class constructor"); try { @@ -121,16 +119,16 @@ public static Bundle toBundle( try { final List bundles = toBundleList(jsonString, ioPathConstructor); if (bundles.size() > 1) { - throw new IllegalArgumentException( - String.format("A JSON string with more than one bundle was provided but only a single bundle is allowed in this context (%s)", - e.getMessage())); + throw new IllegalArgumentException(String.format( + "A JSON string with more than one bundle was provided but only a single bundle is allowed in this context (%s)", + e.getMessage())); } return bundles.get(0); } catch (JSONException | UnsupportedOperationException e2) { throw new IllegalArgumentException( - String.format("The JSON can be interpreted neither as an individual bundle (%s) nor as a bundle collection (%s)", - e.getMessage(), - e2.getMessage()), + String.format( + "The JSON can be interpreted neither as an individual bundle (%s) nor as a bundle collection (%s)", + e.getMessage(), e2.getMessage()), e); } } @@ -145,8 +143,7 @@ public static Bundle toBundle( * @param IOPath-derived class to use for IOPathResources */ public static List toBundleList( - final String jsonString, - final Function ioPathConstructor) { + final String jsonString, final Function ioPathConstructor) { ValidationUtils.nonEmpty(jsonString, "json bundle string"); ValidationUtils.nonNull(ioPathConstructor, "IOPath-derived class constructor"); @@ -154,10 +151,9 @@ public static List toBundleList( try { final JSONArray jsonArray = new JSONArray(jsonString); jsonArray.forEach(element -> { - if (! (element instanceof JSONObject jsonObject)) { - throw new IllegalArgumentException( - String.format("Bundle collections may contain only Bundle objects, found %s", - element.toString())); + if (!(element instanceof JSONObject jsonObject)) { + throw new IllegalArgumentException(String.format( + "Bundle collections may contain only Bundle objects, found %s", element.toString())); } bundles.add(toBundle(jsonObject, ioPathConstructor)); }); @@ -167,9 +163,9 @@ public static List toBundleList( bundles.add(toBundle(new JSONObject(jsonString), ioPathConstructor)); } catch (JSONException | UnsupportedOperationException e2) { throw new IllegalArgumentException( - String.format("JSON can be interpreted neither as an individual bundle (%s) nor as a bundle collection (%s)", - e2.getMessage(), - e.getMessage()), + String.format( + "JSON can be interpreted neither as an individual bundle (%s) nor as a bundle collection (%s)", + e2.getMessage(), e.getMessage()), e); } } @@ -205,8 +201,8 @@ private static Bundle toBundle( } final String schemaVersion = getRequiredPropertyAsString(schemaMap, JSON_PROPERTY_SCHEMA_VERSION); if (!schemaVersion.equals(JSON_SCHEMA_VERSION)) { - throw new IllegalArgumentException(String.format("Expected bundle schema version %s but found %s", - JSON_SCHEMA_VERSION, schemaVersion)); + throw new IllegalArgumentException(String.format( + "Expected bundle schema version %s but found %s", JSON_SCHEMA_VERSION, schemaVersion)); } final String primaryContentType = getRequiredPropertyAsString(jsonObject, JSON_PROPERTY_PRIMARY); @@ -216,19 +212,18 @@ private static Bundle toBundle( throw new IllegalArgumentException(e); } } + private static IOPathResource toBundleResource( - final String contentType, - final JSONObject jsonObject, - final Function ioPathConstructor) { + final String contentType, final JSONObject jsonObject, final Function ioPathConstructor) { final String format = jsonObject.optString(JSON_PROPERTY_FORMAT, null); return new IOPathResource( ioPathConstructor.apply(getRequiredPropertyAsString(jsonObject, JSON_PROPERTY_PATH)), contentType, format); } + private static Collection toBundleResources( - final JSONObject jsonResources, - final Function ioPathConstructor) { + final JSONObject jsonResources, final Function ioPathConstructor) { final List bundleResources = new ArrayList<>(); // default capacity of 10 seems right jsonResources.keySet().forEach(key -> { @@ -248,9 +243,7 @@ private static String getRequiredPropertyAsString(final JSONObject jsonDocument, final String propertyValue = jsonDocument.optString(propertyName, null); if (propertyValue == null) { throw new IllegalArgumentException( - String.format("JSON bundle is missing the required property %s (%s)", - propertyName, - jsonDocument)); + String.format("JSON bundle is missing the required property %s (%s)", propertyName, jsonDocument)); } return propertyValue; diff --git a/src/main/java/htsjdk/beta/io/bundle/BundleResource.java b/src/main/java/htsjdk/beta/io/bundle/BundleResource.java index 2eb610cb0e..b281b4fe56 100644 --- a/src/main/java/htsjdk/beta/io/bundle/BundleResource.java +++ b/src/main/java/htsjdk/beta/io/bundle/BundleResource.java @@ -2,7 +2,6 @@ import htsjdk.io.IOPath; import htsjdk.samtools.seekablestream.SeekableStream; - import java.io.InputStream; import java.io.OutputStream; import java.util.Optional; @@ -130,5 +129,4 @@ public interface BundleResource { * @return true if this resource can be rendered as a {@link SeekableStream} (see {@link #getSeekableStream}) */ boolean hasSeekableStream(); - } diff --git a/src/main/java/htsjdk/beta/io/bundle/BundleResourceBase.java b/src/main/java/htsjdk/beta/io/bundle/BundleResourceBase.java index dacf766f5b..500aab3d34 100644 --- a/src/main/java/htsjdk/beta/io/bundle/BundleResourceBase.java +++ b/src/main/java/htsjdk/beta/io/bundle/BundleResourceBase.java @@ -3,7 +3,6 @@ import htsjdk.io.IOPath; import htsjdk.samtools.seekablestream.SeekableStream; import htsjdk.utils.ValidationUtils; - import java.io.InputStream; import java.io.OutputStream; import java.io.Serializable; @@ -29,10 +28,7 @@ public abstract class BundleResourceBase implements BundleResource, Serializable * a resource with content type "READS". Predefined format strings are defined * in {@link BundleResourceType}. */ - public BundleResourceBase( - final String displayName, - final String contentType, - final String format) { + public BundleResourceBase(final String displayName, final String contentType, final String format) { ValidationUtils.nonEmpty(displayName, "display name"); ValidationUtils.nonEmpty(contentType, "content type"); this.displayName = displayName; @@ -41,7 +37,9 @@ public BundleResourceBase( } @Override - public String getDisplayName() { return displayName; } + public String getDisplayName() { + return displayName; + } @Override public String getContentType() { @@ -54,25 +52,39 @@ public Optional getFileFormat() { } @Override - public Optional getIOPath() { return Optional.empty(); } + public Optional getIOPath() { + return Optional.empty(); + } @Override - public Optional getInputStream() { return Optional.empty(); } + public Optional getInputStream() { + return Optional.empty(); + } @Override - public Optional getOutputStream() { return Optional.empty(); } + public Optional getOutputStream() { + return Optional.empty(); + } @Override - public Optional getSeekableStream() { return Optional.empty(); } + public Optional getSeekableStream() { + return Optional.empty(); + } @Override - public boolean hasSeekableStream() { return false; } + public boolean hasSeekableStream() { + return false; + } @Override - public boolean hasInputType() { return false; } + public boolean hasInputType() { + return false; + } @Override - public boolean hasOutputType() { return false; } + public boolean hasOutputType() { + return false; + } @Override public String toString() { diff --git a/src/main/java/htsjdk/beta/io/bundle/BundleResourceType.java b/src/main/java/htsjdk/beta/io/bundle/BundleResourceType.java index d083b06107..83f0d07a5e 100644 --- a/src/main/java/htsjdk/beta/io/bundle/BundleResourceType.java +++ b/src/main/java/htsjdk/beta/io/bundle/BundleResourceType.java @@ -1,6 +1,5 @@ package htsjdk.beta.io.bundle; -import htsjdk.beta.plugin.HtsContentType; import htsjdk.beta.plugin.reads.ReadsFormats; import htsjdk.beta.plugin.variants.VariantsFormats; @@ -26,6 +25,7 @@ public class BundleResourceType { /**************************************** Common primary content types ******************************************/ public static final String CT_ALIGNED_READS = "ALIGNED_READS"; + public static final String CT_VARIANT_CONTEXTS = "VARIANT_CONTEXTS"; public static final String CT_HAPLOID_REFERENCE = "HAPLOID_REFERENCE"; public static final String CT_FEATURES = "FEATURES"; @@ -33,6 +33,7 @@ public class BundleResourceType { /****************************************** Resource types for READS ********************************************/ /** Formats for primary content type {@link BundleResourceType#CT_ALIGNED_READS} */ public static final String FMT_READS_SAM = ReadsFormats.SAM; + public static final String FMT_READS_BAM = ReadsFormats.BAM; public static final String FMT_READS_CRAM = ReadsFormats.CRAM; public static final String FMT_READS_HTSGET_BAM = ReadsFormats.HTSGET_BAM; @@ -41,12 +42,14 @@ public class BundleResourceType { public static final String CT_READS_INDEX = "READS_INDEX"; /** Formats for secondary content type {@link BundleResourceType#CT_READS_INDEX} resources */ public static final String FMT_READS_INDEX_BAI = "BAI"; + public static final String FMT_READS_INDEX_CRAI = "CRAI"; public static final String FMT_READS_INDEX_CSI = "CSI"; /****************************************** Resource types for VARIANTS ******************************************/ /** Format names for content type {@link BundleResourceType#CT_VARIANT_CONTEXTS} */ public static final String FMT_VARIANTS_VCF = VariantsFormats.VCF; + public static final String FMT_VARIANTS_BCF = VariantsFormats.BCF; /** Secondary content types for primary content type {@link #CT_VARIANT_CONTEXTS} resources */ @@ -55,14 +58,12 @@ public class BundleResourceType { /****************************************** Resource types for HAPLOID REFERENCES ********************************/ /** Secondary content types for {@link BundleResourceType#CT_HAPLOID_REFERENCE} resources*/ public static final String CT_REFERENCE_DICTIONARY = "REFERENCE_DICTIONARY"; + public static final String CT_REFERENCE_INDEX = "REFERENCE_INDEX"; public static final String CT_REFERENCE_INDEX_GZI = "REFERENCE_INDEX_GZI"; - /****************************************** Resource types for FEATURES ********************************/ - /****************************************** MISCELLANEOUS Resource types ********************************/ public static final String CT_MD5 = "MD5"; - } diff --git a/src/main/java/htsjdk/beta/io/bundle/IOPathResource.java b/src/main/java/htsjdk/beta/io/bundle/IOPathResource.java index be200942a4..580f8bbde4 100644 --- a/src/main/java/htsjdk/beta/io/bundle/IOPathResource.java +++ b/src/main/java/htsjdk/beta/io/bundle/IOPathResource.java @@ -5,7 +5,6 @@ import htsjdk.samtools.seekablestream.SeekablePathStream; import htsjdk.samtools.seekablestream.SeekableStream; import htsjdk.utils.ValidationUtils; - import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -31,20 +30,20 @@ public IOPathResource(final IOPath ioPath, final String contentType) { /** * Create a {@link BundleResource} backed by an IOPath, specifying a content type string and format string. - + * * @param ioPath The IOPath for this resource. May not be null. * @param contentType The content type for this resource. May not be mull or 0-length. * @param format The format for this resource. May not be null or 0-length. */ public IOPathResource(final IOPath ioPath, final String contentType, final String format) { - super(ValidationUtils.nonNull(ioPath, "ioPath").getRawInputString(), - contentType, - format); + super(ValidationUtils.nonNull(ioPath, "ioPath").getRawInputString(), contentType, format); this.ioPath = ioPath; } @Override - public Optional getIOPath() { return Optional.of(ioPath); } + public Optional getIOPath() { + return Optional.of(ioPath); + } /** * {@inheritDoc} @@ -59,13 +58,19 @@ public Optional getInputStream() { } @Override - public Optional getOutputStream() { return Optional.of(ioPath.getOutputStream()); } + public Optional getOutputStream() { + return Optional.of(ioPath.getOutputStream()); + } @Override - public boolean hasInputType() { return true; } + public boolean hasInputType() { + return true; + } @Override - public boolean hasOutputType() { return true; } + public boolean hasOutputType() { + return true; + } @Override public boolean hasSeekableStream() { @@ -119,5 +124,4 @@ public int hashCode() { result = 31 * result + ioPath.hashCode(); return result; } - } diff --git a/src/main/java/htsjdk/beta/io/bundle/InputStreamResource.java b/src/main/java/htsjdk/beta/io/bundle/InputStreamResource.java index 2bde148b22..b86158c2c7 100644 --- a/src/main/java/htsjdk/beta/io/bundle/InputStreamResource.java +++ b/src/main/java/htsjdk/beta/io/bundle/InputStreamResource.java @@ -2,7 +2,6 @@ import htsjdk.beta.exception.HtsjdkIOException; import htsjdk.utils.ValidationUtils; - import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; @@ -13,9 +12,9 @@ */ public class InputStreamResource extends BundleResourceBase { private static final long serialVersionUID = 1L; - private static final int MINIMUM_STREAM_BUFFER_SIZE = 64*1024; - private final InputStream rawInputStream; // the stream as provided by the caller - private BufferedInputStream bufferedInputStream; // buffered stream wrapper to compensate for signature probing + private static final int MINIMUM_STREAM_BUFFER_SIZE = 64 * 1024; + private final InputStream rawInputStream; // the stream as provided by the caller + private BufferedInputStream bufferedInputStream; // buffered stream wrapper to compensate for signature probing /** * Create a {@link BundleResource} backed by an InputStream. @@ -44,10 +43,7 @@ public InputStreamResource(final InputStream inputStream, final String displayNa * @param format The format for this resource. May not be null or 0-length. */ public InputStreamResource( - final InputStream inputStream, - final String displayName, - final String contentType, - final String format) { + final InputStream inputStream, final String displayName, final String contentType, final String format) { super(displayName, contentType, format); ValidationUtils.nonNull(inputStream, "input stream"); this.rawInputStream = inputStream; @@ -76,14 +72,14 @@ public SignatureStream getSignatureStream(final int signatureProbeLength) { // is ultimately consumed once signature probing is complete, it will be consumed from the // beginning. bufferedInputStream = new BufferedInputStream( - rawInputStream, - Integer.max(signatureProbeLength, MINIMUM_STREAM_BUFFER_SIZE)); + rawInputStream, Integer.max(signatureProbeLength, MINIMUM_STREAM_BUFFER_SIZE)); bufferedInputStream.mark(signatureProbeLength); bufferedInputStream.read(signaturePrefix); bufferedInputStream.reset(); } catch (final IOException e) { throw new HtsjdkIOException( - String.format("Error during signature probing on %s with prefix size %d", + String.format( + "Error during signature probing on %s with prefix size %d", this.getDisplayName(), signatureProbeLength), e); } @@ -91,7 +87,9 @@ public SignatureStream getSignatureStream(final int signatureProbeLength) { } @Override - public boolean hasInputType() { return true; } + public boolean hasInputType() { + return true; + } @Override public boolean equals(Object o) { diff --git a/src/main/java/htsjdk/beta/io/bundle/OutputStreamResource.java b/src/main/java/htsjdk/beta/io/bundle/OutputStreamResource.java index 56fa46ca22..d176f74ddd 100644 --- a/src/main/java/htsjdk/beta/io/bundle/OutputStreamResource.java +++ b/src/main/java/htsjdk/beta/io/bundle/OutputStreamResource.java @@ -2,7 +2,6 @@ import htsjdk.beta.exception.HtsjdkException; import htsjdk.utils.ValidationUtils; - import java.io.OutputStream; import java.util.Optional; @@ -33,10 +32,7 @@ public OutputStreamResource(final OutputStream outputStream, final String displa * @param format The format for this resource. May not be null or 0-length. */ public OutputStreamResource( - final OutputStream outputStream, - final String displayName, - final String contentType, - final String format) { + final OutputStream outputStream, final String displayName, final String contentType, final String format) { super(displayName, contentType, format); ValidationUtils.nonNull(outputStream, "output stream"); this.outputStream = outputStream; @@ -54,7 +50,9 @@ public SignatureStream getSignatureStream(int signatureProbeLength) { } @Override - public boolean hasOutputType() { return true; } + public boolean hasOutputType() { + return true; + } @Override public boolean equals(Object o) { diff --git a/src/main/java/htsjdk/beta/io/bundle/SeekableStreamResource.java b/src/main/java/htsjdk/beta/io/bundle/SeekableStreamResource.java index 642f53f572..5c9fe39748 100644 --- a/src/main/java/htsjdk/beta/io/bundle/SeekableStreamResource.java +++ b/src/main/java/htsjdk/beta/io/bundle/SeekableStreamResource.java @@ -3,7 +3,6 @@ import htsjdk.beta.exception.HtsjdkIOException; import htsjdk.samtools.seekablestream.SeekableStream; import htsjdk.utils.ValidationUtils; - import java.io.IOException; import java.io.InputStream; import java.util.Optional; @@ -23,7 +22,8 @@ public class SeekableStreamResource extends InputStreamResource { * @param displayName The display name for this resource. May not be null or 0-length. * @param contentType The content type for this resource. May not be null or 0-length. */ - public SeekableStreamResource(final SeekableStream seekableStream, final String displayName, final String contentType) { + public SeekableStreamResource( + final SeekableStream seekableStream, final String displayName, final String contentType) { this(seekableStream, displayName, contentType, null); } @@ -59,7 +59,9 @@ public Optional getInputStream() { } @Override - public Optional getSeekableStream() { return Optional.of(seekableStream); } + public Optional getSeekableStream() { + return Optional.of(seekableStream); + } /** * {@inheritDoc} @@ -69,7 +71,7 @@ public Optional getInputStream() { */ @Override public SignatureStream getSignatureStream(final int signatureProbeLength) { - //we don't want to call the super class' implementation here + // we don't want to call the super class' implementation here final byte[] signaturePrefix = new byte[signatureProbeLength]; try { // for a SeekableStreamResource, we don't want this code to close the actual SeekableStream that @@ -81,19 +83,23 @@ public SignatureStream getSignatureStream(final int signatureProbeLength) { seekableStream.seek(0); } catch (final IOException e) { throw new HtsjdkIOException( - String.format("Error creating signature probe for seekable stream resource with prefix size %d", + String.format( + "Error creating signature probe for seekable stream resource with prefix size %d", signatureProbeLength), e); } return new SignatureStream(signatureProbeLength, signaturePrefix); - } @Override - public boolean hasInputType() { return true; } + public boolean hasInputType() { + return true; + } @Override - public boolean hasSeekableStream() { return true; } + public boolean hasSeekableStream() { + return true; + } @Override public boolean equals(Object o) { diff --git a/src/main/java/htsjdk/beta/io/bundle/SignatureStream.java b/src/main/java/htsjdk/beta/io/bundle/SignatureStream.java index 4feaa88433..32a631a7fd 100644 --- a/src/main/java/htsjdk/beta/io/bundle/SignatureStream.java +++ b/src/main/java/htsjdk/beta/io/bundle/SignatureStream.java @@ -32,6 +32,7 @@ public SignatureStream(final int signaturePrefixLength, final byte[] signaturePr * * @return the maximum number of bytes that can be consumed from this stream. */ - public final int getSignaturePrefixLength() { return signaturePrefixLength;} - + public final int getSignaturePrefixLength() { + return signaturePrefixLength; + } } diff --git a/src/main/java/htsjdk/beta/package-info.java b/src/main/java/htsjdk/beta/package-info.java index 181e0e1c1b..a039f8ef0d 100644 --- a/src/main/java/htsjdk/beta/package-info.java +++ b/src/main/java/htsjdk/beta/package-info.java @@ -9,5 +9,3 @@ * {@link htsjdk.annotations.BetaAPI}. Subpackages may be subsequently released as part of the public API, * at which time they will be moved out of the {@link htsjdk.beta} package. */ - - diff --git a/src/main/java/htsjdk/beta/plugin/HtsCodec.java b/src/main/java/htsjdk/beta/plugin/HtsCodec.java index a128fc19b8..4bfa33e36e 100644 --- a/src/main/java/htsjdk/beta/plugin/HtsCodec.java +++ b/src/main/java/htsjdk/beta/plugin/HtsCodec.java @@ -1,12 +1,12 @@ package htsjdk.beta.plugin; +import htsjdk.beta.io.bundle.Bundle; import htsjdk.beta.io.bundle.BundleResource; import htsjdk.beta.io.bundle.BundleResourceType; import htsjdk.beta.io.bundle.SignatureStream; import htsjdk.beta.plugin.reads.ReadsFormats; import htsjdk.beta.plugin.registry.HtsCodecRegistry; import htsjdk.io.IOPath; -import htsjdk.beta.io.bundle.Bundle; /** * Base interface implemented by all {@link htsjdk.beta.plugin} codecs. @@ -221,7 +221,8 @@ public interface HtsCodecioPath (obtained via {@link IOPath#getURI()}) @@ -362,7 +365,9 @@ default String getDisplayName() { * may throw exceptions. *

*/ - default int getSignatureProbeLength() { return getSignatureLength(); } + default int getSignatureProbeLength() { + return getSignatureLength(); + } /** * Get an {@link HtsDecoder} to decode the provided inputs. The input bundle must contain @@ -397,5 +402,4 @@ default String getDisplayName() { * @return an {@link HtsEncoder} suitable for writing to the provided outputs */ HtsEncoder getEncoder(final Bundle outputBundle, final E encoderOptions); - } diff --git a/src/main/java/htsjdk/beta/plugin/HtsContentType.java b/src/main/java/htsjdk/beta/plugin/HtsContentType.java index abe4312fd7..fb0dbfa6fb 100644 --- a/src/main/java/htsjdk/beta/plugin/HtsContentType.java +++ b/src/main/java/htsjdk/beta/plugin/HtsContentType.java @@ -26,7 +26,7 @@ */ public enum HtsContentType { - //where would a FASTQ codec fit ? in the same category (which implies the same interfaces) ? + // where would a FASTQ codec fit ? in the same category (which implies the same interfaces) ? /** * Haploid reference content type (see {@link HaploidReferenceFormats} for related formats) */ diff --git a/src/main/java/htsjdk/beta/plugin/HtsDecoder.java b/src/main/java/htsjdk/beta/plugin/HtsDecoder.java index 4040f1ce3a..b5d4693a66 100644 --- a/src/main/java/htsjdk/beta/plugin/HtsDecoder.java +++ b/src/main/java/htsjdk/beta/plugin/HtsDecoder.java @@ -15,8 +15,7 @@ * @param type param for the header for this format (i.e. SAMFileHeader) * @param type param for the record for this format (i.e. SAMRecord) */ -public interface HtsDecoder - extends HtsQuery, Closeable { +public interface HtsDecoder extends HtsQuery, Closeable { /** * Get the name of the file format supported by this decoder.The format name defines the underlying @@ -52,5 +51,4 @@ public interface HtsDecoder */ @Override void close(); - } diff --git a/src/main/java/htsjdk/beta/plugin/HtsDecoderOptions.java b/src/main/java/htsjdk/beta/plugin/HtsDecoderOptions.java index cb4ae04d53..ab4f686dad 100644 --- a/src/main/java/htsjdk/beta/plugin/HtsDecoderOptions.java +++ b/src/main/java/htsjdk/beta/plugin/HtsDecoderOptions.java @@ -3,5 +3,4 @@ /** * Base tag interface for options for {@link HtsDecoder}s. */ -public interface HtsDecoderOptions { -} +public interface HtsDecoderOptions {} diff --git a/src/main/java/htsjdk/beta/plugin/HtsEncoder.java b/src/main/java/htsjdk/beta/plugin/HtsEncoder.java index 824dfcfc79..c8cb9d17cb 100644 --- a/src/main/java/htsjdk/beta/plugin/HtsEncoder.java +++ b/src/main/java/htsjdk/beta/plugin/HtsEncoder.java @@ -2,7 +2,6 @@ import htsjdk.beta.io.bundle.BundleResource; import htsjdk.beta.io.bundle.BundleResourceType; - import java.io.Closeable; /** @@ -56,5 +55,4 @@ public interface HtsEncoder extends Cl */ @Override void close(); - } diff --git a/src/main/java/htsjdk/beta/plugin/HtsEncoderOptions.java b/src/main/java/htsjdk/beta/plugin/HtsEncoderOptions.java index 6067aaaafd..093ab3fb92 100644 --- a/src/main/java/htsjdk/beta/plugin/HtsEncoderOptions.java +++ b/src/main/java/htsjdk/beta/plugin/HtsEncoderOptions.java @@ -3,5 +3,4 @@ /** * Base tag interface for options for {@link HtsEncoder}s. */ -public interface HtsEncoderOptions { -} +public interface HtsEncoderOptions {} diff --git a/src/main/java/htsjdk/beta/plugin/HtsHeader.java b/src/main/java/htsjdk/beta/plugin/HtsHeader.java index 5f93d1153d..c2f6e5a583 100644 --- a/src/main/java/htsjdk/beta/plugin/HtsHeader.java +++ b/src/main/java/htsjdk/beta/plugin/HtsHeader.java @@ -1,10 +1,9 @@ package htsjdk.beta.plugin; -//Note: This is a just a tagging interface used to tag SAMFileHeader, VCFHeader, and SAMSequenceDictionary. +// Note: This is a just a tagging interface used to tag SAMFileHeader, VCFHeader, and SAMSequenceDictionary. // It will be more useful once version upgrading is implemented. /** * Tagging interface used as a type-bound for codec/encoder/decoder header type params. */ -public interface HtsHeader { -} +public interface HtsHeader {} diff --git a/src/main/java/htsjdk/beta/plugin/HtsRecord.java b/src/main/java/htsjdk/beta/plugin/HtsRecord.java index fe5cc0c31c..5b2d7ae094 100644 --- a/src/main/java/htsjdk/beta/plugin/HtsRecord.java +++ b/src/main/java/htsjdk/beta/plugin/HtsRecord.java @@ -1,11 +1,10 @@ package htsjdk.beta.plugin; -//Note: This is a tagging interface currently used as a type-bound for codec/encoder/decoder +// Note: This is a tagging interface currently used as a type-bound for codec/encoder/decoder // record type params, and used to tag SAMRecord, BAMRecord, VariantContext, and ReferenceSequence. // It will be more useful once version upgrading is implemented. /** * Tagging interface used as a type-bound for codec/encoder/decoder record type params. */ -public interface HtsRecord { -} +public interface HtsRecord {} diff --git a/src/main/java/htsjdk/beta/plugin/HtsVersion.java b/src/main/java/htsjdk/beta/plugin/HtsVersion.java index e93e325bb9..31e200ee94 100644 --- a/src/main/java/htsjdk/beta/plugin/HtsVersion.java +++ b/src/main/java/htsjdk/beta/plugin/HtsVersion.java @@ -40,7 +40,8 @@ public HtsVersion(final String versionString) { ValidationUtils.nonNull(versionString); final String[] parts = versionString.split("\\."); if (parts.length != 3) { - throw new IllegalArgumentException(String.format("Unable parse version string as major.minor.patch: '%s'", versionString)); + throw new IllegalArgumentException( + String.format("Unable parse version string as major.minor.patch: '%s'", versionString)); } try { majorVersion = Integer.parseInt(parts[0]); @@ -108,7 +109,7 @@ public int compareTo(HtsVersion o) { ValidationUtils.nonNull(o); if (this.majorVersion == o.majorVersion) { if (this.minorVersion == o.minorVersion) { - if (this.patchVersion == o.patchVersion){ + if (this.patchVersion == o.patchVersion) { return 0; } return this.patchVersion - o.patchVersion; diff --git a/src/main/java/htsjdk/beta/plugin/IOUtils.java b/src/main/java/htsjdk/beta/plugin/IOUtils.java index d2512cac93..e6b052b6c8 100644 --- a/src/main/java/htsjdk/beta/plugin/IOUtils.java +++ b/src/main/java/htsjdk/beta/plugin/IOUtils.java @@ -4,7 +4,6 @@ import htsjdk.io.HtsPath; import htsjdk.io.IOPath; import htsjdk.samtools.util.BlockCompressedOutputStream; - import java.io.BufferedOutputStream; import java.io.File; import java.io.IOException; @@ -42,7 +41,7 @@ public static IOPath createTempPath(final String prefix, final String suffix) { * @param toConvert Path to convert to GATKPath * @return a Path, or null if the input was null. */ - public static HtsPath toHtsPath(Path toConvert){ + public static HtsPath toHtsPath(Path toConvert) { return null == toConvert ? null : new HtsPath(toConvert.toUri().toString()); } @@ -55,17 +54,15 @@ public static HtsPath toHtsPath(Path toConvert){ public static String getStringFromPath(final IOPath ioPath) { try { final StringWriter stringWriter = new StringWriter(); - //TODO: the UTF-8 encoding of these should be codified somewhere else... - Files.lines(ioPath.toPath(), StandardCharsets.UTF_8).forEach( - line -> { - stringWriter.write(line); - stringWriter.append("\n"); - }); + // TODO: the UTF-8 encoding of these should be codified somewhere else... + Files.lines(ioPath.toPath(), StandardCharsets.UTF_8).forEach(line -> { + stringWriter.write(line); + stringWriter.append("\n"); + }); return stringWriter.toString(); } catch (final IOException e) { throw new HtsjdkIOException( - String.format("Failed to load reads bundle json from: %s", ioPath.getRawInputString()), - e); + String.format("Failed to load reads bundle json from: %s", ioPath.getRawInputString()), e); } } @@ -77,21 +74,21 @@ public static String getStringFromPath(final IOPath ioPath) { * @param gzipOutput if true, gzip output */ public static void writeStringToPath(final IOPath ioPath, final String contents, final boolean gzipOutput) { - if (gzipOutput) { - try (final BufferedOutputStream bos = new BufferedOutputStream(ioPath.getOutputStream()); - final BlockCompressedOutputStream bcos = new BlockCompressedOutputStream(bos, ioPath.toPath())) { - bcos.write(contents.getBytes()); - } catch (final IOException e) { - throw new HtsjdkIOException( - String.format("Failed to load reads bundle json from: %s", ioPath.getRawInputString()), e); - } - } else { - try (final BufferedOutputStream bos = new BufferedOutputStream(ioPath.getOutputStream())) { - bos.write(contents.getBytes()); - } catch (final IOException e) { - throw new HtsjdkIOException( - String.format("Failed to load reads bundle json from: %s", ioPath.getRawInputString()), e); - } - } + if (gzipOutput) { + try (final BufferedOutputStream bos = new BufferedOutputStream(ioPath.getOutputStream()); + final BlockCompressedOutputStream bcos = new BlockCompressedOutputStream(bos, ioPath.toPath())) { + bcos.write(contents.getBytes()); + } catch (final IOException e) { + throw new HtsjdkIOException( + String.format("Failed to load reads bundle json from: %s", ioPath.getRawInputString()), e); + } + } else { + try (final BufferedOutputStream bos = new BufferedOutputStream(ioPath.getOutputStream())) { + bos.write(contents.getBytes()); + } catch (final IOException e) { + throw new HtsjdkIOException( + String.format("Failed to load reads bundle json from: %s", ioPath.getRawInputString()), e); + } + } } } diff --git a/src/main/java/htsjdk/beta/plugin/hapref/HapRefDecoderOptions.java b/src/main/java/htsjdk/beta/plugin/hapref/HapRefDecoderOptions.java index 363264f067..0b2294654f 100644 --- a/src/main/java/htsjdk/beta/plugin/hapref/HapRefDecoderOptions.java +++ b/src/main/java/htsjdk/beta/plugin/hapref/HapRefDecoderOptions.java @@ -5,5 +5,4 @@ /** * Class for haploid reference decoder options. */ -public class HapRefDecoderOptions implements HtsDecoderOptions { -} +public class HapRefDecoderOptions implements HtsDecoderOptions {} diff --git a/src/main/java/htsjdk/beta/plugin/hapref/HaploidReferenceCodec.java b/src/main/java/htsjdk/beta/plugin/hapref/HaploidReferenceCodec.java index 25b49a3ac0..7bac69149b 100644 --- a/src/main/java/htsjdk/beta/plugin/hapref/HaploidReferenceCodec.java +++ b/src/main/java/htsjdk/beta/plugin/hapref/HaploidReferenceCodec.java @@ -6,11 +6,11 @@ /** * Base class for all {@link HtsContentType#HAPLOID_REFERENCE} codecs. */ -public interface HaploidReferenceCodec extends HtsCodec< - HaploidReferenceDecoderOptions, - HaploidReferenceEncoderOptions> { +public interface HaploidReferenceCodec + extends HtsCodec { @Override - default HtsContentType getContentType() { return HtsContentType.HAPLOID_REFERENCE; } - + default HtsContentType getContentType() { + return HtsContentType.HAPLOID_REFERENCE; + } } diff --git a/src/main/java/htsjdk/beta/plugin/hapref/HaploidReferenceDecoder.java b/src/main/java/htsjdk/beta/plugin/hapref/HaploidReferenceDecoder.java index 0836ca8c06..9fcf79c411 100644 --- a/src/main/java/htsjdk/beta/plugin/hapref/HaploidReferenceDecoder.java +++ b/src/main/java/htsjdk/beta/plugin/hapref/HaploidReferenceDecoder.java @@ -8,4 +8,4 @@ /** * Base class for all {@link HtsContentType#HAPLOID_REFERENCE} decoders. */ -public interface HaploidReferenceDecoder extends HtsDecoder { } +public interface HaploidReferenceDecoder extends HtsDecoder {} diff --git a/src/main/java/htsjdk/beta/plugin/hapref/HaploidReferenceDecoderOptions.java b/src/main/java/htsjdk/beta/plugin/hapref/HaploidReferenceDecoderOptions.java index 6c402f22a2..c2c5170047 100644 --- a/src/main/java/htsjdk/beta/plugin/hapref/HaploidReferenceDecoderOptions.java +++ b/src/main/java/htsjdk/beta/plugin/hapref/HaploidReferenceDecoderOptions.java @@ -5,5 +5,4 @@ /** * Class for haploid reference decoder options. */ -public class HaploidReferenceDecoderOptions implements HtsDecoderOptions { -} +public class HaploidReferenceDecoderOptions implements HtsDecoderOptions {} diff --git a/src/main/java/htsjdk/beta/plugin/hapref/HaploidReferenceEncoder.java b/src/main/java/htsjdk/beta/plugin/hapref/HaploidReferenceEncoder.java index e7eab395cf..fda62cd457 100644 --- a/src/main/java/htsjdk/beta/plugin/hapref/HaploidReferenceEncoder.java +++ b/src/main/java/htsjdk/beta/plugin/hapref/HaploidReferenceEncoder.java @@ -8,4 +8,4 @@ /** * Base class for all {@link HtsContentType#HAPLOID_REFERENCE} encoders. */ -public interface HaploidReferenceEncoder extends HtsEncoder { } +public interface HaploidReferenceEncoder extends HtsEncoder {} diff --git a/src/main/java/htsjdk/beta/plugin/hapref/HaploidReferenceEncoderOptions.java b/src/main/java/htsjdk/beta/plugin/hapref/HaploidReferenceEncoderOptions.java index cb2ea05f91..bc2a9115e0 100644 --- a/src/main/java/htsjdk/beta/plugin/hapref/HaploidReferenceEncoderOptions.java +++ b/src/main/java/htsjdk/beta/plugin/hapref/HaploidReferenceEncoderOptions.java @@ -5,5 +5,4 @@ /** * Class for haploid reference encoder options. */ -public class HaploidReferenceEncoderOptions implements HtsEncoderOptions { -} +public class HaploidReferenceEncoderOptions implements HtsEncoderOptions {} diff --git a/src/main/java/htsjdk/beta/plugin/hapref/HaploidReferenceFormats.java b/src/main/java/htsjdk/beta/plugin/hapref/HaploidReferenceFormats.java index 607189b914..aa25ba996a 100644 --- a/src/main/java/htsjdk/beta/plugin/hapref/HaploidReferenceFormats.java +++ b/src/main/java/htsjdk/beta/plugin/hapref/HaploidReferenceFormats.java @@ -9,5 +9,4 @@ public class HaploidReferenceFormats { * Fasta format */ public static final String FASTA = "FASTA"; - } diff --git a/src/main/java/htsjdk/beta/plugin/interval/HtsIntervalUtils.java b/src/main/java/htsjdk/beta/plugin/interval/HtsIntervalUtils.java index 06555055d3..570ae422bb 100644 --- a/src/main/java/htsjdk/beta/plugin/interval/HtsIntervalUtils.java +++ b/src/main/java/htsjdk/beta/plugin/interval/HtsIntervalUtils.java @@ -1,16 +1,14 @@ package htsjdk.beta.plugin.interval; +import htsjdk.annotations.InternalAPI; import htsjdk.samtools.QueryInterval; import htsjdk.samtools.SAMSequenceDictionary; import htsjdk.samtools.util.Locatable; -import htsjdk.annotations.InternalAPI; import htsjdk.utils.ValidationUtils; - import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; - /** * Methods for interconverting between HtsQueryInterval and existing htsjdk types such as Locatable/QueryInterval */ @@ -57,9 +55,7 @@ public int getEnd() { @Override public String toString() { - return String.format("%s:%s-%s", - interval.getQueryName(), - interval.getStart(), interval.getEnd()); + return String.format("%s:%s-%s", interval.getQueryName(), interval.getStart(), interval.getEnd()); } }; } @@ -73,10 +69,7 @@ public String toString() { @InternalAPI public static List toLocatableList(final List intervals) { ValidationUtils.nonNull(intervals, "interval list"); - return intervals - .stream() - .map(si -> toLocatable(si)) - .collect(Collectors.toList()); + return intervals.stream().map(si -> toLocatable(si)).collect(Collectors.toList()); } /** @@ -88,14 +81,13 @@ public static List toLocatableList(final List intervals) */ @InternalAPI public static QueryInterval[] toQueryIntervalArray( - final List intervals, - final SAMSequenceDictionary dictionary) { + final List intervals, final SAMSequenceDictionary dictionary) { ValidationUtils.nonNull(intervals, "interval list"); ValidationUtils.nonNull(dictionary, "SAMSequenceDictionary"); - return intervals - .stream() + return intervals.stream() .map(si -> toQueryInterval(si, dictionary)) - .collect(Collectors.toList()).toArray(new QueryInterval[intervals.size()]); + .collect(Collectors.toList()) + .toArray(new QueryInterval[intervals.size()]); } /** @@ -106,8 +98,7 @@ public static QueryInterval[] toQueryIntervalArray( */ @InternalAPI public static List fromQueryIntervalArray( - final QueryInterval[] queryIntervals, - final SAMSequenceDictionary dictionary) { + final QueryInterval[] queryIntervals, final SAMSequenceDictionary dictionary) { return Arrays.stream(queryIntervals) .map(si -> new HtsQueryInterval(si, dictionary)) .collect(Collectors.toList()); @@ -126,7 +117,8 @@ public static int toIntegerSafe(final long coord) { try { return Math.toIntExact(coord); } catch (ArithmeticException e) { - throw new IllegalArgumentException(String.format("long to int conversion of %ld results in integer overflow", coord), e); + throw new IllegalArgumentException( + String.format("long to int conversion of %ld results in integer overflow", coord), e); } } } diff --git a/src/main/java/htsjdk/beta/plugin/interval/HtsQuery.java b/src/main/java/htsjdk/beta/plugin/interval/HtsQuery.java index b541c19786..c5e5b79df5 100644 --- a/src/main/java/htsjdk/beta/plugin/interval/HtsQuery.java +++ b/src/main/java/htsjdk/beta/plugin/interval/HtsQuery.java @@ -3,7 +3,6 @@ import htsjdk.beta.exception.HtsjdkUnsupportedOperationException; import htsjdk.samtools.util.CloseableIterator; import htsjdk.utils.ValidationUtils; - import java.util.Collections; import java.util.List; @@ -22,7 +21,7 @@ public interface HtsQuery extends Iterable { @Override CloseableIterator iterator(); - //******************************************* + // ******************************************* // Start temporary common query interface default implementations. /** @@ -63,10 +62,7 @@ default CloseableIterator query(final String queryString) { * @return an iterator over all records from the underlying resource that match the query arguments */ default CloseableIterator query( - final String queryName, - final long start, - final long end, - final HtsQueryRule queryRule) { + final String queryName, final long start, final long end, final HtsQueryRule queryRule) { return query(new HtsQueryInterval(queryName, start, end), queryRule); } @@ -160,7 +156,7 @@ default CloseableIterator queryContained(final List interva return query(intervals, HtsQueryRule.CONTAINED); } - //TODO: match reads that have this start; we *could* just use an HtsInterval with span==1 ? do we need this ? + // TODO: match reads that have this start; we *could* just use an HtsInterval with span==1 ? do we need this ? /** * Get an iterator over all records from the underlying resource that overlap the start position * @@ -172,5 +168,4 @@ default CloseableIterator queryStart(final String queryName, final long ValidationUtils.validateArg(isQueryable(), "Decoder is not queryable"); throw new HtsjdkUnsupportedOperationException("queryStart not implemented for this decoder"); } - } diff --git a/src/main/java/htsjdk/beta/plugin/interval/HtsQueryInterval.java b/src/main/java/htsjdk/beta/plugin/interval/HtsQueryInterval.java index 0cfc202b66..88e2ea030f 100644 --- a/src/main/java/htsjdk/beta/plugin/interval/HtsQueryInterval.java +++ b/src/main/java/htsjdk/beta/plugin/interval/HtsQueryInterval.java @@ -4,7 +4,7 @@ import htsjdk.samtools.SAMSequenceDictionary; import htsjdk.utils.ValidationUtils; -//TODO: wild cards 0, +, end of reference/contig +// TODO: wild cards 0, +, end of reference/contig /** * An concrete query interval implementation of {@link HtsInterval} used for random access queries on @@ -22,8 +22,8 @@ public class HtsQueryInterval implements HtsInterval { * @param start the integer start position * @param end the end position */ - public HtsQueryInterval(final String queryName, final long start, final long end){ - //validatePositions(contig, start, end); + public HtsQueryInterval(final String queryName, final long start, final long end) { + // validatePositions(contig, start, end); this.queryName = queryName; this.start = start; this.end = end; @@ -37,22 +37,32 @@ public HtsQueryInterval(final String queryName, final long start, final long end */ public HtsQueryInterval(final QueryInterval queryInterval, final SAMSequenceDictionary dictionary) { ValidationUtils.nonNull(dictionary, "a valid sequence dictionary is required"); - ValidationUtils.nonNull(dictionary.getSequence(queryInterval.referenceIndex), - String.format("query index %d is not present in the provided dictionary", queryInterval.referenceIndex)); - ValidationUtils.nonNull(dictionary.getSequence(queryInterval.referenceIndex).getContig(), - String.format("contig name for index %d is not present in the provided dictionary", queryInterval.referenceIndex)); + ValidationUtils.nonNull( + dictionary.getSequence(queryInterval.referenceIndex), + String.format( + "query index %d is not present in the provided dictionary", queryInterval.referenceIndex)); + ValidationUtils.nonNull( + dictionary.getSequence(queryInterval.referenceIndex).getContig(), + String.format( + "contig name for index %d is not present in the provided dictionary", + queryInterval.referenceIndex)); this.queryName = dictionary.getSequence(queryInterval.referenceIndex).getContig(); this.start = queryInterval.start; this.end = queryInterval.end; } @Override - public String getQueryName() { return queryName; } + public String getQueryName() { + return queryName; + } @Override - public long getStart() { return start; } + public long getStart() { + return start; + } @Override - public long getEnd() { return end; } - + public long getEnd() { + return end; + } } diff --git a/src/main/java/htsjdk/beta/plugin/reads/ReadsBundle.java b/src/main/java/htsjdk/beta/plugin/reads/ReadsBundle.java index 3d2f244f14..7e18940f2d 100644 --- a/src/main/java/htsjdk/beta/plugin/reads/ReadsBundle.java +++ b/src/main/java/htsjdk/beta/plugin/reads/ReadsBundle.java @@ -1,20 +1,19 @@ package htsjdk.beta.plugin.reads; import htsjdk.beta.io.IOPathUtils; -import htsjdk.beta.io.bundle.BundleJSON; -import htsjdk.io.HtsPath; -import htsjdk.io.IOPath; -import htsjdk.beta.io.bundle.BundleResourceType; import htsjdk.beta.io.bundle.Bundle; import htsjdk.beta.io.bundle.BundleBuilder; -import htsjdk.beta.io.bundle.IOPathResource; +import htsjdk.beta.io.bundle.BundleJSON; import htsjdk.beta.io.bundle.BundleResource; +import htsjdk.beta.io.bundle.BundleResourceType; +import htsjdk.beta.io.bundle.IOPathResource; +import htsjdk.io.HtsPath; +import htsjdk.io.IOPath; import htsjdk.samtools.SamFiles; import htsjdk.samtools.util.FileExtensions; import htsjdk.samtools.util.Log; import htsjdk.samtools.util.Tuple; import htsjdk.utils.ValidationUtils; - import java.io.Serializable; import java.nio.file.Path; import java.util.Arrays; @@ -77,11 +76,11 @@ protected ReadsBundle(final Collection resources) { super(BundleResourceType.CT_ALIGNED_READS, resources); } - /** - * return the {@link BundleResourceType#CT_ALIGNED_READS} {@link BundleResource} for this {@link ReadsBundle} - * - * @return the {@link BundleResourceType#CT_ALIGNED_READS} {@link BundleResource} for this {@link ReadsBundle} - */ + /** + * return the {@link BundleResourceType#CT_ALIGNED_READS} {@link BundleResource} for this {@link ReadsBundle} + * + * @return the {@link BundleResourceType#CT_ALIGNED_READS} {@link BundleResource} for this {@link ReadsBundle} + */ public BundleResource getReads() { return getOrThrow(BundleResourceType.CT_ALIGNED_READS); } @@ -127,9 +126,9 @@ public static ReadsBundle getReadsBundleFromString(final String jsonStri * @return a newly created {@link ReadsBundle} */ public static ReadsBundle getReadsBundleFromString( - final String jsonString, - final Function ioPathConstructor) { - return new ReadsBundle<>(BundleJSON.toBundle(jsonString, ioPathConstructor).getResources()); + final String jsonString, final Function ioPathConstructor) { + return new ReadsBundle<>( + BundleJSON.toBundle(jsonString, ioPathConstructor).getResources()); } /** @@ -157,14 +156,14 @@ public static ReadsBundle resolveIndex(final IOPath reads) { * @return a {@link ReadsBundle} containing reads and companion index, if it can be found */ public static ReadsBundle resolveIndex( - final T reads, - final Function ioPathConstructor) { + final T reads, final Function ioPathConstructor) { if (reads.hasFileSystemProvider()) { final Path index = SamFiles.findIndex(reads.toPath()); if (index == null) { return new ReadsBundle<>(reads); } else { - return new ReadsBundle(reads, ioPathConstructor.apply(index.toUri().toString())); + return new ReadsBundle( + reads, ioPathConstructor.apply(index.toUri().toString())); } } return new ReadsBundle<>(reads); @@ -177,9 +176,7 @@ private static IOPathResource toInputResource(final String pr if (providedContentType != null && !typePair.get().a.equals(providedContentType)) { LOG.warn(String.format( "Provided content type \"%s\" for \"%s\" doesn't match derived content type \"%s\"", - providedContentType, - ioPath.getRawInputString(), - typePair.get().a)); + providedContentType, ioPath.getRawInputString(), typePair.get().a)); } } return new IOPathResource(ioPath, providedContentType); @@ -204,9 +201,8 @@ private static Optional> getInferredCon } else if (ext.equals((FileExtensions.SAM))) { return Optional.of(new Tuple<>(BundleResourceType.CT_ALIGNED_READS, BundleResourceType.FMT_READS_SAM)); } - //TODO: finish this, else SRA, htsget,... + // TODO: finish this, else SRA, htsget,... } return Optional.empty(); } - } diff --git a/src/main/java/htsjdk/beta/plugin/reads/ReadsCodec.java b/src/main/java/htsjdk/beta/plugin/reads/ReadsCodec.java index 2958983e64..3c2b05ba1e 100644 --- a/src/main/java/htsjdk/beta/plugin/reads/ReadsCodec.java +++ b/src/main/java/htsjdk/beta/plugin/reads/ReadsCodec.java @@ -9,6 +9,7 @@ public interface ReadsCodec extends HtsCodec { @Override - default HtsContentType getContentType() { return HtsContentType.ALIGNED_READS; } - + default HtsContentType getContentType() { + return HtsContentType.ALIGNED_READS; + } } diff --git a/src/main/java/htsjdk/beta/plugin/reads/ReadsDecoder.java b/src/main/java/htsjdk/beta/plugin/reads/ReadsDecoder.java index 681a1b47b9..013f6e47a5 100644 --- a/src/main/java/htsjdk/beta/plugin/reads/ReadsDecoder.java +++ b/src/main/java/htsjdk/beta/plugin/reads/ReadsDecoder.java @@ -1,12 +1,11 @@ package htsjdk.beta.plugin.reads; +import htsjdk.beta.io.bundle.Bundle; import htsjdk.beta.plugin.HtsContentType; import htsjdk.beta.plugin.HtsDecoder; -import htsjdk.beta.io.bundle.Bundle; import htsjdk.samtools.SAMFileHeader; import htsjdk.samtools.SAMRecord; import htsjdk.samtools.util.CloseableIterator; - import java.util.Optional; /** @@ -31,4 +30,3 @@ public interface ReadsDecoder extends HtsDecoder, Read @Override Optional queryMate(SAMRecord rec); } - diff --git a/src/main/java/htsjdk/beta/plugin/reads/ReadsDecoderOptions.java b/src/main/java/htsjdk/beta/plugin/reads/ReadsDecoderOptions.java index f1ae8a6536..585d567996 100644 --- a/src/main/java/htsjdk/beta/plugin/reads/ReadsDecoderOptions.java +++ b/src/main/java/htsjdk/beta/plugin/reads/ReadsDecoderOptions.java @@ -1,12 +1,11 @@ package htsjdk.beta.plugin.reads; +import htsjdk.annotations.InternalAPI; import htsjdk.beta.codecs.reads.bam.BAMDecoderOptions; import htsjdk.beta.codecs.reads.cram.CRAMDecoderOptions; import htsjdk.beta.plugin.HtsDecoderOptions; import htsjdk.samtools.ValidationStringency; -import htsjdk.annotations.InternalAPI; import htsjdk.utils.ValidationUtils; - import java.nio.channels.SeekableByteChannel; import java.util.Optional; import java.util.function.Function; @@ -15,15 +14,15 @@ * Reads decoder options (shared/common). */ public class ReadsDecoderOptions implements HtsDecoderOptions { - private ValidationStringency validationStringency = ValidationStringency.STRICT; - private boolean eagerlyDecode = false; // honored by BAM and HtsGet - private boolean fileBasedIndexCached = false; // honored by BAM and CRAM - private boolean memoryMapIndexes = true; // honored by BAM and CRAM - //TODO: replace these with a prefetch size args, and use a local channel wrapper implementation + private ValidationStringency validationStringency = ValidationStringency.STRICT; + private boolean eagerlyDecode = false; // honored by BAM and HtsGet + private boolean fileBasedIndexCached = false; // honored by BAM and CRAM + private boolean memoryMapIndexes = true; // honored by BAM and CRAM + // TODO: replace these with a prefetch size args, and use a local channel wrapper implementation private Function readsChannelTransformer; private Function indexChannelTransformer; - private BAMDecoderOptions bamDecoderOptions = new BAMDecoderOptions(); - private CRAMDecoderOptions cramDecoderOptions = new CRAMDecoderOptions(); + private BAMDecoderOptions bamDecoderOptions = new BAMDecoderOptions(); + private CRAMDecoderOptions cramDecoderOptions = new CRAMDecoderOptions(); /** * Get the {@link ValidationStringency} used for these options. Defaults to {@link ValidationStringency#STRICT}. @@ -112,7 +111,9 @@ public ReadsDecoderOptions setMemoryMapIndexes(final boolean memoryMapIndexes) { * * @return the {@link BAMDecoderOptions} for these options */ - public BAMDecoderOptions getBAMDecoderOptions() { return bamDecoderOptions; } + public BAMDecoderOptions getBAMDecoderOptions() { + return bamDecoderOptions; + } /** * Set the {@link BAMDecoderOptions} used for these options. @@ -131,7 +132,9 @@ public ReadsDecoderOptions setBAMDecoderOptions(final BAMDecoderOptions bamDecod * * @return the {@link CRAMDecoderOptions} for these options */ - public CRAMDecoderOptions getCRAMDecoderOptions() { return cramDecoderOptions; } + public CRAMDecoderOptions getCRAMDecoderOptions() { + return cramDecoderOptions; + } /** * Set the {@link CRAMDecoderOptions} for these ReadsDecoderOptions. @@ -196,5 +199,4 @@ public ReadsDecoderOptions setIndexChannelTransformer( this.indexChannelTransformer = indexChannelTransformer; return this; } - } diff --git a/src/main/java/htsjdk/beta/plugin/reads/ReadsEncoder.java b/src/main/java/htsjdk/beta/plugin/reads/ReadsEncoder.java index 7c16fc2527..042a19bec6 100644 --- a/src/main/java/htsjdk/beta/plugin/reads/ReadsEncoder.java +++ b/src/main/java/htsjdk/beta/plugin/reads/ReadsEncoder.java @@ -8,4 +8,4 @@ /** * Base interface for {@link HtsContentType#ALIGNED_READS} encoders. */ -public interface ReadsEncoder extends HtsEncoder { } +public interface ReadsEncoder extends HtsEncoder {} diff --git a/src/main/java/htsjdk/beta/plugin/reads/ReadsEncoderOptions.java b/src/main/java/htsjdk/beta/plugin/reads/ReadsEncoderOptions.java index 711522f8c4..7e4114317c 100644 --- a/src/main/java/htsjdk/beta/plugin/reads/ReadsEncoderOptions.java +++ b/src/main/java/htsjdk/beta/plugin/reads/ReadsEncoderOptions.java @@ -40,7 +40,9 @@ public ReadsEncoderOptions setPreSorted(boolean preSorted) { * * @return the {@link BAMEncoderOptions} for these ReadsEncoderOptions */ - public BAMEncoderOptions getBAMEncoderOptions() { return bamEncoderOptions; } + public BAMEncoderOptions getBAMEncoderOptions() { + return bamEncoderOptions; + } /** * Set the {@link BAMEncoderOptions} for these ReadsEncoderOptions. Defaults values are default @@ -76,5 +78,4 @@ public ReadsEncoderOptions setCRAMEncoderOptions(final CRAMEncoderOptions cramEn this.cramEncoderOptions = cramEncoderOptions; return this; } - } diff --git a/src/main/java/htsjdk/beta/plugin/reads/ReadsFormats.java b/src/main/java/htsjdk/beta/plugin/reads/ReadsFormats.java index d406da3734..f6a3791182 100644 --- a/src/main/java/htsjdk/beta/plugin/reads/ReadsFormats.java +++ b/src/main/java/htsjdk/beta/plugin/reads/ReadsFormats.java @@ -24,5 +24,4 @@ public class ReadsFormats { * GA4GH htsget BAM format. */ public static final String HTSGET_BAM = "HTSGET_BAM"; - } diff --git a/src/main/java/htsjdk/beta/plugin/reads/ReadsQuery.java b/src/main/java/htsjdk/beta/plugin/reads/ReadsQuery.java index 0ef6821b82..707579e310 100644 --- a/src/main/java/htsjdk/beta/plugin/reads/ReadsQuery.java +++ b/src/main/java/htsjdk/beta/plugin/reads/ReadsQuery.java @@ -2,7 +2,6 @@ import htsjdk.beta.plugin.HtsRecord; import htsjdk.samtools.util.CloseableIterator; - import java.util.Optional; /** diff --git a/src/main/java/htsjdk/beta/plugin/registry/HaploidReferenceResolver.java b/src/main/java/htsjdk/beta/plugin/registry/HaploidReferenceResolver.java index 676a5ffe3c..6b59d45f64 100644 --- a/src/main/java/htsjdk/beta/plugin/registry/HaploidReferenceResolver.java +++ b/src/main/java/htsjdk/beta/plugin/registry/HaploidReferenceResolver.java @@ -15,7 +15,6 @@ import htsjdk.samtools.util.GZIIndex; import htsjdk.samtools.util.IOUtil; import htsjdk.utils.ValidationUtils; - import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -70,8 +69,7 @@ public HaploidReferenceDecoder getHaploidReferenceDecoder(final IOPath inputPath * that the registry contains an incorrectly written codec. */ public HaploidReferenceDecoder getHaploidReferenceDecoder( - final IOPath inputPath, - final HaploidReferenceDecoderOptions HaploidReferenceDecoderOptions) { + final IOPath inputPath, final HaploidReferenceDecoderOptions HaploidReferenceDecoderOptions) { ValidationUtils.nonNull(inputPath, "Input path"); ValidationUtils.nonNull(HaploidReferenceDecoderOptions, "Decoder options"); @@ -109,12 +107,12 @@ public HaploidReferenceDecoder getHaploidReferenceDecoder(final Bundle inputBund */ @SuppressWarnings("unchecked") public HaploidReferenceDecoder getHaploidReferenceDecoder( - final Bundle inputBundle, - final HaploidReferenceDecoderOptions HaploidReferenceDecoderOptions) { + final Bundle inputBundle, final HaploidReferenceDecoderOptions HaploidReferenceDecoderOptions) { ValidationUtils.nonNull(inputBundle, "Input bundle"); ValidationUtils.nonNull(HaploidReferenceDecoderOptions, "Decoder options"); - return (HaploidReferenceDecoder) resolveForDecoding(inputBundle).getDecoder(inputBundle, HaploidReferenceDecoderOptions); + return (HaploidReferenceDecoder) + resolveForDecoding(inputBundle).getDecoder(inputBundle, HaploidReferenceDecoderOptions); } /** @@ -126,38 +124,33 @@ public HaploidReferenceDecoder getHaploidReferenceDecoder( * @return a reference Bundle * @param */ - public static Bundle referenceBundleFromFastaPath(final IOPath fastaPath, final Function ioPathConstructor) { + public static Bundle referenceBundleFromFastaPath( + final IOPath fastaPath, final Function ioPathConstructor) { final BundleBuilder referenceBundleBuilder = new BundleBuilder(); referenceBundleBuilder.addPrimary(new IOPathResource(fastaPath, BundleResourceType.CT_HAPLOID_REFERENCE)); final Path dictPath = ReferenceSequenceFileFactory.getDefaultDictionaryForReferenceSequence(fastaPath.toPath()); if (Files.exists(dictPath)) { - referenceBundleBuilder.addSecondary( - new IOPathResource( - ioPathConstructor.apply(dictPath.toUri().toString()), - BundleResourceType.CT_REFERENCE_DICTIONARY)); + referenceBundleBuilder.addSecondary(new IOPathResource( + ioPathConstructor.apply(dictPath.toUri().toString()), BundleResourceType.CT_REFERENCE_DICTIONARY)); } final Path idxPath = ReferenceSequenceFileFactory.getFastaIndexFileName(fastaPath.toPath()); if (Files.exists(idxPath)) { - referenceBundleBuilder.addSecondary( - new IOPathResource( - ioPathConstructor.apply(idxPath.toUri().toString()), - BundleResourceType.CT_REFERENCE_INDEX)); + referenceBundleBuilder.addSecondary(new IOPathResource( + ioPathConstructor.apply(idxPath.toUri().toString()), BundleResourceType.CT_REFERENCE_INDEX)); } try { if (IOUtil.isBlockCompressed(fastaPath.toPath(), true)) { final Path gziPath = GZIIndex.resolveIndexNameForBgzipFile(fastaPath.toPath()); - referenceBundleBuilder.addSecondary( - new IOPathResource( - ioPathConstructor.apply(gziPath.toUri().toString()), - BundleResourceType.CT_REFERENCE_INDEX_GZI)); + referenceBundleBuilder.addSecondary(new IOPathResource( + ioPathConstructor.apply(gziPath.toUri().toString()), + BundleResourceType.CT_REFERENCE_INDEX_GZI)); } } catch (IOException e) { throw new HtsjdkException("Error while checking for block compression", e); } return referenceBundleBuilder.build(); } - } diff --git a/src/main/java/htsjdk/beta/plugin/registry/HtsCodecRegistry.java b/src/main/java/htsjdk/beta/plugin/registry/HtsCodecRegistry.java index 9ee13a3c68..ad226c9f17 100644 --- a/src/main/java/htsjdk/beta/plugin/registry/HtsCodecRegistry.java +++ b/src/main/java/htsjdk/beta/plugin/registry/HtsCodecRegistry.java @@ -1,11 +1,12 @@ package htsjdk.beta.plugin.registry; +import htsjdk.beta.exception.HtsjdkPluginException; +import htsjdk.beta.exception.HtsjdkUnsupportedOperationException; import htsjdk.beta.plugin.HtsCodec; import htsjdk.beta.plugin.hapref.HaploidReferenceCodec; import htsjdk.beta.plugin.reads.ReadsCodec; import htsjdk.beta.plugin.variants.VariantsCodec; -import htsjdk.beta.exception.HtsjdkPluginException; -import htsjdk.beta.exception.HtsjdkUnsupportedOperationException; + /** * A registry for tracking {@link HtsCodec} instances. *

@@ -26,7 +27,7 @@ public class HtsCodecRegistry { * Create a registry. Protected to prevent use outside of the registry package. To create * a private registry from outside the registry package, use {@link #createPrivateRegistry}. */ - protected HtsCodecRegistry() { } + protected HtsCodecRegistry() {} /** * Add a codec to the registry. If a codec that supports the same (format, version) (determined @@ -66,15 +67,21 @@ protected HtsCodecRegistry() { } * * @return a mutable registry instance for private use */ - public synchronized static HtsCodecRegistry createPrivateRegistry() { + public static synchronized HtsCodecRegistry createPrivateRegistry() { final HtsCodecRegistry privateRegistry = new HtsCodecRegistry(); // propagate the codecs from the sourceRegistry to the new registry - HtsDefaultRegistry.htsDefaultCodecRegistry.getHaploidReferenceResolver().getCodecs() + HtsDefaultRegistry.htsDefaultCodecRegistry + .getHaploidReferenceResolver() + .getCodecs() + .forEach(c -> privateRegistry.registerCodec(c)); + HtsDefaultRegistry.htsDefaultCodecRegistry + .getReadsResolver() + .getCodecs() .forEach(c -> privateRegistry.registerCodec(c)); - HtsDefaultRegistry.htsDefaultCodecRegistry.getReadsResolver().getCodecs(). - forEach(c -> privateRegistry.registerCodec(c)); - HtsDefaultRegistry.htsDefaultCodecRegistry.getVariantsResolver().getCodecs() + HtsDefaultRegistry.htsDefaultCodecRegistry + .getVariantsResolver() + .getCodecs() .forEach(c -> privateRegistry.registerCodec(c)); return privateRegistry; } @@ -84,21 +91,25 @@ public synchronized static HtsCodecRegistry createPrivateRegistry() { * * @return the {@link HaploidReferenceResolver} for this registry */ - public synchronized HaploidReferenceResolver getHaploidReferenceResolver() { return htsHaploidReferenceResolver; } + public synchronized HaploidReferenceResolver getHaploidReferenceResolver() { + return htsHaploidReferenceResolver; + } /** * Get the {@link ReadsResolver} for this registry. * * @return the {@link ReadsResolver} for this registry */ - public synchronized ReadsResolver getReadsResolver() { return htsReadsResolver; } + public synchronized ReadsResolver getReadsResolver() { + return htsReadsResolver; + } /** * Get the {@link VariantsResolver} for this registry. * * @return the {@link VariantsResolver} for this registry */ - public synchronized VariantsResolver getVariantsResolver() { return htsVariantsResolver; } - + public synchronized VariantsResolver getVariantsResolver() { + return htsVariantsResolver; + } } - diff --git a/src/main/java/htsjdk/beta/plugin/registry/HtsCodecResolver.java b/src/main/java/htsjdk/beta/plugin/registry/HtsCodecResolver.java index dbfc7d7ed2..cd83db6b4e 100644 --- a/src/main/java/htsjdk/beta/plugin/registry/HtsCodecResolver.java +++ b/src/main/java/htsjdk/beta/plugin/registry/HtsCodecResolver.java @@ -1,18 +1,17 @@ package htsjdk.beta.plugin.registry; +import htsjdk.annotations.InternalAPI; +import htsjdk.beta.exception.HtsjdkException; import htsjdk.beta.exception.HtsjdkIOException; -import htsjdk.beta.plugin.HtsCodec; -import htsjdk.beta.plugin.HtsVersion; +import htsjdk.beta.exception.HtsjdkPluginException; import htsjdk.beta.io.bundle.Bundle; import htsjdk.beta.io.bundle.BundleResource; import htsjdk.beta.io.bundle.SignatureStream; -import htsjdk.beta.exception.HtsjdkException; -import htsjdk.beta.exception.HtsjdkPluginException; +import htsjdk.beta.plugin.HtsCodec; +import htsjdk.beta.plugin.HtsVersion; import htsjdk.io.IOPath; import htsjdk.samtools.util.Log; -import htsjdk.annotations.InternalAPI; import htsjdk.utils.ValidationUtils; - import java.io.IOException; import java.util.Collections; import java.util.HashMap; @@ -37,8 +36,8 @@ public class HtsCodecResolver> { private static final Log LOG = Log.getInstance(HtsCodecResolver.class); - final static String NO_SUPPORTING_CODEC_ERROR = "No registered codec accepts the provided resource"; - final static String MULTIPLE_SUPPORTING_CODECS_ERROR = "Multiple codecs accept the provided resource"; + static final String NO_SUPPORTING_CODEC_ERROR = "No registered codec accepts the provided resource"; + static final String MULTIPLE_SUPPORTING_CODECS_ERROR = "Multiple codecs accept the provided resource"; private final String requiredContentType; private final Map> codecs = new HashMap<>(); @@ -75,9 +74,9 @@ public C registerCodec(final C codec) { // update the version map for this codec final C oldCodec = versionMap.put(codec.getVersion(), codec); if (oldCodec != null) { - LOG.warn(String.format("A previously registered HTS codec (%s) was replaced with the (%s) codec ", - oldCodec.getDisplayName(), - codec.getDisplayName())); + LOG.warn(String.format( + "A previously registered HTS codec (%s) was replaced with the (%s) codec ", + oldCodec.getDisplayName(), codec.getDisplayName())); } return oldCodec; } @@ -149,15 +148,14 @@ public C resolveForDecoding(final Bundle bundle) { final Optional optFormatString = bundleResource.getFileFormat(); final List candidateCodecs = resolveForFormat(optFormatString); - final List resolvedCodecs = bundleResource.getIOPath().isPresent() ? - resolveForDecodingIOPath(bundleResource, candidateCodecs) : - resolveForDecodingStream(bundleResource, candidateCodecs); + final List resolvedCodecs = bundleResource.getIOPath().isPresent() + ? resolveForDecodingIOPath(bundleResource, candidateCodecs) + : resolveForDecodingStream(bundleResource, candidateCodecs); return getOneOrThrow( resolvedCodecs, - () -> String.format("%s/%s", - optFormatString.isPresent () ? optFormatString.get() : "(NONE)", - bundleResource)); + () -> String.format( + "%s/%s", optFormatString.isPresent() ? optFormatString.get() : "(NONE)", bundleResource)); } /** @@ -180,7 +178,9 @@ public C resolveForDecoding(final Bundle bundle) { * @throws HtsjdkPluginException if more than one codec claims to handle the resource. this usually indicates * that the registry contains an incorrectly written codec. */ - public C resolveForEncoding(final Bundle bundle) { return resolveForEncoding(bundle, HtsVersion.NEWEST_VERSION); } + public C resolveForEncoding(final Bundle bundle) { + return resolveForEncoding(bundle, HtsVersion.NEWEST_VERSION); + } /** * Inspect a bundle and find a codec that can encode to the primary resource using the format version @@ -208,16 +208,15 @@ public C resolveForEncoding(final Bundle bundle, final HtsVersion htsVersion) { final List candidateCodecs = resolveForFormat(optFormatString); final Optional ioPath = bundleResource.getIOPath(); - final List filteredCodecs = bundleResource.getIOPath().isPresent() ? - resolveForEncodingIOPath(ioPath.get(), candidateCodecs) : - candidateCodecs; // there isn't anything else to probe when the output is to a stream + final List filteredCodecs = bundleResource.getIOPath().isPresent() + ? resolveForEncodingIOPath(ioPath.get(), candidateCodecs) + : candidateCodecs; // there isn't anything else to probe when the output is to a stream final List resolvedCodecs = filterByVersion(filteredCodecs, htsVersion); return getOneOrThrow( resolvedCodecs, - () -> String.format("%s/%s", - optFormatString.isPresent () ? optFormatString.get() : "(NONE)", - bundleResource)); + () -> String.format( + "%s/%s", optFormatString.isPresent() ? optFormatString.get() : "(NONE)", bundleResource)); } /** @@ -245,9 +244,9 @@ public List resolveForFormat(final String format) { * @throws HtsjdkException if no registered codecs can handle the resource */ public C resolveFormatAndVersion(final String format, final HtsVersion formatVersion) { - final List matchingCodecs = resolveForFormat(format) - .stream() - .filter(codec -> codec.getFileFormat().equals(format) && codec.getVersion().equals(formatVersion)) + final List matchingCodecs = resolveForFormat(format).stream() + .filter(codec -> codec.getFileFormat().equals(format) + && codec.getVersion().equals(formatVersion)) .collect(Collectors.toList()); return getOneOrThrow(matchingCodecs, () -> String.format("%s/%s", format, formatVersion)); } @@ -259,11 +258,8 @@ public C resolveFormatAndVersion(final String format, final HtsVersion formatVer */ public List getCodecs() { // flatten out the codecs into a single list - final List codecList = codecs - .values() - .stream() - .flatMap(map -> map.values().stream()) - .collect(Collectors.toList()); + final List codecList = + codecs.values().stream().flatMap(map -> map.values().stream()).collect(Collectors.toList()); return codecList; } @@ -296,35 +292,28 @@ private List resolveForDecodingStream(final BundleResource bundleResource, fi final byte[] signatureBuffer = getSignatureProbeBuffer(bundleResource, candidateCodecs); return candidateCodecs.stream() .filter(codec -> codec.canDecodeSignature( - new SignatureStream(signatureBuffer.length, signatureBuffer), - bundleResource.getDisplayName())) + new SignatureStream(signatureBuffer.length, signatureBuffer), bundleResource.getDisplayName())) .collect(Collectors.toList()); } - private final byte[] getSignatureProbeBuffer( - final BundleResource bundleResource, - final List candidateCodecs) { + private final byte[] getSignatureProbeBuffer(final BundleResource bundleResource, final List candidateCodecs) { final int maxSignatureProbeLength = getMaxSignatureProbeLength(candidateCodecs); - try (final SignatureStream probingStream = - bundleResource.getIOPath().isPresent() ? - getIOPathSignatureProbingStream(bundleResource, maxSignatureProbeLength) : - bundleResource.getSignatureStream(maxSignatureProbeLength)) { + try (final SignatureStream probingStream = bundleResource.getIOPath().isPresent() + ? getIOPathSignatureProbingStream(bundleResource, maxSignatureProbeLength) + : bundleResource.getSignatureStream(maxSignatureProbeLength)) { // we need to recreate a stream over the underlying signature for each codec, // since some implementations may use their own mark/reset pairs final byte[] signatureBytes = new byte[probingStream.getSignaturePrefixLength()]; final int readSize = probingStream.read(signatureBytes); if (readSize != maxSignatureProbeLength) { - throw new HtsjdkPluginException( - String.format("Failure to read %d bytes from signature stream for %s (only read %d)", - maxSignatureProbeLength, - bundleResource, - readSize)); + throw new HtsjdkPluginException(String.format( + "Failure to read %d bytes from signature stream for %s (only read %d)", + maxSignatureProbeLength, bundleResource, readSize)); } return signatureBytes; } catch (IOException e) { throw new HtsjdkIOException( - String.format("error closing signature stream for %s", bundleResource.getDisplayName()), - e); + String.format("error closing signature stream for %s", bundleResource.getDisplayName()), e); } } @@ -339,21 +328,19 @@ private List resolveForEncodingIOPath(final IOPath ioPath, final List cand final List filteredCodecs = uriHandlers.isEmpty() ? candidateCodecs : uriHandlers; // reduce our candidates based on uri and IOPath - return filteredCodecs.stream() - .filter(c -> c.canDecodeURI(ioPath)) - .collect(Collectors.toList()); + return filteredCodecs.stream().filter(c -> c.canDecodeURI(ioPath)).collect(Collectors.toList()); } private int getMaxSignatureProbeLength(final List candidateCodecs) { // find the longest signature probe length of any candidate return candidateCodecs.stream() .map(codec -> codec.getSignatureProbeLength()) - .max(Integer::compare).orElse(0); + .max(Integer::compare) + .orElse(0); } private SignatureStream getIOPathSignatureProbingStream( - final BundleResource bundleResource, - final int streamPrefixSize) { + final BundleResource bundleResource, final int streamPrefixSize) { ValidationUtils.validateArg(bundleResource.getIOPath().isPresent(), "an IOPath resource is required"); final IOPath inputPath = bundleResource.getIOPath().get(); if (!inputPath.hasFileSystemProvider()) { @@ -364,11 +351,10 @@ private SignatureStream getIOPathSignatureProbingStream( // "claimURI" implementations, or else it would be a known protocol such as "gs://" for // which the user expected a file system to be present. It likely represents user error // (a user entered "hdf://" instead of "hdfs://"), and it will fail anyway, so throw. - throw new IllegalArgumentException( - String.format("The resource (%s) specifies a custom protocol (%s) " + - "which no registered codec claims, and for which no NIO file system provider is available", - bundleResource, - inputPath.getURI().getScheme())); + throw new IllegalArgumentException(String.format( + "The resource (%s) specifies a custom protocol (%s) " + + "which no registered codec claims, and for which no NIO file system provider is available", + bundleResource, inputPath.getURI().getScheme())); } return bundleResource.getSignatureStream(streamPrefixSize); } @@ -387,10 +373,12 @@ protected List filterByVersion(final List candidateCodecs, final HtsVersio // version (since there still can be more than one) final HtsVersion newestVersion = candidateCodecs.stream() .map(c -> c.getVersion()) - .reduce(candidateCodecs.get(0).getVersion(), + .reduce( + candidateCodecs.get(0).getVersion(), (HtsVersion a, HtsVersion b) -> a.compareTo(b) > 0 ? a : b); - return candidateCodecs.stream().filter( - c -> c.getVersion().equals(newestVersion)).collect(Collectors.toList()); + return candidateCodecs.stream() + .filter(c -> c.getVersion().equals(newestVersion)) + .collect(Collectors.toList()); } else { return candidateCodecs.stream() .filter(c -> c.getVersion().equals(htsVersion)) @@ -402,17 +390,13 @@ protected List filterByVersion(final List candidateCodecs, final HtsVersio // or otherwise all registered codecs for this codec format. private List resolveForFormat(final Optional optFormatString) { final List candidateCodecs = - optFormatString.isPresent() ? - resolveForFormat(optFormatString.get()) : - getCodecs(); + optFormatString.isPresent() ? resolveForFormat(optFormatString.get()) : getCodecs(); if (optFormatString.isPresent() && candidateCodecs.isEmpty()) { // warn if the resource format string is present, but doesn't map to any codec registered // with this resolver (/content type). LOG.warn(String.format( "The specified format string (%s) does not correspond to any registered codec for content type (%s)", - optFormatString.get(), - requiredContentType)); - + optFormatString.get(), requiredContentType)); } return candidateCodecs; } @@ -426,14 +410,13 @@ private List getURIOwners(final List candidateCodecs, final IOPath ioPath) if (isCustomURI) { // ensure that all codecs that claim to own this URI honor the contract that says if canDecodeURI // returns true, ownsURI must also return true for the same IOPath - uriHandlers.stream().forEach( - codec -> { - if (!codec.canDecodeURI(ioPath)) { - throw new HtsjdkPluginException( - String.format("The %s codec returned true for ownsURI but false for canDecodeURI for path: %s", - codec, - ioPath.getURI())); - }}); + uriHandlers.stream().forEach(codec -> { + if (!codec.canDecodeURI(ioPath)) { + throw new HtsjdkPluginException(String.format( + "The %s codec returned true for ownsURI but false for canDecodeURI for path: %s", + codec, ioPath.getURI())); + } + }); } return uriHandlers; } @@ -446,21 +429,18 @@ private final BundleResource getPrimaryResource(final Bundle bundle, final boole if (!requiredContentType.equals(bundlePrimaryContentType)) { throw new IllegalArgumentException(String.format( "The primary content type (%s) for the resource does not match the requested content type (%s).", - bundlePrimaryContentType, - requiredContentType)); + bundlePrimaryContentType, requiredContentType)); } // Make sure the resource type is appropriate for encoding or decoding, as requested by the caller if (forEncoding && !bundleResource.hasInputType()) { - throw new IllegalArgumentException( - String.format("The %s resource found (%s) cannot be used as an input resource", - requiredContentType, - bundleResource)); + throw new IllegalArgumentException(String.format( + "The %s resource found (%s) cannot be used as an input resource", + requiredContentType, bundleResource)); } else if (!forEncoding && !bundleResource.hasOutputType()) { // for decoding - throw new IllegalArgumentException( - String.format("The %s resource found (%s) cannot be used as an output resource", - requiredContentType, - bundleResource)); + throw new IllegalArgumentException(String.format( + "The %s resource found (%s) cannot be used as an output resource", + requiredContentType, bundleResource)); } return bundleResource; @@ -468,13 +448,9 @@ private final BundleResource getPrimaryResource(final Bundle bundle, final boole @InternalAPI static > C getOneOrThrow( - final List resolvedCodecs, - final Supplier contextMessage) { + final List resolvedCodecs, final Supplier contextMessage) { if (resolvedCodecs.size() == 0) { - throw new HtsjdkException(String.format( - "%s %s", - NO_SUPPORTING_CODEC_ERROR, - contextMessage.get())); + throw new HtsjdkException(String.format("%s %s", NO_SUPPORTING_CODEC_ERROR, contextMessage.get())); } else if (resolvedCodecs.size() > 1) { final String multipleCodecsMessage = String.format( "%s (%s)\n%s\nThis indicates an internal error in one or more of the codecs:", @@ -486,5 +462,4 @@ private final BundleResource getPrimaryResource(final Bundle bundle, final boole return resolvedCodecs.get(0); } } - } diff --git a/src/main/java/htsjdk/beta/plugin/registry/HtsDefaultRegistry.java b/src/main/java/htsjdk/beta/plugin/registry/HtsDefaultRegistry.java index 6a14758668..a241221399 100644 --- a/src/main/java/htsjdk/beta/plugin/registry/HtsDefaultRegistry.java +++ b/src/main/java/htsjdk/beta/plugin/registry/HtsDefaultRegistry.java @@ -17,7 +17,9 @@ public class HtsDefaultRegistry { /** * statically populate the default registry with any codecs on the classpath */ - static {ServiceLoader.load(HtsCodec.class).forEach(htsDefaultCodecRegistry::registerCodec);} + static { + ServiceLoader.load(HtsCodec.class).forEach(htsDefaultCodecRegistry::registerCodec); + } /** * Grt the {@link HaploidReferenceResolver} resolver for this registry. @@ -25,7 +27,8 @@ public class HtsDefaultRegistry { * @return the {@link HaploidReferenceResolver} resolver for this registry */ public static synchronized HaploidReferenceResolver getHaploidReferenceResolver() { - return htsDefaultCodecRegistry.getHaploidReferenceResolver(); } + return htsDefaultCodecRegistry.getHaploidReferenceResolver(); + } /** * Gt the {@link ReadsResolver} resolver for this registry. @@ -33,7 +36,8 @@ public static synchronized HaploidReferenceResolver getHaploidReferenceResolver( * @return the {@link ReadsResolver} resolver for this registry */ public static synchronized ReadsResolver getReadsResolver() { - return htsDefaultCodecRegistry.getReadsResolver(); } + return htsDefaultCodecRegistry.getReadsResolver(); + } /** * Get the {@link VariantsResolver} resolver for this registry. @@ -41,6 +45,6 @@ public static synchronized ReadsResolver getReadsResolver() { * @return the {@link VariantsResolver} resolver for this registry */ public static synchronized VariantsResolver getVariantsResolver() { - return htsDefaultCodecRegistry.getVariantsResolver(); } - + return htsDefaultCodecRegistry.getVariantsResolver(); + } } diff --git a/src/main/java/htsjdk/beta/plugin/registry/ReadsResolver.java b/src/main/java/htsjdk/beta/plugin/registry/ReadsResolver.java index b89ffc4a10..90fb0796c2 100644 --- a/src/main/java/htsjdk/beta/plugin/registry/ReadsResolver.java +++ b/src/main/java/htsjdk/beta/plugin/registry/ReadsResolver.java @@ -2,9 +2,9 @@ import htsjdk.beta.exception.HtsjdkException; import htsjdk.beta.exception.HtsjdkPluginException; -import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.io.bundle.Bundle; import htsjdk.beta.io.bundle.BundleResourceType; +import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.reads.ReadsBundle; import htsjdk.beta.plugin.reads.ReadsCodec; import htsjdk.beta.plugin.reads.ReadsDecoder; @@ -25,7 +25,7 @@ * {@link ReadsCodec}s, such as {@link ReadsDecoder}, {@link ReadsEncoder}, * {@link htsjdk.beta.plugin.reads.ReadsDecoderOptions}. */ -public class ReadsResolver extends HtsCodecResolver{ +public class ReadsResolver extends HtsCodecResolver { /** * Create a ReadsResolver. @@ -64,9 +64,7 @@ public ReadsDecoder getReadsDecoder(final IOPath inputPath) { * @throws HtsjdkPluginException if more than one codec claims to handle the resource. this usually indicates * that the registry contains an incorrectly written codec. */ - public ReadsDecoder getReadsDecoder( - final IOPath inputPath, - final ReadsDecoderOptions readsDecoderOptions) { + public ReadsDecoder getReadsDecoder(final IOPath inputPath, final ReadsDecoderOptions readsDecoderOptions) { ValidationUtils.nonNull(inputPath, "Input path"); ValidationUtils.nonNull(readsDecoderOptions, "Decoder options"); @@ -102,9 +100,7 @@ public ReadsDecoder getReadsDecoder(final Bundle inputBundle) { * that the registry contains an incorrectly written codec. */ @SuppressWarnings("unchecked") - public ReadsDecoder getReadsDecoder( - final Bundle inputBundle, - final ReadsDecoderOptions readsDecoderOptions) { + public ReadsDecoder getReadsDecoder(final Bundle inputBundle, final ReadsDecoderOptions readsDecoderOptions) { ValidationUtils.nonNull(inputBundle, "Input bundle"); ValidationUtils.nonNull(readsDecoderOptions, "Decoder options"); @@ -143,9 +139,7 @@ public ReadsEncoder getReadsEncoder(final IOPath outputPath) { * @throws HtsjdkPluginException if more than one codec claims to handle the resource. this usually indicates * that the registry contains an incorrectly written codec. */ - public ReadsEncoder getReadsEncoder( - final IOPath outputPath, - final ReadsEncoderOptions readsEncoderOptions) { + public ReadsEncoder getReadsEncoder(final IOPath outputPath, final ReadsEncoderOptions readsEncoderOptions) { ValidationUtils.nonNull(outputPath, "Output path"); ValidationUtils.nonNull(readsEncoderOptions, "Encoder options"); @@ -168,9 +162,7 @@ public ReadsEncoder getReadsEncoder( * that the registry contains an incorrectly written codec. */ @SuppressWarnings("unchecked") - public ReadsEncoder getReadsEncoder( - final Bundle outputBundle, - final ReadsEncoderOptions readsEncoderOptions) { + public ReadsEncoder getReadsEncoder(final Bundle outputBundle, final ReadsEncoderOptions readsEncoderOptions) { ValidationUtils.nonNull(outputBundle, "outputBundle"); ValidationUtils.nonNull(readsEncoderOptions, "Encoder options"); @@ -200,8 +192,7 @@ public ReadsEncoder getReadsEncoder( ValidationUtils.nonNull(readsFormat, "Reads format"); ValidationUtils.nonNull(formatVersion, "File format version"); - return (ReadsEncoder) resolveFormatAndVersion(readsFormat, formatVersion) - .getEncoder(outputBundle, readsEncoderOptions); + return (ReadsEncoder) + resolveFormatAndVersion(readsFormat, formatVersion).getEncoder(outputBundle, readsEncoderOptions); } - } diff --git a/src/main/java/htsjdk/beta/plugin/registry/VariantsResolver.java b/src/main/java/htsjdk/beta/plugin/registry/VariantsResolver.java index dd8841377e..e755fa219c 100644 --- a/src/main/java/htsjdk/beta/plugin/registry/VariantsResolver.java +++ b/src/main/java/htsjdk/beta/plugin/registry/VariantsResolver.java @@ -3,11 +3,11 @@ import htsjdk.beta.codecs.variants.vcf.vcfv4_2.VCFCodecV4_2; import htsjdk.beta.exception.HtsjdkException; import htsjdk.beta.exception.HtsjdkPluginException; -import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.io.bundle.Bundle; import htsjdk.beta.io.bundle.BundleBuilder; import htsjdk.beta.io.bundle.BundleResourceType; import htsjdk.beta.io.bundle.IOPathResource; +import htsjdk.beta.plugin.HtsVersion; import htsjdk.beta.plugin.variants.VariantsCodec; import htsjdk.beta.plugin.variants.VariantsDecoder; import htsjdk.beta.plugin.variants.VariantsDecoderOptions; @@ -62,8 +62,7 @@ public VariantsDecoder getVariantsDecoder(final IOPath inputPath) { * that the registry contains an incorrectly written codec. */ public VariantsDecoder getVariantsDecoder( - final IOPath inputPath, - final VariantsDecoderOptions variantsDecoderOptions) { + final IOPath inputPath, final VariantsDecoderOptions variantsDecoderOptions) { ValidationUtils.nonNull(inputPath, "Input path"); ValidationUtils.nonNull(variantsDecoderOptions, "Decoder options"); @@ -102,8 +101,7 @@ public VariantsDecoder getVariantsDecoder(final Bundle inputBundle) { */ @SuppressWarnings("unchecked") public VariantsDecoder getVariantsDecoder( - final Bundle inputBundle, - final VariantsDecoderOptions variantsDecoderOptions) { + final Bundle inputBundle, final VariantsDecoderOptions variantsDecoderOptions) { ValidationUtils.nonNull(inputBundle, "Input bundle"); ValidationUtils.nonNull(variantsDecoderOptions, "Decoder options"); @@ -137,8 +135,7 @@ public VariantsEncoder getVariantsEncoder(final IOPath outputPath) { * that the registry contains an incorrectly written codec. */ public VariantsEncoder getVariantsEncoder( - final IOPath outputPath, - final VariantsEncoderOptions variantsEncoderOptions) { + final IOPath outputPath, final VariantsEncoderOptions variantsEncoderOptions) { ValidationUtils.nonNull(outputPath, "Output path"); ValidationUtils.nonNull(variantsEncoderOptions, "Encoder options"); @@ -159,12 +156,11 @@ public VariantsEncoder getVariantsEncoder( * that the registry contains an incorrectly written codec. */ public VariantsEncoder getVariantsEncoder( - final Bundle outputBundle, - final VariantsEncoderOptions variantsEncoderOptions) { + final Bundle outputBundle, final VariantsEncoderOptions variantsEncoderOptions) { ValidationUtils.nonNull(outputBundle, "Output bundle"); ValidationUtils.nonNull(variantsEncoderOptions, "Encoder options"); - //NOTE: we can't allow the resolver to choose the newest registered codec when writing a + // NOTE: we can't allow the resolver to choose the newest registered codec when writing a // VCF, since the newest codec is v4.3, which has no encoder, so for now explicitly select v4.2 final VariantsCodec variantsCodec = resolveForEncoding(outputBundle, VCFCodecV4_2.VCF_V42_VERSION); return (VariantsEncoder) variantsCodec.getEncoder(outputBundle, variantsEncoderOptions); @@ -194,8 +190,7 @@ public VariantsEncoder getVariantsEncoder( ValidationUtils.nonNull(variantsFormat, "Format"); ValidationUtils.nonNull(formatVersion, "Format version"); - return (VariantsEncoder) resolveFormatAndVersion(variantsFormat, formatVersion) - .getEncoder(outputBundle, variantsEncoderOptions); + return (VariantsEncoder) + resolveFormatAndVersion(variantsFormat, formatVersion).getEncoder(outputBundle, variantsEncoderOptions); } - } diff --git a/src/main/java/htsjdk/beta/plugin/variants/VariantsBundle.java b/src/main/java/htsjdk/beta/plugin/variants/VariantsBundle.java index 2a8dae15e4..128d0d2840 100644 --- a/src/main/java/htsjdk/beta/plugin/variants/VariantsBundle.java +++ b/src/main/java/htsjdk/beta/plugin/variants/VariantsBundle.java @@ -8,7 +8,6 @@ import htsjdk.samtools.util.Log; import htsjdk.samtools.util.Tuple; import htsjdk.utils.ValidationUtils; - import java.io.Serial; import java.io.Serializable; import java.nio.file.Files; @@ -30,6 +29,7 @@ public class VariantsBundle extends Bundle implements Serializable { @Serial private static final long serialVersionUID = 1L; + private static final Log LOG = Log.getInstance(VariantsBundle.class); /** @@ -108,8 +108,8 @@ public static VariantsBundle getVariantsBundleFromPath(final IOPath jsonPath) { * @param ioPathConstructor a function that takes a string and returns an IOPath-derived class of type {@code T} * @return a {@link VariantsBundle} created from jsonPath */ - public static VariantsBundle getVariantsBundleFromPath(final IOPath jsonPath, - final Function ioPathConstructor) { + public static VariantsBundle getVariantsBundleFromPath( + final IOPath jsonPath, final Function ioPathConstructor) { return getVariantsBundleFromString(IOPathUtils.getStringFromPath(jsonPath), ioPathConstructor); } @@ -133,9 +133,9 @@ public static VariantsBundle getVariantsBundleFromString(final String jsonString * @return a newly created {@link htsjdk.beta.plugin.variants.VariantsBundle} */ public static VariantsBundle getVariantsBundleFromString( - final String jsonString, - final Function ioPathConstructor) { - return new VariantsBundle(BundleJSON.toBundle(jsonString, ioPathConstructor).getResources()); + final String jsonString, final Function ioPathConstructor) { + return new VariantsBundle( + BundleJSON.toBundle(jsonString, ioPathConstructor).getResources()); } /** @@ -166,8 +166,7 @@ public static Optional resolveIndex(final IOPath variants) { * if it can be found */ public static Optional resolveIndex( - final T variantsHtsPath, - final Function ioPathConstructor) { + final T variantsHtsPath, final Function ioPathConstructor) { final Set indexExtensions = Set.of(FileExtensions.TRIBBLE_INDEX, FileExtensions.TABIX_INDEX); for (final String extension : indexExtensions) { final T putativeIndexPath = IOPathUtils.appendExtension(variantsHtsPath, extension, ioPathConstructor); @@ -185,9 +184,7 @@ private static IOPathResource toInputResource(final String pr if (providedContentType != null && !typePair.get().a.equals(providedContentType)) { LOG.warn(String.format( "Provided content type \"%s\" for \"%s\" doesn't match derived content type \"%s\"", - providedContentType, - ioPath.getRawInputString(), - typePair.get().a)); + providedContentType, ioPath.getRawInputString(), typePair.get().a)); } } return new IOPathResource(ioPath, providedContentType); @@ -206,9 +203,11 @@ private static Optional> getInferredCon if (extension.isPresent()) { final String ext = extension.get(); if (ext.equals(FileExtensions.VCF)) { - return Optional.of(new Tuple<>(BundleResourceType.CT_VARIANT_CONTEXTS, BundleResourceType.FMT_VARIANTS_VCF)); + return Optional.of( + new Tuple<>(BundleResourceType.CT_VARIANT_CONTEXTS, BundleResourceType.FMT_VARIANTS_VCF)); } else if (ext.equals(FileExtensions.COMPRESSED_VCF) || ext.equals(FileExtensions.COMPRESSED_VCF_BGZ)) { - return Optional.of(new Tuple<>(BundleResourceType.CT_VARIANT_CONTEXTS, BundleResourceType.FMT_VARIANTS_VCF)); + return Optional.of( + new Tuple<>(BundleResourceType.CT_VARIANT_CONTEXTS, BundleResourceType.FMT_VARIANTS_VCF)); } } return Optional.empty(); diff --git a/src/main/java/htsjdk/beta/plugin/variants/VariantsCodec.java b/src/main/java/htsjdk/beta/plugin/variants/VariantsCodec.java index 97cc39306b..76591b3f5c 100644 --- a/src/main/java/htsjdk/beta/plugin/variants/VariantsCodec.java +++ b/src/main/java/htsjdk/beta/plugin/variants/VariantsCodec.java @@ -9,6 +9,7 @@ public interface VariantsCodec extends HtsCodec { @Override - default HtsContentType getContentType() { return HtsContentType.VARIANT_CONTEXTS; } - + default HtsContentType getContentType() { + return HtsContentType.VARIANT_CONTEXTS; + } } diff --git a/src/main/java/htsjdk/beta/plugin/variants/VariantsDecoder.java b/src/main/java/htsjdk/beta/plugin/variants/VariantsDecoder.java index 1d19461c1c..420388fcdb 100644 --- a/src/main/java/htsjdk/beta/plugin/variants/VariantsDecoder.java +++ b/src/main/java/htsjdk/beta/plugin/variants/VariantsDecoder.java @@ -8,4 +8,4 @@ /** * Base class for all {@link HtsContentType#VARIANT_CONTEXTS} decoders. */ -public interface VariantsDecoder extends HtsDecoder { } +public interface VariantsDecoder extends HtsDecoder {} diff --git a/src/main/java/htsjdk/beta/plugin/variants/VariantsDecoderOptions.java b/src/main/java/htsjdk/beta/plugin/variants/VariantsDecoderOptions.java index 46a2abad5a..9a112c2dff 100644 --- a/src/main/java/htsjdk/beta/plugin/variants/VariantsDecoderOptions.java +++ b/src/main/java/htsjdk/beta/plugin/variants/VariantsDecoderOptions.java @@ -1,14 +1,13 @@ package htsjdk.beta.plugin.variants; -import htsjdk.beta.plugin.HtsDecoderOptions; import htsjdk.annotations.InternalAPI; - +import htsjdk.beta.plugin.HtsDecoderOptions; import java.nio.channels.SeekableByteChannel; import java.util.Optional; import java.util.function.Function; public class VariantsDecoderOptions implements HtsDecoderOptions { - //TODO: replace these with a prefetch size args, and use a local channel wrapper implementation + // TODO: replace these with a prefetch size args, and use a local channel wrapper implementation private Function variantsChannelTransformer; private Function indexChannelTransformer; @@ -63,5 +62,4 @@ public VariantsDecoderOptions setIndexChannelTransformer( this.indexChannelTransformer = indexChannelTransformer; return this; } - } diff --git a/src/main/java/htsjdk/beta/plugin/variants/VariantsEncoder.java b/src/main/java/htsjdk/beta/plugin/variants/VariantsEncoder.java index 9840047e69..932f3deea2 100644 --- a/src/main/java/htsjdk/beta/plugin/variants/VariantsEncoder.java +++ b/src/main/java/htsjdk/beta/plugin/variants/VariantsEncoder.java @@ -8,4 +8,4 @@ /** * Base class for all {@link HtsContentType#VARIANT_CONTEXTS} encoders. */ -public interface VariantsEncoder extends HtsEncoder { } +public interface VariantsEncoder extends HtsEncoder {} diff --git a/src/main/java/htsjdk/beta/plugin/variants/VariantsEncoderOptions.java b/src/main/java/htsjdk/beta/plugin/variants/VariantsEncoderOptions.java index 94182dc4d3..0b09fd3335 100644 --- a/src/main/java/htsjdk/beta/plugin/variants/VariantsEncoderOptions.java +++ b/src/main/java/htsjdk/beta/plugin/variants/VariantsEncoderOptions.java @@ -6,12 +6,11 @@ import htsjdk.samtools.Defaults; public class VariantsEncoderOptions implements HtsEncoderOptions { - private boolean writeSitesOnly = false; - private boolean writeFullFormatField = false; - private boolean allowFieldsMissingFromHeader = false; - private boolean isAsyncIO = false; - private int bufferSize = Defaults.NON_ZERO_BUFFER_SIZE; // 128k - + private boolean writeSitesOnly = false; + private boolean writeFullFormatField = false; + private boolean allowFieldsMissingFromHeader = false; + private boolean isAsyncIO = false; + private int bufferSize = Defaults.NON_ZERO_BUFFER_SIZE; // 128k /** * Get the buffer size used when writing to an {@link IOPathResource}. Defaults @@ -115,5 +114,4 @@ public VariantsEncoderOptions setWriteFullFormatField(boolean writeFullFormatFie this.writeFullFormatField = writeFullFormatField; return this; } - } diff --git a/src/main/java/htsjdk/io/AsyncWriterPool.java b/src/main/java/htsjdk/io/AsyncWriterPool.java index f95bcbc7db..dab043ce39 100644 --- a/src/main/java/htsjdk/io/AsyncWriterPool.java +++ b/src/main/java/htsjdk/io/AsyncWriterPool.java @@ -1,7 +1,6 @@ package htsjdk.io; import htsjdk.samtools.util.RuntimeIOException; - import java.io.Closeable; import java.io.IOException; import java.util.ArrayList; @@ -21,7 +20,6 @@ public class AsyncWriterPool implements Closeable { private final ExecutorService executor; private final List> writers = new ArrayList<>(); - // The amount of time to wait on the queue in the event of catastrophic failure in the writer threads. private int timeoutSeconds = 5; @@ -65,7 +63,10 @@ public AsyncWriterPool() { public void close() throws IOException { if (this.poolClosed) return; this.poolClosed = true; - CompletableFuture.allOf(this.writers.stream().map(PooledWriter::nonBlockingClose).toArray(CompletableFuture[]::new)).join(); + CompletableFuture.allOf(this.writers.stream() + .map(PooledWriter::nonBlockingClose) + .toArray(CompletableFuture[]::new)) + .join(); this.executor.shutdown(); } @@ -104,7 +105,6 @@ public Writer pool(final Writer writer, final BlockingQueue queue, return pooledWriter; } - /** * Any class that implements {@link Writer} can be exchanged for a {@code PooledWriter}. The PooledWriter provides * the same API as {@link Writer}, but will manage buffering of writes and sending to the {@link AsyncWriterPool} it @@ -122,7 +122,8 @@ private class PooledWriter implements Writer { private boolean isClosed = false; - // Holds the Future of the last task submitted to the AsyncWriterPools until it is checked, then it is null again. + // Holds the Future of the last task submitted to the AsyncWriterPools until it is checked, then it is null + // again. private Future currentTask; /** @@ -137,7 +138,8 @@ private PooledWriter(final Writer writer, final BlockingQueue queue, final if (writeThreshold <= 0) throw new IllegalArgumentException("writeThreshold must be >= 1: " + writeThreshold); if (writeThreshold > queue.remainingCapacity()) - throw new IllegalArgumentException("writeThreshold (" + writeThreshold + ") can't be larger then queue capacity (" + queue.remainingCapacity() + ")."); + throw new IllegalArgumentException("writeThreshold (" + writeThreshold + + ") can't be larger then queue capacity (" + queue.remainingCapacity() + ")."); this.writer = writer; this.queue = queue; @@ -208,7 +210,10 @@ public void write(final A item) { * normal operations the timeout should not come into play and items will add immediately. */ try { - while (!this.isClosed && !this.queue.offer(item, AsyncWriterPool.this.getTimeoutSeconds(), TimeUnit.SECONDS)) { /* Just wait. */ } + while (!this.isClosed + && !this.queue.offer(item, AsyncWriterPool.this.getTimeoutSeconds(), TimeUnit.SECONDS)) { + /* Just wait. */ + } } catch (InterruptedException e) { throw new RuntimeException("Exception while placing item in queue", e); } @@ -251,14 +256,16 @@ private void drain() { */ private CompletableFuture nonBlockingClose() { - return CompletableFuture.supplyAsync(() -> { - try { - this.close(); - return null; - } catch (Exception e) { - throw new RuntimeException("Caught exception while closing PooledWriter.", e); - } - }, AsyncWriterPool.this.executor); + return CompletableFuture.supplyAsync( + () -> { + try { + this.close(); + return null; + } catch (Exception e) { + throw new RuntimeException("Caught exception while closing PooledWriter.", e); + } + }, + AsyncWriterPool.this.executor); } /** diff --git a/src/main/java/htsjdk/io/HtsPath.java b/src/main/java/htsjdk/io/HtsPath.java index 035b1ff418..f3c2df78b8 100644 --- a/src/main/java/htsjdk/io/HtsPath.java +++ b/src/main/java/htsjdk/io/HtsPath.java @@ -1,7 +1,6 @@ package htsjdk.io; import htsjdk.utils.ValidationUtils; - import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -71,10 +70,10 @@ public class HtsPath implements IOPath, Serializable { private static final long serialVersionUID = 1L; private static final String HIERARCHICAL_SCHEME_SEPARATOR = "://"; - private final String rawInputString; // raw input string provided by th user; may or may not have a scheme - private final URI uri; // working URI; always has a scheme ("file" if not otherwise specified) + private final String rawInputString; // raw input string provided by th user; may or may not have a scheme + private final URI uri; // working URI; always has a scheme ("file" if not otherwise specified) private transient String pathFailureReason; // cache the reason for "toPath" conversion failure - private transient Path cachedPath; // cache the Path associated with this URI if its "Path-able" + private transient Path cachedPath; // cache the Path associated with this URI if its "Path-able" /** * Create an HtsPath from a raw input path string. @@ -117,12 +116,14 @@ public String getURIString() { * Return the raw input string provided to the constructor. */ @Override - public String getRawInputString() { return rawInputString; } + public String getRawInputString() { + return rawInputString; + } @Override public boolean hasFileSystemProvider() { // try to find a provider; assume that our URI always has a scheme - for (FileSystemProvider provider: FileSystemProvider.installedProviders()) { + for (FileSystemProvider provider : FileSystemProvider.installedProviders()) { if (provider.getScheme().equalsIgnoreCase(uri.getScheme())) { return true; } @@ -134,10 +135,10 @@ public boolean hasFileSystemProvider() { public boolean isPath() { try { return getCachedPath() != null || toPath() != null; - } catch (ProviderNotFoundException | - FileSystemNotFoundException | - IllegalArgumentException | - AssertionError e) { + } catch (ProviderNotFoundException + | FileSystemNotFoundException + | IllegalArgumentException + | AssertionError e) { // jimfs throws an AssertionError that wraps a URISyntaxException when trying to create path where // the scheme-specific part is missing or incorrect pathFailureReason = e.getMessage(); @@ -192,7 +193,10 @@ public InputStream getInputStream() { return Files.newInputStream(resourcePath); } catch (IOException e) { throw new RuntimeException( - String.format("Could not create open input stream for %s (as URI %s)", getRawInputString(), getURIString()), e); + String.format( + "Could not create open input stream for %s (as URI %s)", + getRawInputString(), getURIString()), + e); } } @@ -206,12 +210,17 @@ public OutputStream getOutputStream() { try { return Files.newOutputStream(resourcePath); } catch (IOException e) { - throw new RuntimeException(String.format("Could not open output stream for %s (as URI %s)", getRawInputString(), getURIString()), e); + throw new RuntimeException( + String.format( + "Could not open output stream for %s (as URI %s)", getRawInputString(), getURIString()), + e); } } // get the cached path associated with this URI if its already been created - protected Path getCachedPath() { return cachedPath; } + protected Path getCachedPath() { + return cachedPath; + } protected void setCachedPath(Path path) { this.cachedPath = path; @@ -251,8 +260,8 @@ private URI getURIForString(final String pathString) { tempURI = getCachedPath().toUri(); } } catch (URISyntaxException uriException) { - //check that the uri wasn't a badly encoded absolute uri of some sort - //if you don't do this it will be treated as a badly formed file:// url + // check that the uri wasn't a badly encoded absolute uri of some sort + // if you don't do this it will be treated as a badly formed file:// url assertNoProblematicScheme(pathString, uriException); // the input string isn't a valid URI; assume its a local (non-URI) file reference, and @@ -265,9 +274,7 @@ private URI getURIForString(final String pathString) { // the user intended to provide a local file reference or a URI, so preserve both final String errorMessage = String.format( "%s can't be interpreted as a local file (%s) or as a URI (%s).", - pathString, - pathException.getMessage(), - uriException.getMessage()); + pathString, pathException.getMessage(), uriException.getMessage()); throw new IllegalArgumentException(errorMessage, pathException); } } @@ -292,28 +299,30 @@ private URI getURIForString(final String pathString) { * @param pathString the path being examined * @param cause the original failure reason */ - static void assertNoProblematicScheme(String pathString, URISyntaxException cause){ - if(pathString.equals(HIERARCHICAL_SCHEME_SEPARATOR)){ + static void assertNoProblematicScheme(String pathString, URISyntaxException cause) { + if (pathString.equals(HIERARCHICAL_SCHEME_SEPARATOR)) { throw new IllegalArgumentException(HIERARCHICAL_SCHEME_SEPARATOR + " is not a valid path.", cause); } final String[] split = pathString.split(HIERARCHICAL_SCHEME_SEPARATOR, -1); final String scheme = split[0]; - if(split.length == 2 && pathString.endsWith(HIERARCHICAL_SCHEME_SEPARATOR)) { - throw new IllegalArgumentException("A path consisting of only a scheme is not allowed: " + pathString, cause); + if (split.length == 2 && pathString.endsWith(HIERARCHICAL_SCHEME_SEPARATOR)) { + throw new IllegalArgumentException( + "A path consisting of only a scheme is not allowed: " + pathString, cause); } - if(split.length > 1){ - if(scheme == null || scheme.isEmpty()){ - throw new IllegalArgumentException("Malformed path " + pathString + " includes an empty scheme.", cause); + if (split.length > 1) { + if (scheme == null || scheme.isEmpty()) { + throw new IllegalArgumentException( + "Malformed path " + pathString + " includes an empty scheme.", cause); } - if(!scheme.equals("file")){ - throw new IllegalArgumentException("Malformed path " + pathString + " includes a scheme: " + scheme + ":// but was an invalid URI." + - "\nCheck that it is fully encoded.", cause); + if (!scheme.equals("file")) { + throw new IllegalArgumentException( + "Malformed path " + pathString + " includes a scheme: " + scheme + ":// but was an invalid URI." + + "\nCheck that it is fully encoded.", + cause); } } - } - } diff --git a/src/main/java/htsjdk/io/IOPath.java b/src/main/java/htsjdk/io/IOPath.java index 7f22df3c4a..bd2d3d1873 100644 --- a/src/main/java/htsjdk/io/IOPath.java +++ b/src/main/java/htsjdk/io/IOPath.java @@ -2,7 +2,6 @@ import htsjdk.samtools.util.FileExtensions; import htsjdk.utils.ValidationUtils; - import java.io.InputStream; import java.io.OutputStream; import java.net.URI; @@ -91,7 +90,8 @@ default String getScheme() { default Optional getExtension() { final String hierarchicalPath = getURI().getPath(); if (hierarchicalPath != null) { - final int indexOfLastComponent = hierarchicalPath.lastIndexOf(FileSystems.getDefault().getSeparator()); + final int indexOfLastComponent = + hierarchicalPath.lastIndexOf(FileSystems.getDefault().getSeparator()); if (indexOfLastComponent != -1 && indexOfLastComponent < hierarchicalPath.length() - 1) { final String lastComponent = hierarchicalPath.substring(indexOfLastComponent + 1); if (lastComponent.length() > 0) { @@ -127,9 +127,7 @@ default boolean hasExtension(final String extension) { // We don't want to use {@code #getExtension} here, since it won't work correctly if we're comparing an // extension that uses multiple . chars, such as .fasta.gz. final String hierarchicalPath = getURI().getPath(); - return hierarchicalPath == null ? - false : - hierarchicalPath.toLowerCase().endsWith(extension.toLowerCase()); + return hierarchicalPath == null ? false : hierarchicalPath.toLowerCase().endsWith(extension.toLowerCase()); } /** @@ -140,7 +138,8 @@ default boolean hasExtension(final String extension) { */ default Optional getBaseName() { final String hierarchicalPath = getURI().getPath(); - final int indexOfLastComponent = hierarchicalPath.lastIndexOf(FileSystems.getDefault().getSeparator()); + final int indexOfLastComponent = + hierarchicalPath.lastIndexOf(FileSystems.getDefault().getSeparator()); if (indexOfLastComponent != -1 && indexOfLastComponent < hierarchicalPath.length() - 1) { final String lastComponent = hierarchicalPath.substring(indexOfLastComponent + 1); if (lastComponent.length() > 0) { diff --git a/src/main/java/htsjdk/samtools/AbstractBAMFileIndex.java b/src/main/java/htsjdk/samtools/AbstractBAMFileIndex.java index 9df206ecfd..7989ca3184 100644 --- a/src/main/java/htsjdk/samtools/AbstractBAMFileIndex.java +++ b/src/main/java/htsjdk/samtools/AbstractBAMFileIndex.java @@ -25,7 +25,6 @@ import htsjdk.samtools.seekablestream.SeekableStream; import htsjdk.samtools.util.RuntimeIOException; - import java.io.File; import java.util.ArrayList; import java.util.Arrays; @@ -60,11 +59,16 @@ protected AbstractBAMFileIndex(final File file, final SAMSequenceDictionary dict this(new MemoryMappedFileBuffer(file), file.getName(), dictionary); } - protected AbstractBAMFileIndex(final File file, final SAMSequenceDictionary dictionary, final boolean useMemoryMapping) { - this((useMemoryMapping ? new MemoryMappedFileBuffer(file) : new RandomAccessFileBuffer(file)), file.getName(), dictionary); + protected AbstractBAMFileIndex( + final File file, final SAMSequenceDictionary dictionary, final boolean useMemoryMapping) { + this( + (useMemoryMapping ? new MemoryMappedFileBuffer(file) : new RandomAccessFileBuffer(file)), + file.getName(), + dictionary); } - protected AbstractBAMFileIndex(final IndexFileBuffer indexFileBuffer, final String source, final SAMSequenceDictionary dictionary) { + protected AbstractBAMFileIndex( + final IndexFileBuffer indexFileBuffer, final String source, final SAMSequenceDictionary dictionary) { mIndexBuffer = indexFileBuffer; mBamDictionary = dictionary; verifyIndexMagicNumber(source); @@ -87,9 +91,10 @@ public static int getNumIndexLevels() { return GenomicIndexUtil.LEVEL_STARTS.length; } - private static void assertLevelIsValid (final int levelNumber) { + private static void assertLevelIsValid(final int levelNumber) { if (levelNumber >= getNumIndexLevels()) { - throw new SAMException("Level number (" + levelNumber + ") is greater than or equal to maximum (" + getNumIndexLevels() + ")."); + throw new SAMException("Level number (" + levelNumber + ") is greater than or equal to maximum (" + + getNumIndexLevels() + ")."); } } @@ -112,7 +117,7 @@ public static int getFirstBinInLevel(final int levelNumber) { public int getLevelSize(final int levelNumber) { assertLevelIsValid(levelNumber); - if (levelNumber == getNumIndexLevels()-1) { + if (levelNumber == getNumIndexLevels() - 1) { return GenomicIndexUtil.MAX_BINS - GenomicIndexUtil.LEVEL_STARTS[levelNumber] - 1; } else { return GenomicIndexUtil.LEVEL_STARTS[levelNumber + 1] - GenomicIndexUtil.LEVEL_STARTS[levelNumber]; @@ -125,13 +130,12 @@ public int getLevelSize(final int levelNumber) { * @return the level associated with the given bin number. */ public int getLevelForBin(final Bin bin) { - if(bin.getBinNumber() >= GenomicIndexUtil.MAX_BINS) + if (bin.getBinNumber() >= GenomicIndexUtil.MAX_BINS) throw new SAMException("Tried to get level for invalid bin."); - for(int i = getNumIndexLevels()-1; i >= 0; i--) { - if(bin.getBinNumber() >= GenomicIndexUtil.LEVEL_STARTS[i]) - return i; + for (int i = getNumIndexLevels() - 1; i >= 0; i--) { + if (bin.getBinNumber() >= GenomicIndexUtil.LEVEL_STARTS[i]) return i; } - throw new SAMException("Unable to find correct bin for bin "+bin); + throw new SAMException("Unable to find correct bin for bin " + bin); } /** @@ -142,8 +146,11 @@ public int getLevelForBin(final Bin bin) { public int getFirstLocusInBin(final Bin bin) { final int level = getLevelForBin(bin); final int levelStart = GenomicIndexUtil.LEVEL_STARTS[level]; - final int levelSize = ((level==getNumIndexLevels()-1) ? GenomicIndexUtil.MAX_BINS-1 : GenomicIndexUtil.LEVEL_STARTS[level+1]) - levelStart; - return (bin.getBinNumber() - levelStart)*(GenomicIndexUtil.BIN_GENOMIC_SPAN /levelSize)+1; + final int levelSize = ((level == getNumIndexLevels() - 1) + ? GenomicIndexUtil.MAX_BINS - 1 + : GenomicIndexUtil.LEVEL_STARTS[level + 1]) + - levelStart; + return (bin.getBinNumber() - levelStart) * (GenomicIndexUtil.BIN_GENOMIC_SPAN / levelSize) + 1; } /** @@ -154,8 +161,11 @@ public int getFirstLocusInBin(final Bin bin) { public int getLastLocusInBin(final Bin bin) { final int level = getLevelForBin(bin); final int levelStart = GenomicIndexUtil.LEVEL_STARTS[level]; - final int levelSize = ((level==getNumIndexLevels()-1) ? GenomicIndexUtil.MAX_BINS-1 : GenomicIndexUtil.LEVEL_STARTS[level+1]) - levelStart; - return (bin.getBinNumber()-levelStart+1)*(GenomicIndexUtil.BIN_GENOMIC_SPAN /levelSize); + final int levelSize = ((level == getNumIndexLevels() - 1) + ? GenomicIndexUtil.MAX_BINS - 1 + : GenomicIndexUtil.LEVEL_STARTS[level + 1]) + - levelStart; + return (bin.getBinNumber() - levelStart + 1) * (GenomicIndexUtil.BIN_GENOMIC_SPAN / levelSize); } public int getNumberOfReferences() { @@ -271,7 +281,7 @@ protected BAMIndexContent query(final int referenceSequence, final int startPos, final int binCount = readInteger(); boolean metaDataSeen = false; - final Bin[] bins = new Bin[getMaxBinNumberForReference(referenceSequence) +1]; + final Bin[] bins = new Bin[getMaxBinNumberForReference(referenceSequence) + 1]; for (int binNumber = 0; binNumber < binCount; binNumber++) { final int indexBin = readInteger(); final int nChunks = readInteger(); @@ -279,7 +289,7 @@ protected BAMIndexContent query(final int referenceSequence, final int startPos, // System.out.println("# bin[" + i + "] = " + indexBin + ", nChunks = " + nChunks); Chunk lastChunk = null; if (regionBins.get(indexBin)) { - chunks = new ArrayList(nChunks); + chunks = new ArrayList(nChunks); readChunks(nChunks, chunks); } else if (indexBin == GenomicIndexUtil.MAX_BINS) { // meta data - build the bin so that the count of bins is correct; @@ -300,20 +310,25 @@ protected BAMIndexContent query(final int referenceSequence, final int startPos, final int nLinearBins = readInteger(); final int regionLinearBinStart = LinearIndex.convertToLinearIndexOffset(startPos); - final int regionLinearBinStop = endPos > 0 ? LinearIndex.convertToLinearIndexOffset(endPos) : nLinearBins-1; - final int actualStop = Math.min(regionLinearBinStop, nLinearBins -1); + final int regionLinearBinStop = endPos > 0 ? LinearIndex.convertToLinearIndexOffset(endPos) : nLinearBins - 1; + final int actualStop = Math.min(regionLinearBinStop, nLinearBins - 1); long[] linearIndexEntries = new long[0]; if (regionLinearBinStart < nLinearBins) { - linearIndexEntries = new long[actualStop-regionLinearBinStart+1]; + linearIndexEntries = new long[actualStop - regionLinearBinStart + 1]; skipBytes(8 * regionLinearBinStart); - for(int linearBin = regionLinearBinStart; linearBin <= actualStop; linearBin++) - linearIndexEntries[linearBin-regionLinearBinStart] = readLong(); + for (int linearBin = regionLinearBinStart; linearBin <= actualStop; linearBin++) + linearIndexEntries[linearBin - regionLinearBinStart] = readLong(); } - final LinearIndex linearIndex = new LinearIndex(referenceSequence,regionLinearBinStart,linearIndexEntries); + final LinearIndex linearIndex = new LinearIndex(referenceSequence, regionLinearBinStart, linearIndexEntries); - return new BAMIndexContent(referenceSequence, bins, binCount - (metaDataSeen? 1 : 0), new BAMIndexMetaData(metaDataChunks), linearIndex); + return new BAMIndexContent( + referenceSequence, + bins, + binCount - (metaDataSeen ? 1 : 0), + new BAMIndexMetaData(metaDataChunks), + linearIndex); } /** @@ -338,7 +353,7 @@ static int getMaxBinNumberForSequenceLength(final int sequenceLength) { // return 4680 + (sequenceLength >> 14); // note 4680 = getFirstBinInLevel(getNumIndexLevels() - 1) } - abstract protected BAMIndexContent getQueryResults(int reference); + protected abstract BAMIndexContent getQueryResults(int reference); /** * Gets the possible number of bins for a given reference sequence. @@ -375,8 +390,7 @@ protected void verifyIndexMagicNumber(final String sourceName) { final byte[] buffer = new byte[4]; readBytes(buffer); if (!Arrays.equals(buffer, BAMFileConstants.BAI_INDEX_MAGIC)) { - throw new RuntimeIOException("Invalid file header in BAM index " + sourceName + - ": " + new String(buffer)); + throw new RuntimeIOException("Invalid file header in BAM index " + sourceName + ": " + new String(buffer)); } } @@ -399,11 +413,11 @@ protected void readChunks(int nChunks, List chunks) { } protected void skipToSequence(final int sequenceIndex) { - //Use sequence position cache if available - if(sequenceIndexes[sequenceIndex] != -1){ - seek(sequenceIndexes[sequenceIndex]); - return; - } + // Use sequence position cache if available + if (sequenceIndexes[sequenceIndex] != -1) { + seek(sequenceIndexes[sequenceIndex]); + return; + } // Use previous sequence position if in cache, which optimizes for common access pattern // of iterating through sequences in order. @@ -415,7 +429,7 @@ protected void skipToSequence(final int sequenceIndex) { } else { startSequenceIndex = 0; } - + for (int i = startSequenceIndex; i < sequenceIndex; i++) { // System.out.println("# Sequence TID: " + i); final int nBins = readInteger(); @@ -430,8 +444,8 @@ protected void skipToSequence(final int sequenceIndex) { // System.out.println("# nLinearBins: " + nLinearBins); skipBytes(8 * nLinearBins); } - - //Update sequence position cache + + // Update sequence position cache sequenceIndexes[sequenceIndex] = position(); } @@ -454,16 +468,16 @@ protected final void skipBytes(final int count) { protected final void seek(final long position) { mIndexBuffer.seek(position); } - - protected final long position(){ - return mIndexBuffer.position(); + + protected final long position() { + return mIndexBuffer.position(); } protected final SAMSequenceDictionary getBamDictionary() { return mBamDictionary; } - protected final void setSequenceIndexes (int nReferences) { + protected final void setSequenceIndexes(int nReferences) { sequenceIndexes = new long[nReferences + 1]; Arrays.fill(sequenceIndexes, -1); } diff --git a/src/main/java/htsjdk/samtools/AbstractSAMHeaderRecord.java b/src/main/java/htsjdk/samtools/AbstractSAMHeaderRecord.java index a3e2ce5966..210d2e0415 100644 --- a/src/main/java/htsjdk/samtools/AbstractSAMHeaderRecord.java +++ b/src/main/java/htsjdk/samtools/AbstractSAMHeaderRecord.java @@ -23,7 +23,6 @@ */ package htsjdk.samtools; - import java.io.Serializable; import java.util.LinkedHashMap; import java.util.Map; @@ -33,11 +32,10 @@ * Base class for the various concrete records in a SAM header, providing uniform * access to the attributes. */ - public abstract class AbstractSAMHeaderRecord implements Serializable { public static final long serialVersionUID = 1L; - private final Map mAttributes = new LinkedHashMap(); + private final Map mAttributes = new LinkedHashMap(); public String getAttribute(final String key) { return mAttributes.get(key); @@ -53,7 +51,7 @@ public String getAttribute(final String key) { */ @Deprecated public void setAttribute(final String key, final Object value) { - setAttribute(key, value == null? null: value.toString()); + setAttribute(key, value == null ? null : value.toString()); } /** @@ -83,11 +81,10 @@ public void setAttribute(final String key, final String value) { /** * Returns the Set of attributes. */ - public Set> getAttributes() { + public Set> getAttributes() { return mAttributes.entrySet(); } - /** * Returns the ID tag (or equivalent) for this header record. The * default implementation throws a SAMException to indicate "not implemented". @@ -118,7 +115,8 @@ protected int attributesHashCode() { abstract Set getStandardTags(); /** Simple to String that outputs the concrete class name and the set of attributes stored. */ - @Override public String toString() { + @Override + public String toString() { return getClass().getSimpleName() + this.mAttributes.toString(); } @@ -126,5 +124,5 @@ protected int attributesHashCode() { * Returns the record in the SAM line-based text format. Fields are * separated by '\t' characters. The String is NOT terminated by '\n'. */ - abstract public String getSAMString(); + public abstract String getSAMString(); } diff --git a/src/main/java/htsjdk/samtools/AlignmentBlock.java b/src/main/java/htsjdk/samtools/AlignmentBlock.java index 1320dfdf66..bf41783ff3 100644 --- a/src/main/java/htsjdk/samtools/AlignmentBlock.java +++ b/src/main/java/htsjdk/samtools/AlignmentBlock.java @@ -48,11 +48,17 @@ public class AlignmentBlock implements Serializable { } /** The first, 1-based, base in the read that is aligned to the reference reference. */ - public int getReadStart() { return readStart; } + public int getReadStart() { + return readStart; + } /** The first, 1-based, position in the reference to which the read is aligned. */ - public int getReferenceStart() { return referenceStart; } + public int getReferenceStart() { + return referenceStart; + } /** The number of contiguous bases aligned to the reference. */ - public int getLength() { return length; } + public int getLength() { + return length; + } } diff --git a/src/main/java/htsjdk/samtools/AsyncSAMFileWriter.java b/src/main/java/htsjdk/samtools/AsyncSAMFileWriter.java index ea85458ec3..3d8e0f561c 100644 --- a/src/main/java/htsjdk/samtools/AsyncSAMFileWriter.java +++ b/src/main/java/htsjdk/samtools/AsyncSAMFileWriter.java @@ -33,16 +33,25 @@ public AsyncSAMFileWriter(final SAMFileWriter out, final int queueSize) { this.underlyingWriter = out; } - @Override protected void synchronouslyWrite(final SAMRecord item) { this.underlyingWriter.addAlignment(item); } + @Override + protected void synchronouslyWrite(final SAMRecord item) { + this.underlyingWriter.addAlignment(item); + } - @Override protected void synchronouslyClose() { this.underlyingWriter.close(); } + @Override + protected void synchronouslyClose() { + this.underlyingWriter.close(); + } - @Override protected final String getThreadNamePrefix() { return "SAMFileWriterThread-"; } + @Override + protected final String getThreadNamePrefix() { + return "SAMFileWriterThread-"; + } - @Override - public void setProgressLogger(final ProgressLoggerInterface progress) { - this.underlyingWriter.setProgressLogger(progress); - } + @Override + public void setProgressLogger(final ProgressLoggerInterface progress) { + this.underlyingWriter.setProgressLogger(progress); + } @Override public void setSortOrderChecking(boolean check) { diff --git a/src/main/java/htsjdk/samtools/BAMFileConstants.java b/src/main/java/htsjdk/samtools/BAMFileConstants.java index 638c56cc56..8192bf5612 100644 --- a/src/main/java/htsjdk/samtools/BAMFileConstants.java +++ b/src/main/java/htsjdk/samtools/BAMFileConstants.java @@ -36,7 +36,6 @@ class BAMFileConstants { * BAM file magic number. This is what is present in the gunzipped version of the file, * which never exists on disk. */ - static final byte[] BAM_MAGIC = "BAM\1".getBytes(); /** * BAM index file magic numbers. @@ -44,6 +43,7 @@ class BAMFileConstants { */ @Deprecated static final byte[] BAM_INDEX_MAGIC = "BAI\1".getBytes(); + static final byte[] BAI_INDEX_MAGIC = "BAI\1".getBytes(); static final byte[] CSI_INDEX_MAGIC = "CSI\1".getBytes(); @@ -51,6 +51,7 @@ class BAMFileConstants { * CSI index related constants */ static final int CSI_MAGIC_OFFSET = 0; + static final int CSI_MINSHIFT_OFFSET = 4; static final int CSI_AUXDATA_OFFSET = 12; static final int CSI_CHUNK_SIZE = 16; diff --git a/src/main/java/htsjdk/samtools/BAMFileReader.java b/src/main/java/htsjdk/samtools/BAMFileReader.java index 3693eeba8c..9667174d32 100644 --- a/src/main/java/htsjdk/samtools/BAMFileReader.java +++ b/src/main/java/htsjdk/samtools/BAMFileReader.java @@ -23,11 +23,9 @@ */ package htsjdk.samtools; - import htsjdk.samtools.seekablestream.SeekableStream; import htsjdk.samtools.util.*; import htsjdk.samtools.util.zip.InflaterFactory; - import java.io.DataInputStream; import java.io.File; import java.io.IOException; @@ -94,15 +92,22 @@ public class BAMFileReader extends SamReader.ReaderImplementation { * @param samRecordFactory SAM record factory * @throws IOException */ - BAMFileReader(final InputStream stream, - final File indexFile, - final boolean eagerDecode, - final boolean useAsynchronousIO, - final ValidationStringency validationStringency, - final SAMRecordFactory samRecordFactory) + BAMFileReader( + final InputStream stream, + final File indexFile, + final boolean eagerDecode, + final boolean useAsynchronousIO, + final ValidationStringency validationStringency, + final SAMRecordFactory samRecordFactory) throws IOException { - this(stream, indexFile, eagerDecode, useAsynchronousIO, validationStringency, samRecordFactory, - BlockGunzipper.getDefaultInflaterFactory()); + this( + stream, + indexFile, + eagerDecode, + useAsynchronousIO, + validationStringency, + samRecordFactory, + BlockGunzipper.getDefaultInflaterFactory()); } /** @@ -116,17 +121,20 @@ public class BAMFileReader extends SamReader.ReaderImplementation { * @param inflaterFactory InflaterFactory used by BlockCompressedInputStream * @throws IOException */ - BAMFileReader(final InputStream stream, - final File indexFile, - final boolean eagerDecode, - final boolean useAsynchronousIO, - final ValidationStringency validationStringency, - final SAMRecordFactory samRecordFactory, - final InflaterFactory inflaterFactory) + BAMFileReader( + final InputStream stream, + final File indexFile, + final boolean eagerDecode, + final boolean useAsynchronousIO, + final ValidationStringency validationStringency, + final SAMRecordFactory samRecordFactory, + final InflaterFactory inflaterFactory) throws IOException { mIndexFile = indexFile; mIsSeekable = false; - mCompressedInputStream = useAsynchronousIO ? new AsyncBlockCompressedInputStream(stream, inflaterFactory) : new BlockCompressedInputStream(stream, inflaterFactory); + mCompressedInputStream = useAsynchronousIO + ? new AsyncBlockCompressedInputStream(stream, inflaterFactory) + : new BlockCompressedInputStream(stream, inflaterFactory); mStream = new BinaryCodec(new DataInputStream(mCompressedInputStream)); this.eagerDecode = eagerDecode; this.mValidationStringency = validationStringency; @@ -144,14 +152,22 @@ public class BAMFileReader extends SamReader.ReaderImplementation { * @param samRecordFactory SAM record factory * @throws IOException */ - BAMFileReader(final File file, - final File indexFile, - final boolean eagerDecode, - final boolean useAsynchronousIO, - final ValidationStringency validationStringency, - final SAMRecordFactory samRecordFactory) - throws IOException { - this(file, indexFile, eagerDecode, useAsynchronousIO, validationStringency, samRecordFactory, BlockGunzipper.getDefaultInflaterFactory()); + BAMFileReader( + final File file, + final File indexFile, + final boolean eagerDecode, + final boolean useAsynchronousIO, + final ValidationStringency validationStringency, + final SAMRecordFactory samRecordFactory) + throws IOException { + this( + file, + indexFile, + eagerDecode, + useAsynchronousIO, + validationStringency, + samRecordFactory, + BlockGunzipper.getDefaultInflaterFactory()); } /** @@ -165,20 +181,29 @@ public class BAMFileReader extends SamReader.ReaderImplementation { * @param inflaterFactory InflaterFactory used by BlockCompressedInputStream * @throws IOException */ - BAMFileReader(final File file, - final File indexFile, - final boolean eagerDecode, - final boolean useAsynchronousIO, - final ValidationStringency validationStringency, - final SAMRecordFactory samRecordFactory, - final InflaterFactory inflaterFactory) - throws IOException { - this(useAsynchronousIO ? new AsyncBlockCompressedInputStream(file, inflaterFactory) : new BlockCompressedInputStream(file, inflaterFactory), - indexFile!=null ? indexFile : SamFiles.findIndex(file), eagerDecode, useAsynchronousIO, file.getAbsolutePath(), validationStringency, samRecordFactory); + BAMFileReader( + final File file, + final File indexFile, + final boolean eagerDecode, + final boolean useAsynchronousIO, + final ValidationStringency validationStringency, + final SAMRecordFactory samRecordFactory, + final InflaterFactory inflaterFactory) + throws IOException { + this( + useAsynchronousIO + ? new AsyncBlockCompressedInputStream(file, inflaterFactory) + : new BlockCompressedInputStream(file, inflaterFactory), + indexFile != null ? indexFile : SamFiles.findIndex(file), + eagerDecode, + useAsynchronousIO, + file.getAbsolutePath(), + validationStringency, + samRecordFactory); if (mIndexFile != null && mIndexFile.lastModified() < file.lastModified() - 5000) { - System.err.println("WARNING: BAM index file " + mIndexFile.getAbsolutePath() + - " is older than BAM " + file.getAbsolutePath()); + System.err.println("WARNING: BAM index file " + mIndexFile.getAbsolutePath() + " is older than BAM " + + file.getAbsolutePath()); } // Provide better error message when there is an error reading. @@ -195,14 +220,22 @@ public class BAMFileReader extends SamReader.ReaderImplementation { * @param samRecordFactory SAM record factory * @throws IOException */ - BAMFileReader(final SeekableStream strm, - final File indexFile, - final boolean eagerDecode, - final boolean useAsynchronousIO, - final ValidationStringency validationStringency, - final SAMRecordFactory samRecordFactory) - throws IOException { - this(strm, indexFile, eagerDecode, useAsynchronousIO, validationStringency, samRecordFactory, BlockGunzipper.getDefaultInflaterFactory()); + BAMFileReader( + final SeekableStream strm, + final File indexFile, + final boolean eagerDecode, + final boolean useAsynchronousIO, + final ValidationStringency validationStringency, + final SAMRecordFactory samRecordFactory) + throws IOException { + this( + strm, + indexFile, + eagerDecode, + useAsynchronousIO, + validationStringency, + samRecordFactory, + BlockGunzipper.getDefaultInflaterFactory()); } /** @@ -216,16 +249,25 @@ public class BAMFileReader extends SamReader.ReaderImplementation { * @param inflaterFactory InflaterFactory used by BlockCompressedInputStream * @throws IOException */ - BAMFileReader(final SeekableStream strm, - final File indexFile, - final boolean eagerDecode, - final boolean useAsynchronousIO, - final ValidationStringency validationStringency, - final SAMRecordFactory samRecordFactory, - final InflaterFactory inflaterFactory) - throws IOException { - this(useAsynchronousIO ? new AsyncBlockCompressedInputStream(strm, inflaterFactory) : new BlockCompressedInputStream(strm, inflaterFactory), - indexFile, eagerDecode, useAsynchronousIO, strm.getSource(), validationStringency, samRecordFactory); + BAMFileReader( + final SeekableStream strm, + final File indexFile, + final boolean eagerDecode, + final boolean useAsynchronousIO, + final ValidationStringency validationStringency, + final SAMRecordFactory samRecordFactory, + final InflaterFactory inflaterFactory) + throws IOException { + this( + useAsynchronousIO + ? new AsyncBlockCompressedInputStream(strm, inflaterFactory) + : new BlockCompressedInputStream(strm, inflaterFactory), + indexFile, + eagerDecode, + useAsynchronousIO, + strm.getSource(), + validationStringency, + samRecordFactory); } /** @@ -238,14 +280,22 @@ public class BAMFileReader extends SamReader.ReaderImplementation { * @param samRecordFactory SAM record factory * @throws IOException */ - BAMFileReader(final SeekableStream strm, - final SeekableStream indexStream, - final boolean eagerDecode, - final boolean useAsynchronousIO, - final ValidationStringency validationStringency, - final SAMRecordFactory samRecordFactory) - throws IOException { - this(strm, indexStream, eagerDecode, useAsynchronousIO, validationStringency, samRecordFactory, BlockGunzipper.getDefaultInflaterFactory()); + BAMFileReader( + final SeekableStream strm, + final SeekableStream indexStream, + final boolean eagerDecode, + final boolean useAsynchronousIO, + final ValidationStringency validationStringency, + final SAMRecordFactory samRecordFactory) + throws IOException { + this( + strm, + indexStream, + eagerDecode, + useAsynchronousIO, + validationStringency, + samRecordFactory, + BlockGunzipper.getDefaultInflaterFactory()); } /** @@ -259,16 +309,25 @@ public class BAMFileReader extends SamReader.ReaderImplementation { * @param inflaterFactory InflaterFactory used by BlockCompressedInputStream * @throws IOException */ - BAMFileReader(final SeekableStream strm, - final SeekableStream indexStream, - final boolean eagerDecode, - final boolean useAsynchronousIO, - final ValidationStringency validationStringency, - final SAMRecordFactory samRecordFactory, - final InflaterFactory inflaterFactory) - throws IOException { - this(useAsynchronousIO ? new AsyncBlockCompressedInputStream(strm, inflaterFactory) : new BlockCompressedInputStream(strm, inflaterFactory), - indexStream, eagerDecode, useAsynchronousIO, strm.getSource(), validationStringency, samRecordFactory); + BAMFileReader( + final SeekableStream strm, + final SeekableStream indexStream, + final boolean eagerDecode, + final boolean useAsynchronousIO, + final ValidationStringency validationStringency, + final SAMRecordFactory samRecordFactory, + final InflaterFactory inflaterFactory) + throws IOException { + this( + useAsynchronousIO + ? new AsyncBlockCompressedInputStream(strm, inflaterFactory) + : new BlockCompressedInputStream(strm, inflaterFactory), + indexStream, + eagerDecode, + useAsynchronousIO, + strm.getSource(), + validationStringency, + samRecordFactory); } /** @@ -282,14 +341,15 @@ public class BAMFileReader extends SamReader.ReaderImplementation { * @param samRecordFactory SAM record factory * @throws IOException */ - private BAMFileReader(final BlockCompressedInputStream compressedInputStream, - final File indexFile, - final boolean eagerDecode, - final boolean useAsynchronousIO, - final String source, - final ValidationStringency validationStringency, - final SAMRecordFactory samRecordFactory) - throws IOException { + private BAMFileReader( + final BlockCompressedInputStream compressedInputStream, + final File indexFile, + final boolean eagerDecode, + final boolean useAsynchronousIO, + final String source, + final ValidationStringency validationStringency, + final SAMRecordFactory samRecordFactory) + throws IOException { mIndexFile = indexFile; mIsSeekable = true; mCompressedInputStream = compressedInputStream; @@ -312,14 +372,15 @@ private BAMFileReader(final BlockCompressedInputStream compressedInputStream, * @param samRecordFactory SAM record factory * @throws IOException */ - private BAMFileReader(final BlockCompressedInputStream compressedInputStream, - final SeekableStream indexStream, - final boolean eagerDecode, - final boolean useAsynchronousIO, - final String source, - final ValidationStringency validationStringency, - final SAMRecordFactory samRecordFactory) - throws IOException { + private BAMFileReader( + final BlockCompressedInputStream compressedInputStream, + final SeekableStream indexStream, + final boolean eagerDecode, + final boolean useAsynchronousIO, + final String source, + final ValidationStringency validationStringency, + final SAMRecordFactory samRecordFactory) + throws IOException { mIndexStream = indexStream; mIsSeekable = true; mCompressedInputStream = compressedInputStream; @@ -333,7 +394,8 @@ private BAMFileReader(final BlockCompressedInputStream compressedInputStream, /** Reads through the header and sequence records to find the virtual file offset of the first record in the BAM file. */ static long findVirtualOffsetOfFirstRecord(final File bam) throws IOException { - final BAMFileReader reader = new BAMFileReader(bam, null, false, false, ValidationStringency.SILENT, new DefaultSAMRecordFactory()); + final BAMFileReader reader = + new BAMFileReader(bam, null, false, false, ValidationStringency.SILENT, new DefaultSAMRecordFactory()); final long offset = reader.mFirstRecordPointer; reader.close(); return offset; @@ -344,7 +406,13 @@ static long findVirtualOffsetOfFirstRecord(final File bam) throws IOException { * The caller is responsible for closing the stream. */ static long findVirtualOffsetOfFirstRecord(final SeekableStream seekableStream) throws IOException { - final BAMFileReader reader = new BAMFileReader(seekableStream, (SeekableStream) null, false, false, ValidationStringency.SILENT, new DefaultSAMRecordFactory()); + final BAMFileReader reader = new BAMFileReader( + seekableStream, + (SeekableStream) null, + false, + false, + ValidationStringency.SILENT, + new DefaultSAMRecordFactory()); return reader.mFirstRecordPointer; } @@ -363,7 +431,7 @@ void enableFileSource(final SamReader reader, final boolean enabled) { */ @Override protected void enableIndexCaching(final boolean enabled) { - if(mIndex != null) + if (mIndex != null) throw new SAMException("Unable to turn on index caching; index file has already been loaded."); this.mEnableIndexCaching = enabled; } @@ -381,11 +449,15 @@ protected void enableIndexMemoryMapping(final boolean enabled) { this.mEnableIndexMemoryMapping = enabled; } - @Override void enableCrcChecking(final boolean enabled) { + @Override + void enableCrcChecking(final boolean enabled) { this.mCompressedInputStream.setCheckCrcs(enabled); } - @Override void setSAMRecordFactory(final SAMRecordFactory samRecordFactory) { this.samRecordFactory = samRecordFactory; } + @Override + void setSAMRecordFactory(final SAMRecordFactory samRecordFactory) { + this.samRecordFactory = samRecordFactory; + } @Override public SamReader.Type type() { @@ -409,26 +481,27 @@ public boolean hasIndex() { */ @Override public BAMIndex getIndex() { - if(!hasIndex()) { + if (!hasIndex()) { throw new SAMException("No index is available for this BAM file."); } - if(mIndex == null) { + if (mIndex == null) { final SamIndexes samIndexType = getIndexType(); final SAMSequenceDictionary sequenceDictionary = getFileHeader().getSequenceDictionary(); - if(mIndexFile != null) { + if (mIndexFile != null) { if (samIndexType.equals(SamIndexes.BAI)) { - mIndex = mEnableIndexCaching ? new CachingBAMFileIndex(mIndexFile, sequenceDictionary, mEnableIndexMemoryMapping) + mIndex = mEnableIndexCaching + ? new CachingBAMFileIndex(mIndexFile, sequenceDictionary, mEnableIndexMemoryMapping) : new DiskBasedBAMFileIndex(mIndexFile, sequenceDictionary, mEnableIndexMemoryMapping); } else if (samIndexType.equals(SamIndexes.CSI)) { mIndex = new CSIIndex(mIndexFile, mEnableIndexMemoryMapping, sequenceDictionary); } else { throw new SAMFormatException("Unsupported BAM index file format: " + mIndexFile.getName()); } - } else if(mIndexStream != null) { + } else if (mIndexStream != null) { if (samIndexType.equals(SamIndexes.BAI)) { mIndex = new CachingBAMFileIndex(mIndexStream, sequenceDictionary); } else if (samIndexType.equals(SamIndexes.CSI)) { - mIndex = new CSIIndex(mIndexStream, sequenceDictionary); + mIndex = new CSIIndex(mIndexStream, sequenceDictionary); } else { throw new SAMFormatException("Unsupported BAM index file format: " + mIndexStream.getSource()); } @@ -455,13 +528,16 @@ public SamIndexes getIndexType() { if (samIndexesType == SamIndexes.BAI || samIndexesType == SamIndexes.CSI) { return samIndexesType; } - throw new SAMFormatException(String.format("Unknown BAM index file type: %s in %s", samIndexesType, mIndexStream.getSource())); + throw new SAMFormatException( + String.format("Unknown BAM index file type: %s in %s", samIndexesType, mIndexStream.getSource())); } return null; } - public void setEagerDecode(final boolean desired) { this.eagerDecode = desired; } + public void setEagerDecode(final boolean desired) { + this.eagerDecode = desired; + } @Override public void close() { @@ -541,7 +617,7 @@ public CloseableIterator getIterator(final SAMFileSpan chunks) { } // Create an iterator over the given chunk boundaries. - mCurrentIterator = new BAMFileIndexIterator(((BAMFileSpan)chunks).toCoordinateArray()); + mCurrentIterator = new BAMFileIndexIterator(((BAMFileSpan) chunks).toCoordinateArray()); return mCurrentIterator; } @@ -553,7 +629,7 @@ public CloseableIterator getIterator(final SAMFileSpan chunks) { */ @Override public SAMFileSpan getFilePointerSpanningReads() { - return new BAMFileSpan(new Chunk(mFirstRecordPointer,Long.MAX_VALUE)); + return new BAMFileSpan(new Chunk(mFirstRecordPointer, Long.MAX_VALUE)); } /** @@ -704,8 +780,9 @@ public CloseableIterator queryUnmapped() { * @param validationStringency Determines how stringent to be when validating the sam * @param source Note that this is used only for reporting errors. */ - protected static SAMFileHeader readHeader(final BinaryCodec stream, final ValidationStringency validationStringency, final String source) - throws IOException { + protected static SAMFileHeader readHeader( + final BinaryCodec stream, final ValidationStringency validationStringency, final String source) + throws IOException { final byte[] buffer = new byte[4]; stream.readBytes(buffer); @@ -717,27 +794,27 @@ protected static SAMFileHeader readHeader(final BinaryCodec stream, final Valida final String textHeader = stream.readString(headerTextLength); final SAMTextHeaderCodec headerCodec = new SAMTextHeaderCodec(); headerCodec.setValidationStringency(validationStringency); - final SAMFileHeader samFileHeader = headerCodec.decode(BufferedLineReader.fromString(textHeader), - source); + final SAMFileHeader samFileHeader = headerCodec.decode(BufferedLineReader.fromString(textHeader), source); final int sequenceCount = stream.readInt(); if (!samFileHeader.getSequenceDictionary().isEmpty()) { // It is allowed to have binary sequences but no text sequences, so only validate if both are present if (sequenceCount != samFileHeader.getSequenceDictionary().size()) { - throw new SAMFormatException("Number of sequences in text header (" + - samFileHeader.getSequenceDictionary().size() + - ") != number of sequences in binary header (" + sequenceCount + ") for file " + source); + throw new SAMFormatException("Number of sequences in text header (" + + samFileHeader.getSequenceDictionary().size() + + ") != number of sequences in binary header (" + + sequenceCount + ") for file " + source); } for (int i = 0; i < sequenceCount; i++) { final SAMSequenceRecord binarySequenceRecord = readSequenceRecord(stream, source); final SAMSequenceRecord sequenceRecord = samFileHeader.getSequence(i); if (!sequenceRecord.getSequenceName().equals(binarySequenceRecord.getSequenceName())) { - throw new SAMFormatException("For sequence " + i + ", text and binary have different names in file " + - source); + throw new SAMFormatException( + "For sequence " + i + ", text and binary have different names in file " + source); } if (sequenceRecord.getSequenceLength() != binarySequenceRecord.getSequenceLength()) { - throw new SAMFormatException("For sequence " + i + ", text and binary have different lengths in file " + - source); + throw new SAMFormatException( + "For sequence " + i + ", text and binary have different lengths in file " + source); } } } else { @@ -794,7 +871,6 @@ protected void assertOpen() { public void remove() { throw new UnsupportedOperationException("Not supported: remove"); } - } private class EmptyBamIterator extends AbstractBamIterator { @@ -810,8 +886,8 @@ public SAMRecord next() { } /** - - /** + * + * /** * Iterator for non-indexed sequential iteration through all SAMRecords in file. * Starting point of iteration is wherever current file position is when the iterator is constructed. */ @@ -829,8 +905,8 @@ private class BAMFileIterator extends AbstractBamIterator { */ BAMFileIterator(final boolean advance) { this.bamRecordCodec = new BAMRecordCodec(getFileHeader(), samRecordFactory); - this.bamRecordCodec.setInputStream(BAMFileReader.this.mStream.getInputStream(), - BAMFileReader.this.mStream.getInputFileName()); + this.bamRecordCodec.setInputStream( + BAMFileReader.this.mStream.getInputStream(), BAMFileReader.this.mStream.getInputFileName()); if (advance) { advance(); @@ -861,9 +937,10 @@ void advance() { mNextRecord.setValidationStringency(mValidationStringency); if (mValidationStringency != ValidationStringency.SILENT) { - final List validationErrors = mNextRecord.isValid(mValidationStringency == ValidationStringency.STRICT); - SAMUtils.processValidationErrors(validationErrors, - this.samRecordIndex, BAMFileReader.this.getValidationStringency()); + final List validationErrors = + mNextRecord.isValid(mValidationStringency == ValidationStringency.STRICT); + SAMUtils.processValidationErrors( + validationErrors, this.samRecordIndex, BAMFileReader.this.getValidationStringency()); } } if (eagerDecode && mNextRecord != null) { @@ -882,8 +959,9 @@ SAMRecord getNextRecord() throws IOException { final SAMRecord next = bamRecordCodec.decode(); final long stopCoordinate = mCompressedInputStream.getFilePointer(); - if(mReader != null && next != null) - next.setFileSource(new SAMFileSource(mReader,new BAMFileSpan(new Chunk(startCoordinate,stopCoordinate)))); + if (mReader != null && next != null) + next.setFileSource( + new SAMFileSource(mReader, new BAMFileSpan(new Chunk(startCoordinate, stopCoordinate)))); return next; } @@ -901,8 +979,7 @@ protected SAMRecord peek() { * @param referenceIndex Desired reference sequence. * @param start 1-based alignment start. */ - private CloseableIterator createStartingAtIndexIterator(final int referenceIndex, - final int start) { + private CloseableIterator createStartingAtIndexIterator(final int referenceIndex, final int start) { // Hit the index to determine the chunk boundaries for the required data. final BAMIndex fileIndex = getIndex(); @@ -914,7 +991,7 @@ private CloseableIterator createStartingAtIndexIterator(final int ref // Add some preprocessing filters for edge-case reads that don't fit into this // query type. - return new BAMQueryFilteringIterator(iterator,new BAMStartingAtIteratorFilter(referenceIndex,start)); + return new BAMQueryFilteringIterator(iterator, new BAMStartingAtIteratorFilter(referenceIndex, start)); } /** @@ -927,7 +1004,8 @@ public static BAMFileSpan getFileSpan(QueryInterval[] intervals, BAMIndex fileIn final BAMFileSpan[] inputSpans = new BAMFileSpan[intervals.length]; for (int i = 0; i < intervals.length; ++i) { final QueryInterval interval = intervals[i]; - final BAMFileSpan span = fileIndex.getSpanOverlapping(interval.referenceIndex, interval.start, interval.end); + final BAMFileSpan span = + fileIndex.getSpanOverlapping(interval.referenceIndex, interval.start, interval.end); inputSpans[i] = span; } final BAMFileSpan span; @@ -939,8 +1017,7 @@ public static BAMFileSpan getFileSpan(QueryInterval[] intervals, BAMIndex fileIn return span; } - private CloseableIterator createIndexIterator(final QueryInterval[] intervals, - final boolean contained) { + private CloseableIterator createIndexIterator(final QueryInterval[] intervals, final boolean contained) { QueryInterval.assertIntervalsOptimized(intervals); @@ -951,7 +1028,8 @@ private CloseableIterator createIndexIterator(final QueryInterval[] i // Add some preprocessing filters for edge-case reads that don't fit into this // query type. - return new BAMQueryFilteringIterator(iterator, new BAMQueryMultipleIntervalsIteratorFilter(intervals, contained)); + return new BAMQueryFilteringIterator( + iterator, new BAMQueryMultipleIntervalsIteratorFilter(intervals, contained)); } /** @@ -962,9 +1040,8 @@ private CloseableIterator createIndexIterator(final QueryInterval[] i * @param filePointers file pointer pairs corresponding to chunk boundaries for the * intervals */ - public CloseableIterator createIndexIterator(final QueryInterval[] intervals, - final boolean contained, - final long[] filePointers) { + public CloseableIterator createIndexIterator( + final QueryInterval[] intervals, final boolean contained, final long[] filePointers) { QueryInterval.assertIntervalsOptimized(intervals); @@ -973,7 +1050,8 @@ public CloseableIterator createIndexIterator(final QueryInterval[] in // Add some preprocessing filters for edge-case reads that don't fit into this // query type. - return new BAMQueryFilteringIterator(iterator, new BAMQueryMultipleIntervalsIteratorFilter(intervals, contained)); + return new BAMQueryFilteringIterator( + iterator, new BAMQueryMultipleIntervalsIteratorFilter(intervals, contained)); } /** @@ -998,18 +1076,16 @@ private class BAMFileIndexIterator extends BAMFileIterator { * @param filePointers the block / offset combination, stored in chunk format. */ BAMFileIndexIterator(final long[] filePointers) { - super(false); // delay advance() until after construction + super(false); // delay advance() until after construction mFilePointers = filePointers; advance(); } @Override - SAMRecord getNextRecord() - throws IOException { + SAMRecord getNextRecord() throws IOException { // Advance to next file block if necessary while (mCompressedInputStream.getFilePointer() >= mFilePointerLimit) { - if (mFilePointers == null || - mFilePointerIndex >= mFilePointers.length) { + if (mFilePointers == null || mFilePointerIndex >= mFilePointers.length) { return null; } final long startOffset = mFilePointers[mFilePointerIndex++]; @@ -1034,10 +1110,11 @@ public class BAMQueryFilteringIterator extends AbstractBamIterator { * The next record to be returned. Will be null if no such record exists. */ protected SAMRecord mNextRecord; + private final BAMIteratorFilter iteratorFilter; - public BAMQueryFilteringIterator(final CloseableIterator iterator, - final BAMIteratorFilter iteratorFilter) { + public BAMQueryFilteringIterator( + final CloseableIterator iterator, final BAMIteratorFilter iteratorFilter) { this.wrappedIterator = iterator; this.iteratorFilter = iteratorFilter; mNextRecord = advance(); @@ -1058,8 +1135,7 @@ public boolean hasNext() { */ @Override public SAMRecord next() { - if(!hasNext()) - throw new NoSuchElementException("BAMQueryFilteringIterator: no next element available"); + if (!hasNext()) throw new NoSuchElementException("BAMQueryFilteringIterator: no next element available"); final SAMRecord currentRead = mNextRecord; mNextRecord = advance(); return currentRead; @@ -1068,21 +1144,24 @@ public SAMRecord next() { SAMRecord advance() { while (true) { // Pull next record from stream - if(!wrappedIterator.hasNext()) - return null; + if (!wrappedIterator.hasNext()) return null; final SAMRecord record = wrappedIterator.next(); switch (iteratorFilter.compareToFilter(record)) { - case MATCHES_FILTER: return record; - case STOP_ITERATION: return null; - case CONTINUE_ITERATION: break; // keep looping - default: throw new SAMException("Unexpected return from compareToFilter"); + case MATCHES_FILTER: + return record; + case STOP_ITERATION: + return null; + case CONTINUE_ITERATION: + break; // keep looping + default: + throw new SAMException("Unexpected return from compareToFilter"); } } } } - private class BAMFileIndexUnmappedIterator extends BAMFileIterator { + private class BAMFileIndexUnmappedIterator extends BAMFileIterator { private BAMFileIndexUnmappedIterator() { while (this.hasNext() && peek().getReferenceIndex() != SAMRecord.NO_ALIGNMENT_REFERENCE_INDEX) { advance(); diff --git a/src/main/java/htsjdk/samtools/BAMFileSpan.java b/src/main/java/htsjdk/samtools/BAMFileSpan.java index d99760d2a8..4fe90198e7 100644 --- a/src/main/java/htsjdk/samtools/BAMFileSpan.java +++ b/src/main/java/htsjdk/samtools/BAMFileSpan.java @@ -24,7 +24,6 @@ package htsjdk.samtools; import htsjdk.samtools.util.StringUtil; - import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; @@ -90,8 +89,7 @@ public boolean isEmpty() { @Override public BAMFileSpan clone() { final BAMFileSpan clone = new BAMFileSpan(); - for(final Chunk chunk: chunks) - clone.chunks.add(chunk.clone()); + for (final Chunk chunk : chunks) clone.chunks.add(chunk.clone()); return clone; } @@ -104,30 +102,26 @@ public BAMFileSpan clone() { */ @Override public SAMFileSpan removeContentsBefore(final SAMFileSpan fileSpan) { - if(fileSpan == null) - return clone(); + if (fileSpan == null) return clone(); - if(!(fileSpan instanceof BAMFileSpan)) - throw new SAMException("Unable to compare "); + if (!(fileSpan instanceof BAMFileSpan)) throw new SAMException("Unable to compare "); - final BAMFileSpan bamFileSpan = (BAMFileSpan)fileSpan; + final BAMFileSpan bamFileSpan = (BAMFileSpan) fileSpan; - if(bamFileSpan.isEmpty()) - return clone(); + if (bamFileSpan.isEmpty()) return clone(); validateSorted(); final BAMFileSpan trimmedChunkList = new BAMFileSpan(); final long chunkStart = bamFileSpan.chunks.get(0).getChunkStart(); - for(final Chunk chunkToTrim: chunks) { - if(chunkToTrim.getChunkEnd() > chunkStart) { - if(chunkToTrim.getChunkStart() >= chunkStart) { + for (final Chunk chunkToTrim : chunks) { + if (chunkToTrim.getChunkEnd() > chunkStart) { + if (chunkToTrim.getChunkStart() >= chunkStart) { // This chunk from the list is completely beyond the start of the filtering chunk. trimmedChunkList.add(chunkToTrim.clone()); - } - else { + } else { // This chunk from the list partially overlaps the filtering chunk and must be trimmed. - trimmedChunkList.add(new Chunk(chunkStart,chunkToTrim.getChunkEnd())); + trimmedChunkList.add(new Chunk(chunkStart, chunkToTrim.getChunkEnd())); } } } @@ -143,30 +137,27 @@ public SAMFileSpan removeContentsBefore(final SAMFileSpan fileSpan) { * given chunk. */ public SAMFileSpan removeContentsAfter(final SAMFileSpan fileSpan) { - if(fileSpan == null) - return clone(); + if (fileSpan == null) return clone(); - if(!(fileSpan instanceof BAMFileSpan)) - throw new SAMException("Unable to compare "); + if (!(fileSpan instanceof BAMFileSpan)) throw new SAMException("Unable to compare "); - final BAMFileSpan bamFileSpan = (BAMFileSpan)fileSpan; + final BAMFileSpan bamFileSpan = (BAMFileSpan) fileSpan; - if(bamFileSpan.isEmpty()) - return clone(); + if (bamFileSpan.isEmpty()) return clone(); validateSorted(); final BAMFileSpan trimmedChunkList = new BAMFileSpan(); - final long chunkEnd = bamFileSpan.chunks.get(bamFileSpan.chunks.size() - 1).getChunkEnd(); - for(final Chunk chunkToTrim: chunks) { - if(chunkToTrim.getChunkStart() < chunkEnd) { - if(chunkToTrim.getChunkEnd() <= chunkEnd) { + final long chunkEnd = + bamFileSpan.chunks.get(bamFileSpan.chunks.size() - 1).getChunkEnd(); + for (final Chunk chunkToTrim : chunks) { + if (chunkToTrim.getChunkStart() < chunkEnd) { + if (chunkToTrim.getChunkEnd() <= chunkEnd) { // This chunk from the list is completely before the end of the filtering chunk. trimmedChunkList.add(chunkToTrim.clone()); - } - else { + } else { // This chunk from the list partially overlaps the filtering chunk and must be trimmed. - trimmedChunkList.add(new Chunk(chunkToTrim.getChunkStart(),chunkEnd)); + trimmedChunkList.add(new Chunk(chunkToTrim.getChunkStart(), chunkEnd)); } } } @@ -179,10 +170,10 @@ public SAMFileSpan removeContentsAfter(final SAMFileSpan fileSpan) { */ @Override public SAMFileSpan getContentsFollowing() { - if(chunks.isEmpty()) + if (chunks.isEmpty()) throw new SAMException("Unable to get the file pointer following this one: no data present."); validateSorted(); - return new BAMFileSpan(new Chunk(chunks.get(chunks.size()-1).getChunkEnd(),Long.MAX_VALUE)); + return new BAMFileSpan(new Chunk(chunks.get(chunks.size() - 1).getChunkEnd(), Long.MAX_VALUE)); } /** @@ -228,7 +219,7 @@ public long[] toCoordinateArray() { */ public long getFirstOffset() { final long result = 0; - if (chunks == null){ + if (chunks == null) { return result; } for (final Chunk chunk : chunks) { @@ -250,7 +241,7 @@ public List getChunks() { * @return The single chunk stored in this span */ protected Chunk getSingleChunk() { - if (chunks.size() != 1){ + if (chunks.size() != 1) { throw new SAMException("Expecting a single chunk for span. Found " + chunks.size()); } return chunks.get(0); @@ -265,12 +256,12 @@ protected Chunk getSingleChunk() { * @return A list of chunks. */ protected static SAMFileSpan toChunkList(final long[] coordinateArray) { - if(coordinateArray.length % 2 != 0) + if (coordinateArray.length % 2 != 0) throw new SAMException("Data supplied does not appear to be in coordinate array format."); final BAMFileSpan chunkList = new BAMFileSpan(); - for(int i = 0; i < coordinateArray.length; i += 2) - chunkList.add(new Chunk(coordinateArray[i],coordinateArray[i+1])); + for (int i = 0; i < coordinateArray.length; i += 2) + chunkList.add(new Chunk(coordinateArray[i], coordinateArray[i + 1])); chunkList.validateSorted(); @@ -281,9 +272,10 @@ protected static SAMFileSpan toChunkList(final long[] coordinateArray) { * Validates the list of chunks to ensure that they appear in sorted order. */ private void validateSorted() { - for(int i = 1; i < chunks.size(); i++) { - if(chunks.get(i).getChunkStart() < chunks.get(i-1).getChunkEnd()) - throw new SAMException(String.format("Chunk list is unsorted; chunk %s is before chunk %s",chunks.get(i-1),chunks.get(i))); + for (int i = 1; i < chunks.size(); i++) { + if (chunks.get(i).getChunkStart() < chunks.get(i - 1).getChunkEnd()) + throw new SAMException(String.format( + "Chunk list is unsorted; chunk %s is before chunk %s", chunks.get(i - 1), chunks.get(i))); } } @@ -303,7 +295,7 @@ public String toString() { public static BAMFileSpan merge(final BAMFileSpan[] spans) { final ArrayList inputChunks = new ArrayList(); for (final BAMFileSpan span : spans) { - if(span != null){ + if (span != null) { inputChunks.addAll(span.chunks); } } diff --git a/src/main/java/htsjdk/samtools/BAMFileWriter.java b/src/main/java/htsjdk/samtools/BAMFileWriter.java index ae6f6a0c26..b2e3381493 100644 --- a/src/main/java/htsjdk/samtools/BAMFileWriter.java +++ b/src/main/java/htsjdk/samtools/BAMFileWriter.java @@ -29,7 +29,6 @@ import htsjdk.samtools.util.IOUtil; import htsjdk.samtools.util.RuntimeIOException; import htsjdk.samtools.util.zip.DeflaterFactory; - import java.io.File; import java.io.IOException; import java.io.OutputStream; @@ -72,19 +71,25 @@ protected BAMFileWriter(final OutputStream os, final File file, final int compre outputBinaryCodec.setOutputFileName(getPathString(file)); } - protected BAMFileWriter(final OutputStream os, final File file, final int compressionLevel, final DeflaterFactory deflaterFactory) { + protected BAMFileWriter( + final OutputStream os, final File file, final int compressionLevel, final DeflaterFactory deflaterFactory) { blockCompressedOutputStream = new BlockCompressedOutputStream(os, file, compressionLevel, deflaterFactory); outputBinaryCodec = new BinaryCodec(blockCompressedOutputStream); outputBinaryCodec.setOutputFileName(getPathString(file)); } - protected BAMFileWriter(final OutputStream os, final String absoluteFilename, final int compressionLevel, final DeflaterFactory deflaterFactory) { - blockCompressedOutputStream = new BlockCompressedOutputStream(os, (Path)null, compressionLevel, deflaterFactory); - outputBinaryCodec = new BinaryCodec(blockCompressedOutputStream); - outputBinaryCodec.setOutputFileName(absoluteFilename); + protected BAMFileWriter( + final OutputStream os, + final String absoluteFilename, + final int compressionLevel, + final DeflaterFactory deflaterFactory) { + blockCompressedOutputStream = + new BlockCompressedOutputStream(os, (Path) null, compressionLevel, deflaterFactory); + outputBinaryCodec = new BinaryCodec(blockCompressedOutputStream); + outputBinaryCodec.setOutputFileName(absoluteFilename); } - private void prepareToWriteAlignments() { + private void prepareToWriteAlignments() { if (bamRecordCodec == null) { bamRecordCodec = new BAMRecordCodec(getFileHeader()); bamRecordCodec.setOutputStream(outputBinaryCodec.getOutputStream(), getFilename()); @@ -92,17 +97,17 @@ private void prepareToWriteAlignments() { } /** @return absolute path, or null if arg is null. */ - private String getPathString(final File path){ + private String getPathString(final File path) { return (path != null) ? path.getAbsolutePath() : null; } - // Allow enabling the bam index construction - // only enabled by factory method before anything is written - void enableBamIndexConstruction () { - if (!getSortOrder().equals(SAMFileHeader.SortOrder.coordinate)){ - throw new SAMException("Not creating BAM index since not sorted by coordinates: " + getSortOrder()); + // Allow enabling the bam index construction + // only enabled by factory method before anything is written + void enableBamIndexConstruction() { + if (!getSortOrder().equals(SAMFileHeader.SortOrder.coordinate)) { + throw new SAMException("Not creating BAM index since not sorted by coordinates: " + getSortOrder()); } - if(getFilename() == null){ + if (getFilename() == null) { throw new SAMException("Not creating BAM index since we don't have an output file name"); } bamIndexer = createBamIndex(getFilename()); @@ -110,12 +115,13 @@ void enableBamIndexConstruction () { private BAMIndexer createBamIndex(final String pathURI) { try { - final String indexFileBase = pathURI.endsWith(FileExtensions.BAM) ? - pathURI.substring(0, pathURI.lastIndexOf('.')) : pathURI; + final String indexFileBase = + pathURI.endsWith(FileExtensions.BAM) ? pathURI.substring(0, pathURI.lastIndexOf('.')) : pathURI; final Path indexPath = IOUtil.getPath(indexFileBase + FileExtensions.BAI_INDEX); if (Files.exists(indexPath)) { if (!Files.isWritable(indexPath)) { - throw new SAMException("Not creating BAM index since unable to write index file " + indexPath.toUri()); + throw new SAMException( + "Not creating BAM index since unable to write index file " + indexPath.toUri()); } } return new BAMIndexer(indexPath, getFileHeader()); @@ -153,13 +159,13 @@ protected void writeHeader(final String textHeader) { @Override protected void finish() { outputBinaryCodec.close(); - try { - if (bamIndexer != null) { - bamIndexer.finish(); - } - } catch (Exception e) { - throw new SAMException("Exception writing BAM index file", e); + try { + if (bamIndexer != null) { + bamIndexer.finish(); } + } catch (Exception e) { + throw new SAMException("Exception writing BAM index file", e); + } } /** @return absolute path in URI format, or null if this writer does not correspond to a file. @@ -173,7 +179,8 @@ protected String getFilename() { * Writes a header to a BAM file. samFileHeader and headerText are redundant - one can be used to regenerate the other but in * some instances we already have both so this allows us to save some cycles */ - protected static void writeHeader(final BinaryCodec outputBinaryCodec, final SAMFileHeader samFileHeader, final String headerText) { + protected static void writeHeader( + final BinaryCodec outputBinaryCodec, final SAMFileHeader samFileHeader, final String headerText) { outputBinaryCodec.writeBytes(BAMFileConstants.BAM_MAGIC); // calculate and write the length of the SAM file header text and the header text @@ -181,7 +188,8 @@ protected static void writeHeader(final BinaryCodec outputBinaryCodec, final SAM // write the sequences binarily. This is redundant with the text header outputBinaryCodec.writeInt(samFileHeader.getSequenceDictionary().size()); - for (final SAMSequenceRecord sequenceRecord: samFileHeader.getSequenceDictionary().getSequences()) { + for (final SAMSequenceRecord sequenceRecord : + samFileHeader.getSequenceDictionary().getSequences()) { outputBinaryCodec.writeString(sequenceRecord.getSequenceName(), true, true); outputBinaryCodec.writeInt(sequenceRecord.getSequenceLength()); } @@ -203,7 +211,8 @@ protected static void writeHeader(final BinaryCodec outputBinaryCodec, final SAM * @param samFileHeader the header to write */ public static void writeHeader(final OutputStream outputStream, final SAMFileHeader samFileHeader) { - final BlockCompressedOutputStream blockCompressedOutputStream = new BlockCompressedOutputStream(outputStream, (Path)null); + final BlockCompressedOutputStream blockCompressedOutputStream = + new BlockCompressedOutputStream(outputStream, (Path) null); final BinaryCodec outputBinaryCodec = new BinaryCodec(blockCompressedOutputStream); writeHeader(outputBinaryCodec, samFileHeader); try { diff --git a/src/main/java/htsjdk/samtools/BAMIndex.java b/src/main/java/htsjdk/samtools/BAMIndex.java index ffc93993ce..d55797241e 100644 --- a/src/main/java/htsjdk/samtools/BAMIndex.java +++ b/src/main/java/htsjdk/samtools/BAMIndex.java @@ -23,9 +23,8 @@ */ package htsjdk.samtools; -import java.io.Closeable; - import htsjdk.samtools.util.FileExtensions; +import java.io.Closeable; /** * A basic interface for querying BAM indices. @@ -55,7 +54,7 @@ public interface BAMIndex extends Closeable { * Gets the compressed chunks which should be searched for the contents of records contained by the span * referenceIndex:startPos-endPos, inclusive. See the BAM spec for more information on how a chunk is * represented. - * + * * @param referenceIndex The contig. * @param startPos Genomic start of query. * @param endPos Genomic end of query. diff --git a/src/main/java/htsjdk/samtools/BAMIndexContent.java b/src/main/java/htsjdk/samtools/BAMIndexContent.java index be9d856aa0..d4dd047f78 100644 --- a/src/main/java/htsjdk/samtools/BAMIndexContent.java +++ b/src/main/java/htsjdk/samtools/BAMIndexContent.java @@ -1,69 +1,75 @@ -/* - * The MIT License - * - * Copyright (c) 2010 The Broad Institute - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package htsjdk.samtools; - -/** - * Represents the contents of a bam index file for one reference. - * A BAM index (.bai) file contains information for all references in the bam file. - * This class describes the data present in the index file for one of these references; - * including the bins, chunks, and linear index. - */ -class BAMIndexContent extends BinningIndexContent { - /** - * Chunks containing metaData for the reference, e.g. number of aligned and unaligned records - */ - private final BAMIndexMetaData mMetaData; - - - - /** - * @param referenceSequence Content corresponds to this reference. - * @param binList Array of bins represented by this content, possibly sparse - * @param metaData Extra information about the reference in this index - * @param linearIndex Additional index used to optimize queries - */ - BAMIndexContent(final int referenceSequence, final BinList binList, final BAMIndexMetaData metaData, final LinearIndex linearIndex) { - super(referenceSequence, binList, linearIndex); - this.mMetaData = metaData; - } - - /** - * @param referenceSequence Content corresponds to this reference. - * @param bins Array of bins represented by this content, possibly sparse - * @param numberOfBins Number of non-null bins - * @param metaData Extra information about the reference in this index - * @param linearIndex Additional index used to optimize queries - */ - BAMIndexContent(final int referenceSequence, final Bin[] bins, final int numberOfBins, final BAMIndexMetaData metaData, final LinearIndex linearIndex) { - this(referenceSequence, new BinList(bins, numberOfBins), metaData, linearIndex); - } - - /** - * @return the meta data chunks for this content - */ - public BAMIndexMetaData getMetaData() { - return mMetaData; - } - -} +/* + * The MIT License + * + * Copyright (c) 2010 The Broad Institute + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package htsjdk.samtools; + +/** + * Represents the contents of a bam index file for one reference. + * A BAM index (.bai) file contains information for all references in the bam file. + * This class describes the data present in the index file for one of these references; + * including the bins, chunks, and linear index. + */ +class BAMIndexContent extends BinningIndexContent { + /** + * Chunks containing metaData for the reference, e.g. number of aligned and unaligned records + */ + private final BAMIndexMetaData mMetaData; + + /** + * @param referenceSequence Content corresponds to this reference. + * @param binList Array of bins represented by this content, possibly sparse + * @param metaData Extra information about the reference in this index + * @param linearIndex Additional index used to optimize queries + */ + BAMIndexContent( + final int referenceSequence, + final BinList binList, + final BAMIndexMetaData metaData, + final LinearIndex linearIndex) { + super(referenceSequence, binList, linearIndex); + this.mMetaData = metaData; + } + + /** + * @param referenceSequence Content corresponds to this reference. + * @param bins Array of bins represented by this content, possibly sparse + * @param numberOfBins Number of non-null bins + * @param metaData Extra information about the reference in this index + * @param linearIndex Additional index used to optimize queries + */ + BAMIndexContent( + final int referenceSequence, + final Bin[] bins, + final int numberOfBins, + final BAMIndexMetaData metaData, + final LinearIndex linearIndex) { + this(referenceSequence, new BinList(bins, numberOfBins), metaData, linearIndex); + } + + /** + * @return the meta data chunks for this content + */ + public BAMIndexMetaData getMetaData() { + return mMetaData; + } +} diff --git a/src/main/java/htsjdk/samtools/BAMIndexMerger.java b/src/main/java/htsjdk/samtools/BAMIndexMerger.java index 2d0890e750..0ba360cd74 100644 --- a/src/main/java/htsjdk/samtools/BAMIndexMerger.java +++ b/src/main/java/htsjdk/samtools/BAMIndexMerger.java @@ -25,7 +25,6 @@ import htsjdk.samtools.seekablestream.SeekableStream; import htsjdk.samtools.util.BlockCompressedFilePointerUtil; - import java.io.OutputStream; import java.util.ArrayList; import java.util.Arrays; @@ -78,8 +77,9 @@ public void processIndex(final AbstractBAMFileIndex index, final long partLength sequenceDictionary = index.getBamDictionary(); } if (index.getNumberOfReferences() != numReferences) { - throw new IllegalArgumentException( - String.format("Cannot merge BAI files with different number of references, %s and %s.", numReferences, index.getNumberOfReferences())); + throw new IllegalArgumentException(String.format( + "Cannot merge BAI files with different number of references, %s and %s.", + numReferences, index.getNumberOfReferences())); } index.getBamDictionary().assertSameDictionary(sequenceDictionary); // just store the indexes rather than computing the BAMIndexContent for each ref, @@ -99,7 +99,8 @@ public void finish(final long dataFileLength) { try (BinaryBAMIndexWriter writer = new BinaryBAMIndexWriter(numReferences, out)) { for (int ref = 0; ref < numReferences; ref++) { final int r = ref; - List bamIndexContentList = indexes.stream().map(index -> index.getQueryResults(r)).collect(Collectors.toList()); + List bamIndexContentList = + indexes.stream().map(index -> index.getQueryResults(r)).collect(Collectors.toList()); final BAMIndexContent bamIndexContent = mergeBAMIndexContent(ref, bamIndexContentList, offsets); writer.writeReference(bamIndexContent); } @@ -111,8 +112,8 @@ public static AbstractBAMFileIndex openIndex(SeekableStream stream, SAMSequenceD return new CachingBamFileIndexOptimizedForMerging(stream, dictionary); } - private static BAMIndexContent mergeBAMIndexContent(final int referenceSequence, - final List bamIndexContentList, final long[] offsets) { + private static BAMIndexContent mergeBAMIndexContent( + final int referenceSequence, final List bamIndexContentList, final long[] offsets) { final List binLists = new ArrayList<>(); final List metaDataList = new ArrayList<>(); final List linearIndexes = new ArrayList<>(); @@ -140,9 +141,14 @@ private static BAMIndexContent mergeBAMIndexContent(final int referenceSequence, * @param offsets bin i will be shifted by offset i * @return the merged bins */ - public static BinningIndexContent.BinList mergeBins(final List binLists, final long[] offsets) { + public static BinningIndexContent.BinList mergeBins( + final List binLists, final long[] offsets) { final List mergedBins = new ArrayList<>(); - final int maxBinNumber = binLists.stream().filter(Objects::nonNull).mapToInt(bl -> bl.maxBinNumber).max().orElse(0); + final int maxBinNumber = binLists.stream() + .filter(Objects::nonNull) + .mapToInt(bl -> bl.maxBinNumber) + .max() + .orElse(0); int commonNonNullBins = 0; for (int i = 0; i <= maxBinNumber; i++) { final List nonNullBins = new ArrayList<>(); @@ -161,8 +167,11 @@ public static BinningIndexContent.BinList mergeBins(final List bins) { final List allChunks = new ArrayList<>(); for (Bin b : bins) { if (b.getReferenceSequence() != referenceSequence) { - throw new IllegalArgumentException(String.format("Bins have different reference sequences, %s and %s.", b.getReferenceSequence(), referenceSequence)); + throw new IllegalArgumentException(String.format( + "Bins have different reference sequences, %s and %s.", + b.getReferenceSequence(), referenceSequence)); } if (b.getBinNumber() != binNumber) { - throw new IllegalArgumentException(String.format("Bins have different numbers, %s and %s.", b.getBinNumber(), binNumber)); + throw new IllegalArgumentException( + String.format("Bins have different numbers, %s and %s.", b.getBinNumber(), binNumber)); } allChunks.addAll(b.getChunkList()); } @@ -241,7 +253,8 @@ private static BAMIndexMetaData mergeMetaData(final List metaD * @param offsets linear index i will be shifted by offset i * @return the merged linear index */ - public static LinearIndex mergeLinearIndexes(final int referenceSequence, final List linearIndexes, final long[] offsets) { + public static LinearIndex mergeLinearIndexes( + final int referenceSequence, final List linearIndexes, final long[] offsets) { int maxIndex = -1; for (LinearIndex li : linearIndexes) { if (li == null) { diff --git a/src/main/java/htsjdk/samtools/BAMIndexMetaData.java b/src/main/java/htsjdk/samtools/BAMIndexMetaData.java index e2b1818bec..8e4ad4531a 100644 --- a/src/main/java/htsjdk/samtools/BAMIndexMetaData.java +++ b/src/main/java/htsjdk/samtools/BAMIndexMetaData.java @@ -1,287 +1,289 @@ -/* - * The MIT License - * - * Copyright (c) 2010 The Broad Institute - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package htsjdk.samtools; - -import htsjdk.samtools.cram.BAIEntry; -import htsjdk.samtools.util.BlockCompressedFilePointerUtil; - -import java.io.File; -import java.io.IOException; -import java.util.List; - -/** - * Metadata about the bam index contained within the bam index. - * One instance created per index file. - */ -public class BAMIndexMetaData { - - // information for the entire index. - // stored at the end of the index - private long noCoordinateRecords = 0; - - // information for each reference. - // stored in two chunks in bin # MAX_BINS - private long firstOffset = -1; - private long lastOffset = 0; - private int alignedRecords = 0; - private int unAlignedRecords = 0; // unmapped, but associated with this reference - - - /** - * Constructor used when writing an index - * construct one instance for each index generated - */ - BAMIndexMetaData() { - noCoordinateRecords = 0; - newReference(); - } - - /** - * Constructor used when reading an index - * construct one instance for each index generated - */ - BAMIndexMetaData(List chunkList) { - noCoordinateRecords = 0; - - if (chunkList == null || chunkList.isEmpty()) { - // System.out.println("No metadata chunks"); - } else if (chunkList.size() != 2) { - throw new SAMException("Unexpected number of metadata chunks " + (chunkList.size())); - } - // fill in the first/lastOffset un/alignedRecords from this - boolean firstChunk = true; - if (chunkList != null) { - for (Chunk c : chunkList) { - long start = c.getChunkStart(); - long end = c.getChunkEnd(); - if (firstChunk) { - firstOffset = start; - lastOffset = end; - firstChunk = false; - } else { - firstChunk = true; - alignedRecords = (int) start; - unAlignedRecords = (int) end; - } - } - } - } - - private BAMIndexMetaData(final long firstOffset, final long lastOffset, final int alignedRecords, final int unAlignedRecords) { - this.firstOffset = firstOffset; - this.lastOffset = lastOffset; - this.alignedRecords = alignedRecords; - this.unAlignedRecords = unAlignedRecords; - } - - /** - * @return the count of aligned records associated with this reference - */ - public int getAlignedRecordCount() { - return alignedRecords; - } - - /** - * @return the count of unaligned records associated with this reference - */ - public int getUnalignedRecordCount() { - return unAlignedRecords; - } - - /** - * Call for each new reference sequence encountered - */ - void newReference() { - firstOffset = -1; - lastOffset = 0; - alignedRecords = 0; - unAlignedRecords = 0; - } - - /** - * Extract relevant metaData from the record and its filePointer - * Call only once per record in the file being indexed - * - * @param rec - */ - void recordMetaData(final SAMRecord rec) { - - final int alignmentStart = rec.getAlignmentStart(); - if (alignmentStart == SAMRecord.NO_ALIGNMENT_START) { - incrementNoCoordinateRecordCount(); - return; - } - - if (rec.getFileSource() == null) { - throw new SAMException("BAM cannot be indexed without setting a fileSource for record " + rec); - } - final Chunk newChunk = ((BAMFileSpan) rec.getFileSource().getFilePointer()).getSingleChunk(); - final long start = newChunk.getChunkStart(); - final long end = newChunk.getChunkEnd(); - - if (rec.getReadUnmappedFlag()) { - unAlignedRecords++; - } else { - alignedRecords++; - } - if (BlockCompressedFilePointerUtil.compare(start, firstOffset) < 1 || firstOffset == -1) { - this.firstOffset = start; - } - if (BlockCompressedFilePointerUtil.compare(lastOffset, end) < 1) { - this.lastOffset = end; - } - } - - // The resolution of a CRAM BAI index is more coarse than for BAM BAI. Each entry - // is represented by a BAIEntry that represents a slice (or, in the case of - // MULTI_REFERENCE slices, a subset of a slice), rather than SAMRecords. - void recordMetaData(final BAIEntry baiEntry) { - alignedRecords += baiEntry.getMappedReadsCount(); - noCoordinateRecords += baiEntry.getUnmappedUnplacedReadsCount(); - unAlignedRecords += baiEntry.getUnmappedReadsCount(); - - final long start = baiEntry.getSliceByteOffsetFromCompressionHeaderStart(); - - if (BlockCompressedFilePointerUtil.compare(start, firstOffset) < 1 || firstOffset == -1) { - this.firstOffset = start; - // not actually used, so set it to a dummy value (start) - // see https://github.com/samtools/htsjdk/issues/401 - this.lastOffset = start; - } - } - - /** - * Call whenever a reference with no coordinate information is encountered in the bam file - */ - void incrementNoCoordinateRecordCount() { - noCoordinateRecords++; - } - - /** - * Set local variable. Normally noCoordinateRecord count accessed from AbstractBAMFileIndex when reading - */ - private void setNoCoordinateRecordCount(long count) { - noCoordinateRecords = count; - } - - - /** - * @return the count of records with no coordinate information in the bam file. - * Not public, since only used by BAMIndexer when writing bam index. - * Readers of bam index should use AbstractBAMFileIndex.getNoCoordinateRecordCount. - */ - long getNoCoordinateRecordCount() { - return noCoordinateRecords; - } - - /** - * @return the first virtual file offset used by this reference - */ - long getFirstOffset() { - return firstOffset; - } - - /** - * @return the last virtual file offset used by this reference - */ - long getLastOffset() { - return lastOffset; - } - - /** - * Return a new metadata object shifted by a given (non-virtual) offset. - * - * @param offset the offset in bytes - * @return a new metadata object shifted by the given offset - * @see BlockCompressedFilePointerUtil#shift(long, long) - */ - BAMIndexMetaData shift(final long offset) { - final long newFirstOffset = firstOffset == -1 ? firstOffset : BlockCompressedFilePointerUtil.shift(firstOffset, offset); // -1 is unset - final long newLastOffset = lastOffset == 0 ? lastOffset : BlockCompressedFilePointerUtil.shift(lastOffset, offset); // 0 is unset - return new BAMIndexMetaData(newFirstOffset, newLastOffset, alignedRecords, unAlignedRecords); - } - - /** - * Prints meta-data statistics from BAM index (.bai or .csi) file - * Statistics include count of aligned and unaligned reads for each reference sequence - * and a count of all records with no start coordinate - */ - static public void printIndexStats(final File inputBamFile) { - try { - final BAMFileReader bam = new BAMFileReader(inputBamFile, null, false, false, ValidationStringency.SILENT, new DefaultSAMRecordFactory()); - if (!bam.hasIndex() || bam.getIndexType() == null) { - throw new SAMException("No index for bam file " + inputBamFile); - } - - BAMIndexMetaData[] data = getIndexStats(bam); - if (data == null) { - throw new SAMException("Exception in getting index statistics"); - } - - // read through all the bins of every reference. - int nRefs = bam.getFileHeader().getSequenceDictionary().size(); - for (int i = 0; i < nRefs; i++) { - final SAMSequenceRecord seq = bam.getFileHeader().getSequence(i); - if (seq == null) continue; - final String sequenceName = seq.getSequenceName(); - final int sequenceLength = seq.getSequenceLength(); - System.out.print(sequenceName + ' ' + "length=\t" + sequenceLength); - if (data[i] == null) { - System.out.println(); - continue; - } - System.out.println("\tAligned= " + data[i].getAlignedRecordCount() + - "\tUnaligned= " + data[i].getUnalignedRecordCount()); - } - System.out.println("NoCoordinateCount= " + data[0].getNoCoordinateRecordCount()); - } catch (IOException e) { - throw new SAMException("Exception in getting index statistics", e); - } - } - - /** - * Prints meta-data statistics from BAM index (.bai or .csi) file - * Statistics include count of aligned and unaligned reads for each reference sequence - * and a count of all records with no start coordinate - */ - static public BAMIndexMetaData[] getIndexStats(final BAMFileReader bam) { - - AbstractBAMFileIndex index = (AbstractBAMFileIndex) bam.getIndex(); - // read through all the bins of every reference. - int nRefs = index.getNumberOfReferences(); - BAMIndexMetaData[] result = new BAMIndexMetaData[nRefs == 0 ? 1 : nRefs]; - for (int i = 0; i < nRefs; i++) { - result[i] = index.getMetaData(i); - } - - if (result[0] == null) { - result[0] = new BAMIndexMetaData(); - } - final Long noCoordCount = index.getNoCoordinateCount(); - if (noCoordCount != null) // null in old index files without metadata - result[0].setNoCoordinateRecordCount(noCoordCount); - - return result; - } -} +/* + * The MIT License + * + * Copyright (c) 2010 The Broad Institute + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package htsjdk.samtools; + +import htsjdk.samtools.cram.BAIEntry; +import htsjdk.samtools.util.BlockCompressedFilePointerUtil; +import java.io.File; +import java.io.IOException; +import java.util.List; + +/** + * Metadata about the bam index contained within the bam index. + * One instance created per index file. + */ +public class BAMIndexMetaData { + + // information for the entire index. + // stored at the end of the index + private long noCoordinateRecords = 0; + + // information for each reference. + // stored in two chunks in bin # MAX_BINS + private long firstOffset = -1; + private long lastOffset = 0; + private int alignedRecords = 0; + private int unAlignedRecords = 0; // unmapped, but associated with this reference + + /** + * Constructor used when writing an index + * construct one instance for each index generated + */ + BAMIndexMetaData() { + noCoordinateRecords = 0; + newReference(); + } + + /** + * Constructor used when reading an index + * construct one instance for each index generated + */ + BAMIndexMetaData(List chunkList) { + noCoordinateRecords = 0; + + if (chunkList == null || chunkList.isEmpty()) { + // System.out.println("No metadata chunks"); + } else if (chunkList.size() != 2) { + throw new SAMException("Unexpected number of metadata chunks " + (chunkList.size())); + } + // fill in the first/lastOffset un/alignedRecords from this + boolean firstChunk = true; + if (chunkList != null) { + for (Chunk c : chunkList) { + long start = c.getChunkStart(); + long end = c.getChunkEnd(); + if (firstChunk) { + firstOffset = start; + lastOffset = end; + firstChunk = false; + } else { + firstChunk = true; + alignedRecords = (int) start; + unAlignedRecords = (int) end; + } + } + } + } + + private BAMIndexMetaData( + final long firstOffset, final long lastOffset, final int alignedRecords, final int unAlignedRecords) { + this.firstOffset = firstOffset; + this.lastOffset = lastOffset; + this.alignedRecords = alignedRecords; + this.unAlignedRecords = unAlignedRecords; + } + + /** + * @return the count of aligned records associated with this reference + */ + public int getAlignedRecordCount() { + return alignedRecords; + } + + /** + * @return the count of unaligned records associated with this reference + */ + public int getUnalignedRecordCount() { + return unAlignedRecords; + } + + /** + * Call for each new reference sequence encountered + */ + void newReference() { + firstOffset = -1; + lastOffset = 0; + alignedRecords = 0; + unAlignedRecords = 0; + } + + /** + * Extract relevant metaData from the record and its filePointer + * Call only once per record in the file being indexed + * + * @param rec + */ + void recordMetaData(final SAMRecord rec) { + + final int alignmentStart = rec.getAlignmentStart(); + if (alignmentStart == SAMRecord.NO_ALIGNMENT_START) { + incrementNoCoordinateRecordCount(); + return; + } + + if (rec.getFileSource() == null) { + throw new SAMException("BAM cannot be indexed without setting a fileSource for record " + rec); + } + final Chunk newChunk = ((BAMFileSpan) rec.getFileSource().getFilePointer()).getSingleChunk(); + final long start = newChunk.getChunkStart(); + final long end = newChunk.getChunkEnd(); + + if (rec.getReadUnmappedFlag()) { + unAlignedRecords++; + } else { + alignedRecords++; + } + if (BlockCompressedFilePointerUtil.compare(start, firstOffset) < 1 || firstOffset == -1) { + this.firstOffset = start; + } + if (BlockCompressedFilePointerUtil.compare(lastOffset, end) < 1) { + this.lastOffset = end; + } + } + + // The resolution of a CRAM BAI index is more coarse than for BAM BAI. Each entry + // is represented by a BAIEntry that represents a slice (or, in the case of + // MULTI_REFERENCE slices, a subset of a slice), rather than SAMRecords. + void recordMetaData(final BAIEntry baiEntry) { + alignedRecords += baiEntry.getMappedReadsCount(); + noCoordinateRecords += baiEntry.getUnmappedUnplacedReadsCount(); + unAlignedRecords += baiEntry.getUnmappedReadsCount(); + + final long start = baiEntry.getSliceByteOffsetFromCompressionHeaderStart(); + + if (BlockCompressedFilePointerUtil.compare(start, firstOffset) < 1 || firstOffset == -1) { + this.firstOffset = start; + // not actually used, so set it to a dummy value (start) + // see https://github.com/samtools/htsjdk/issues/401 + this.lastOffset = start; + } + } + + /** + * Call whenever a reference with no coordinate information is encountered in the bam file + */ + void incrementNoCoordinateRecordCount() { + noCoordinateRecords++; + } + + /** + * Set local variable. Normally noCoordinateRecord count accessed from AbstractBAMFileIndex when reading + */ + private void setNoCoordinateRecordCount(long count) { + noCoordinateRecords = count; + } + + /** + * @return the count of records with no coordinate information in the bam file. + * Not public, since only used by BAMIndexer when writing bam index. + * Readers of bam index should use AbstractBAMFileIndex.getNoCoordinateRecordCount. + */ + long getNoCoordinateRecordCount() { + return noCoordinateRecords; + } + + /** + * @return the first virtual file offset used by this reference + */ + long getFirstOffset() { + return firstOffset; + } + + /** + * @return the last virtual file offset used by this reference + */ + long getLastOffset() { + return lastOffset; + } + + /** + * Return a new metadata object shifted by a given (non-virtual) offset. + * + * @param offset the offset in bytes + * @return a new metadata object shifted by the given offset + * @see BlockCompressedFilePointerUtil#shift(long, long) + */ + BAMIndexMetaData shift(final long offset) { + final long newFirstOffset = firstOffset == -1 + ? firstOffset + : BlockCompressedFilePointerUtil.shift(firstOffset, offset); // -1 is unset + final long newLastOffset = + lastOffset == 0 ? lastOffset : BlockCompressedFilePointerUtil.shift(lastOffset, offset); // 0 is unset + return new BAMIndexMetaData(newFirstOffset, newLastOffset, alignedRecords, unAlignedRecords); + } + + /** + * Prints meta-data statistics from BAM index (.bai or .csi) file + * Statistics include count of aligned and unaligned reads for each reference sequence + * and a count of all records with no start coordinate + */ + public static void printIndexStats(final File inputBamFile) { + try { + final BAMFileReader bam = new BAMFileReader( + inputBamFile, null, false, false, ValidationStringency.SILENT, new DefaultSAMRecordFactory()); + if (!bam.hasIndex() || bam.getIndexType() == null) { + throw new SAMException("No index for bam file " + inputBamFile); + } + + BAMIndexMetaData[] data = getIndexStats(bam); + if (data == null) { + throw new SAMException("Exception in getting index statistics"); + } + + // read through all the bins of every reference. + int nRefs = bam.getFileHeader().getSequenceDictionary().size(); + for (int i = 0; i < nRefs; i++) { + final SAMSequenceRecord seq = bam.getFileHeader().getSequence(i); + if (seq == null) continue; + final String sequenceName = seq.getSequenceName(); + final int sequenceLength = seq.getSequenceLength(); + System.out.print(sequenceName + ' ' + "length=\t" + sequenceLength); + if (data[i] == null) { + System.out.println(); + continue; + } + System.out.println("\tAligned= " + data[i].getAlignedRecordCount() + "\tUnaligned= " + + data[i].getUnalignedRecordCount()); + } + System.out.println("NoCoordinateCount= " + data[0].getNoCoordinateRecordCount()); + } catch (IOException e) { + throw new SAMException("Exception in getting index statistics", e); + } + } + + /** + * Prints meta-data statistics from BAM index (.bai or .csi) file + * Statistics include count of aligned and unaligned reads for each reference sequence + * and a count of all records with no start coordinate + */ + public static BAMIndexMetaData[] getIndexStats(final BAMFileReader bam) { + + AbstractBAMFileIndex index = (AbstractBAMFileIndex) bam.getIndex(); + // read through all the bins of every reference. + int nRefs = index.getNumberOfReferences(); + BAMIndexMetaData[] result = new BAMIndexMetaData[nRefs == 0 ? 1 : nRefs]; + for (int i = 0; i < nRefs; i++) { + result[i] = index.getMetaData(i); + } + + if (result[0] == null) { + result[0] = new BAMIndexMetaData(); + } + final Long noCoordCount = index.getNoCoordinateCount(); + if (noCoordCount != null) // null in old index files without metadata + result[0].setNoCoordinateRecordCount(noCoordCount); + + return result; + } +} diff --git a/src/main/java/htsjdk/samtools/BAMIndexWriter.java b/src/main/java/htsjdk/samtools/BAMIndexWriter.java index aafcb5fbff..b6aaa2a4cb 100644 --- a/src/main/java/htsjdk/samtools/BAMIndexWriter.java +++ b/src/main/java/htsjdk/samtools/BAMIndexWriter.java @@ -30,7 +30,7 @@ * * @author mborkan */ -interface BAMIndexWriter extends Closeable { // note - only package visibility +interface BAMIndexWriter extends Closeable { // note - only package visibility /** * Write the data for one alignments to one reference sequence @@ -51,5 +51,4 @@ interface BAMIndexWriter extends Closeable { // note - only package visibility */ @Override public void close(); - -} \ No newline at end of file +} diff --git a/src/main/java/htsjdk/samtools/BAMIndexer.java b/src/main/java/htsjdk/samtools/BAMIndexer.java index 139af8d9a0..341b268bad 100644 --- a/src/main/java/htsjdk/samtools/BAMIndexer.java +++ b/src/main/java/htsjdk/samtools/BAMIndexer.java @@ -24,7 +24,6 @@ package htsjdk.samtools; import htsjdk.samtools.util.Log; - import java.io.File; import java.io.OutputStream; import java.nio.file.Path; @@ -88,7 +87,8 @@ public BAMIndexer(final OutputStream output, final SAMFileHeader fileHeader) { * if false, leave uninitialized values as -1, which is required when merging index files * (see {@link BAMIndexMerger}) */ - public BAMIndexer(final OutputStream output, final SAMFileHeader fileHeader, final boolean fillInUninitializedValues) { + public BAMIndexer( + final OutputStream output, final SAMFileHeader fileHeader, final boolean fillInUninitializedValues) { this(fileHeader, numRefs -> new BinaryBAMIndexWriter(numRefs, output), fillInUninitializedValues); } @@ -98,13 +98,16 @@ public BAMIndexer(final OutputStream output, final SAMFileHeader fileHeader, fin * @param fileHeader header for the corresponding bam file. * @param createWrite a lambda that, given an Integer numReferences value, will create a BinaryBAMIndexWriter * with that value and an appropriate output. - */ - private BAMIndexer(final SAMFileHeader fileHeader, Function createWriter, final boolean fillInUninitializedValues) { + */ + private BAMIndexer( + final SAMFileHeader fileHeader, + Function createWriter, + final boolean fillInUninitializedValues) { if (fileHeader.getSortOrder() != SAMFileHeader.SortOrder.coordinate) { if (fileHeader.getSortOrder() == SAMFileHeader.SortOrder.unsorted) { - log.warn("For indexing, the BAM file is required to be coordinate sorted. Attempting to index \"unsorted\" BAM file."); - } - else { + log.warn( + "For indexing, the BAM file is required to be coordinate sorted. Attempting to index \"unsorted\" BAM file."); + } else { throw new SAMException("Indexing requires a coordinate-sorted input BAM."); } } @@ -163,7 +166,7 @@ private void advanceToReference(final int nextReference) { * @param output BAM Index (.bai) file (or bai.txt file when text) * @param textOutput Whether to create text output or binary */ - static public void createAndWriteIndex(final File input, final File output, final boolean textOutput) { + public static void createAndWriteIndex(final File input, final File output, final boolean textOutput) { // content is from an existing bai file. @@ -231,8 +234,8 @@ public void processAlignment(final SAMRecord rec) { // various checks final int reference = rec.getReferenceIndex(); if (reference != currentReference) { - throw new SAMException("Unexpected reference " + reference + - " when constructing index for " + currentReference + " for record " + rec); + throw new SAMException("Unexpected reference " + reference + " when constructing index for " + + currentReference + " for record " + rec); } binningIndexBuilder.processFeature(new BinningIndexBuilder.FeatureToBeIndexed() { @@ -247,18 +250,20 @@ public int getEnd() { } @Override - public Integer getIndexingBin() { return rec.computeIndexingBin(); } + public Integer getIndexingBin() { + return rec.computeIndexingBin(); + } @Override public Chunk getChunk() { final SAMFileSource source = rec.getFileSource(); if (source == null) { - throw new SAMException("No source (virtual file offsets); needed for indexing on BAM Record " + rec); + throw new SAMException( + "No source (virtual file offsets); needed for indexing on BAM Record " + rec); } return ((BAMFileSpan) source.getFilePointer()).getSingleChunk(); } }); - } /** @@ -270,14 +275,17 @@ public Chunk getChunk() { public BAMIndexContent processReference(final int reference) { if (reference != currentReference) { - throw new SAMException("Unexpected reference " + reference + " when constructing index for " + currentReference); + throw new SAMException( + "Unexpected reference " + reference + " when constructing index for " + currentReference); } final BinningIndexContent indexContent = binningIndexBuilder.generateIndexContent(); if (indexContent == null) return null; - return new BAMIndexContent(indexContent.getReferenceSequence(), indexContent.getBins(), - indexStats, indexContent.getLinearIndex()); - + return new BAMIndexContent( + indexContent.getReferenceSequence(), + indexContent.getBins(), + indexStats, + indexContent.getLinearIndex()); } /** @@ -295,8 +303,10 @@ void startNewReference() { // I'm not crazy about recycling this object, but that is the way it was originally written and // it helps keep track of no-coordinate read count (which shouldn't be stored in this class anyway). indexStats.newReference(); - binningIndexBuilder = new BinningIndexBuilder(currentReference, - sequenceDictionary.getSequence(currentReference).getSequenceLength(), fillInUninitializedValues); + binningIndexBuilder = new BinningIndexBuilder( + currentReference, + sequenceDictionary.getSequence(currentReference).getSequenceLength(), + fillInUninitializedValues); } } diff --git a/src/main/java/htsjdk/samtools/BAMIteratorFilter.java b/src/main/java/htsjdk/samtools/BAMIteratorFilter.java index bc7d2c0259..3af3ddaf47 100644 --- a/src/main/java/htsjdk/samtools/BAMIteratorFilter.java +++ b/src/main/java/htsjdk/samtools/BAMIteratorFilter.java @@ -1,12 +1,14 @@ package htsjdk.samtools; - /** * Interface implemented by filetering iterators used for BAM/CRAM readers. */ interface BAMIteratorFilter { public enum IntervalComparison { - BEFORE, AFTER, OVERLAPPING, CONTAINED + BEFORE, + AFTER, + OVERLAPPING, + CONTAINED } /** @@ -14,7 +16,9 @@ public enum IntervalComparison { * how to handle each SAMRecord. */ public enum FilteringIteratorState { - MATCHES_FILTER, STOP_ITERATION, CONTINUE_ITERATION + MATCHES_FILTER, + STOP_ITERATION, + CONTINUE_ITERATION } /** @@ -23,4 +27,3 @@ public enum FilteringIteratorState { */ FilteringIteratorState compareToFilter(final SAMRecord record); } - diff --git a/src/main/java/htsjdk/samtools/BAMQueryMultipleIntervalsIteratorFilter.java b/src/main/java/htsjdk/samtools/BAMQueryMultipleIntervalsIteratorFilter.java index 8dadc692eb..2f1fba9e0b 100644 --- a/src/main/java/htsjdk/samtools/BAMQueryMultipleIntervalsIteratorFilter.java +++ b/src/main/java/htsjdk/samtools/BAMQueryMultipleIntervalsIteratorFilter.java @@ -10,9 +10,7 @@ public class BAMQueryMultipleIntervalsIteratorFilter implements BAMIteratorFilte final boolean contained; int intervalIndex = 0; - - public BAMQueryMultipleIntervalsIteratorFilter(final QueryInterval[] intervals, - final boolean contained) { + public BAMQueryMultipleIntervalsIteratorFilter(final QueryInterval[] intervals, final boolean contained) { this.contained = contained; this.intervals = intervals; } @@ -23,14 +21,20 @@ public FilteringIteratorState compareToFilter(final SAMRecord record) { final IntervalComparison comparison = compareIntervalToRecord(intervals[intervalIndex], record); switch (comparison) { // Interval is before SAMRecord. Try next interval; - case BEFORE: ++intervalIndex; break; + case BEFORE: + ++intervalIndex; + break; // Interval is after SAMRecord. Keep scanning forward in SAMRecords - case AFTER: return FilteringIteratorState.CONTINUE_ITERATION; + case AFTER: + return FilteringIteratorState.CONTINUE_ITERATION; // Found a good record - case CONTAINED: return FilteringIteratorState.MATCHES_FILTER; + case CONTAINED: + return FilteringIteratorState.MATCHES_FILTER; // Either found a good record, or else keep scanning SAMRecords - case OVERLAPPING: return - (contained ? FilteringIteratorState.CONTINUE_ITERATION : FilteringIteratorState.MATCHES_FILTER); + case OVERLAPPING: + return (contained + ? FilteringIteratorState.CONTINUE_ITERATION + : FilteringIteratorState.MATCHES_FILTER); } } // Went past the last interval @@ -39,7 +43,7 @@ public FilteringIteratorState compareToFilter(final SAMRecord record) { public static IntervalComparison compareIntervalToRecord(final QueryInterval interval, final SAMRecord record) { // interval.end <= 0 implies the end of the reference sequence. - final int intervalEnd = (interval.end <= 0? Integer.MAX_VALUE: interval.end); + final int intervalEnd = (interval.end <= 0 ? Integer.MAX_VALUE : interval.end); final int alignmentEnd; if (record.getReadUnmappedFlag() && record.getAlignmentStart() != SAMRecord.NO_ALIGNMENT_START) { // Unmapped read with coordinate of mate. diff --git a/src/main/java/htsjdk/samtools/BAMRecord.java b/src/main/java/htsjdk/samtools/BAMRecord.java index cd82fdb38c..e55080a1ee 100644 --- a/src/main/java/htsjdk/samtools/BAMRecord.java +++ b/src/main/java/htsjdk/samtools/BAMRecord.java @@ -23,13 +23,12 @@ */ package htsjdk.samtools; -import htsjdk.samtools.util.StringUtil; +import static htsjdk.samtools.SAMTag.CG; +import htsjdk.samtools.util.StringUtil; import java.nio.ByteBuffer; import java.nio.ByteOrder; -import static htsjdk.samtools.SAMTag.CG; - /** * Wrapper class for binary BAM records. * Delays unpacking all data binary until requested. @@ -44,7 +43,7 @@ public class BAMRecord extends SAMRecord { * Constant for converting between the number of operators in a Cigar and the length * of the int[] array needed to represent it in the BAM format */ - static public final short CIGAR_SIZE_MULTIPLIER = 4; + public static final short CIGAR_SIZE_MULTIPLIER = 4; /** * Maximal number of cigar operators that can be represented normally in the cigar part of the bam record. @@ -54,13 +53,13 @@ public class BAMRecord extends SAMRecord { * When a BAM record is decoded, the sentinel cigar informs of the existance of the CG tag, which is decoded and removed. * The sentinel value is then replaced with the actual cigar (in memory). */ - public final static int MAX_CIGAR_OPERATORS = 0xffff; + public static final int MAX_CIGAR_OPERATORS = 0xffff; - public final static int MAX_CIGAR_ELEMENT_LENGTH = (1 << 28) - 1; + public static final int MAX_CIGAR_ELEMENT_LENGTH = (1 << 28) - 1; /** * Number of operators in "Sentinel" cigar xSyN */ - private final static int LONG_CIGAR_SENTINEL_LENGTH = 2; + private static final int LONG_CIGAR_SENTINEL_LENGTH = 2; /** * Variable-length part of BAMRecord. Lazily decoded. @@ -93,19 +92,20 @@ public class BAMRecord extends SAMRecord { * than NO_ALIGNMENT_REFERENCE_INDEX (-1), then the specified index values must exist in the sequence dictionary * in the header argument. */ - protected BAMRecord(final SAMFileHeader header, - final int referenceID, - final int coordinate, - final short readNameLength, - final short mappingQuality, - final int indexingBin, - final int cigarLen, - final int flags, - final int readLen, - final int mateReferenceID, - final int mateCoordinate, - final int insertSize, - final byte[] restOfData) { + protected BAMRecord( + final SAMFileHeader header, + final int referenceID, + final int coordinate, + final short readNameLength, + final short mappingQuality, + final int indexingBin, + final int cigarLen, + final int flags, + final int readLen, + final int mateReferenceID, + final int mateCoordinate, + final int insertSize, + final byte[] restOfData) { super(header); // Set reference index and name directly, avoiding the round-trip through // setReferenceIndex -> resolveNameFromIndex -> setReferenceName -> resolveIndexFromName @@ -281,7 +281,9 @@ public Cigar getCigar() { extractCigarFromCGAttribute(super.getCigar()); } - if (null != getHeader() && getValidationStringency() != ValidationStringency.SILENT && !this.getReadUnmappedFlag()) { + if (null != getHeader() + && getValidationStringency() != ValidationStringency.SILENT + && !this.getReadUnmappedFlag()) { // Don't know line number, and don't want to force read name to be decoded. SAMUtils.processValidationErrors(validateCigar(-1L), -1, getValidationStringency()); } @@ -296,13 +298,12 @@ public Cigar getCigar() { */ static boolean isSentinelCigar(final Cigar cigar, final int readLength) { // There's an implicit assumption here there readLength == length of read in cigar, unless readLength==0 - return cigar.numCigarElements() == 2 && - cigar.getCigarElement(1).getOperator() == CigarOperator.N && - cigar.getCigarElement(0).getOperator() == CigarOperator.S && - (cigar.getCigarElement(0).getLength() == readLength || readLength == 0) ; + return cigar.numCigarElements() == 2 + && cigar.getCigarElement(1).getOperator() == CigarOperator.N + && cigar.getCigarElement(0).getOperator() == CigarOperator.S + && (cigar.getCigarElement(0).getLength() == readLength || readLength == 0); } - /** * Long cigars (with more than 64K operators) cannot be encoded into BAM. Instead a sentinel cigar is * placed as a placeholder, and the actual cigar is placed in the CG tag. This method @@ -314,8 +315,8 @@ private void extractCigarFromCGAttribute(final Cigar sentinelCigar) throws Illeg if (cigarFromCG == null) return; // place the integer array into a buffer so we can decode it - final ByteBuffer byteBuffer = ByteBuffer.allocate(cigarFromCG.length * CIGAR_SIZE_MULTIPLIER) - .order(ByteOrder.LITTLE_ENDIAN); + final ByteBuffer byteBuffer = + ByteBuffer.allocate(cigarFromCG.length * CIGAR_SIZE_MULTIPLIER).order(ByteOrder.LITTLE_ENDIAN); byteBuffer.asIntBuffer().put(cigarFromCG); // decode cigar @@ -325,9 +326,7 @@ private void extractCigarFromCGAttribute(final Cigar sentinelCigar) throws Illeg if (decodedCigar.numCigarElements() <= MAX_CIGAR_OPERATORS) { throw new IllegalStateException(String.format( "Only Cigar with > %d operators should be placed in CG tag. Found %d operators. \n Here's the Cigar:\n%s", - MAX_CIGAR_OPERATORS, - decodedCigar.getCigarElements().size(), - decodedCigar.toString())); + MAX_CIGAR_OPERATORS, decodedCigar.getCigarElements().size(), decodedCigar.toString())); } if (decodedCigar.getReferenceLength() != sentinelCigar.getReferenceLength()) { @@ -339,16 +338,13 @@ private void extractCigarFromCGAttribute(final Cigar sentinelCigar) throws Illeg decodedCigar.toString())); } - if (decodedCigar.getReadLength() != sentinelCigar.getReadLength() ) { + if (decodedCigar.getReadLength() != sentinelCigar.getReadLength()) { throw new IllegalStateException(String.format( "Sentinel cigar and %s cigar should have the same read length. Found %d and %d.\n Here's the Cigar:\n%s", - CG.name(), - sentinelCigar.getReadLength(), - decodedCigar.getReadLength(), - decodedCigar.toString())); + CG.name(), sentinelCigar.getReadLength(), decodedCigar.getReadLength(), decodedCigar.toString())); } - //used initializeCigar instead of setCigar so as to not clobber the indexingBin. + // used initializeCigar instead of setCigar so as to not clobber the indexingBin. initializeCigar(decodedCigar); // remove CG attribute. @@ -411,7 +407,8 @@ private void decodeAttributes() { mAttributesDecoded = true; final int tagsOffset = readNameSize() + cigarSize() + basesSize() + qualsSize(); final int tagsSize = mRestOfBinaryData.length - tagsOffset; - final SAMBinaryTagAndValue attributes = BinaryTagCodec.readTags(mRestOfBinaryData, tagsOffset, tagsSize, getValidationStringency()); + final SAMBinaryTagAndValue attributes = + BinaryTagCodec.readTags(mRestOfBinaryData, tagsOffset, tagsSize, getValidationStringency()); setAttributes(attributes); // if there's a CG tag, we should getCigar() so that the CG tag has a chance of turning into the CIGAR diff --git a/src/main/java/htsjdk/samtools/BAMRecordCodec.java b/src/main/java/htsjdk/samtools/BAMRecordCodec.java index 6717364499..31c62fbe34 100644 --- a/src/main/java/htsjdk/samtools/BAMRecordCodec.java +++ b/src/main/java/htsjdk/samtools/BAMRecordCodec.java @@ -23,22 +23,21 @@ */ package htsjdk.samtools; +import static htsjdk.samtools.SAMTag.CG; + import htsjdk.samtools.util.BinaryCodec; import htsjdk.samtools.util.Log; import htsjdk.samtools.util.RuntimeEOFException; import htsjdk.samtools.util.SortingCollection; - import java.io.InputStream; import java.io.OutputStream; import java.util.Arrays; -import static htsjdk.samtools.SAMTag.CG; - /** * Class for translating between in-memory and disk representation of BAMRecord. */ public class BAMRecordCodec implements SortingCollection.Codec { - private final static Log LOG = Log.getInstance(BAMRecordCodec.class); + private static final Log LOG = Log.getInstance(BAMRecordCodec.class); private final SAMFileHeader header; private final BinaryCodec binaryCodec = new BinaryCodec(); @@ -116,14 +115,17 @@ public void encode(final SAMRecord alignment) { final int[] cigarEncoding = BinaryCigarCodec.encode(alignment.getCigar()); alignment.setAttribute(CG.name(), cigarEncoding); cigarToWrite = makeSentinelCigar(alignment.getCigar()); - } - else { + } else { cigarToWrite = alignment.getCigar(); } - int blockSize = BAMFileConstants.FIXED_BLOCK_SIZE + alignment.getReadNameLength() + 1 + // null terminated - cigarToWrite.numCigarElements() * BAMRecord.CIGAR_SIZE_MULTIPLIER + - (readLength + 1) / 2 + // 2 bases per byte, round up + int blockSize = BAMFileConstants.FIXED_BLOCK_SIZE + + alignment.getReadNameLength() + + 1 + + // null terminated + cigarToWrite.numCigarElements() * BAMRecord.CIGAR_SIZE_MULTIPLIER + + (readLength + 1) / 2 + + // 2 bases per byte, round up readLength; final int attributesSize = alignment.getAttributesBinarySize(); @@ -167,11 +169,12 @@ public void encode(final SAMRecord alignment) { // when the record was read from a BAM file. this.binaryCodec.writeBytes(variableLengthBinaryBlock); } else { - if (alignment.getReadLength() != alignment.getBaseQualities().length && - alignment.getBaseQualities().length != 0) { - throw new RuntimeException("Mismatch between read length and quals length writing read " + - alignment.getReadName() + "; read length: " + alignment.getReadLength() + - "; quals length: " + alignment.getBaseQualities().length); + if (alignment.getReadLength() != alignment.getBaseQualities().length + && alignment.getBaseQualities().length != 0) { + throw new RuntimeException( + "Mismatch between read length and quals length writing read " + alignment.getReadName() + + "; read length: " + alignment.getReadLength() + "; quals length: " + + alignment.getBaseQualities().length); } this.binaryCodec.writeString(alignment.getReadName(), false, true); final int[] binaryCigar = BinaryCigarCodec.encode(cigarToWrite); @@ -213,17 +216,15 @@ public void encode(final SAMRecord alignment) { public static Cigar makeSentinelCigar(final Cigar cigar) { // in BAM there are only 28 bits for a cigar operator, so this a protection against overflow. if (cigar.getReadLength() > BAMRecord.MAX_CIGAR_ELEMENT_LENGTH) { - throw new IllegalArgumentException( - String.format( - "Cannot encode (to BAM) a record with more than %d cigar operations and a read-length greater than %d.", - BAMRecord.MAX_CIGAR_OPERATORS, BAMRecord.MAX_CIGAR_ELEMENT_LENGTH)); + throw new IllegalArgumentException(String.format( + "Cannot encode (to BAM) a record with more than %d cigar operations and a read-length greater than %d.", + BAMRecord.MAX_CIGAR_OPERATORS, BAMRecord.MAX_CIGAR_ELEMENT_LENGTH)); } if (cigar.getReferenceLength() > BAMRecord.MAX_CIGAR_ELEMENT_LENGTH) { - throw new IllegalArgumentException( - String.format( - "Cannot encode (to BAM) a record that has than %d cigar operations and spans more than %d bases on the reference.", - BAMRecord.MAX_CIGAR_OPERATORS, BAMRecord.MAX_CIGAR_ELEMENT_LENGTH)); + throw new IllegalArgumentException(String.format( + "Cannot encode (to BAM) a record that has than %d cigar operations and spans more than %d bases on the reference.", + BAMRecord.MAX_CIGAR_OPERATORS, BAMRecord.MAX_CIGAR_ELEMENT_LENGTH)); } return new Cigar(Arrays.asList( @@ -237,11 +238,13 @@ public static Cigar makeSentinelCigar(final Cigar cigar) { * @return true if the sequence is too large, false otherwise */ private boolean warnIfReferenceIsTooLargeForBinField(final SAMRecord rec) { - final SAMSequenceRecord sequence = rec.getHeader() != null ? rec.getHeader().getSequence(rec.getReferenceName()) : null; + final SAMSequenceRecord sequence = + rec.getHeader() != null ? rec.getHeader().getSequence(rec.getReferenceName()) : null; final boolean tooLarge = sequence != null && SAMUtils.isReferenceSequenceIncompatibleWithBAI(sequence); if (!isReferenceSizeWarningShowed && tooLarge && rec.getValidationStringency() != ValidationStringency.SILENT) { LOG.warn("Reference length is too large for BAM bin field."); - LOG.warn("Reads on references longer than " + GenomicIndexUtil.BIN_GENOMIC_SPAN + "bp will have bin set to 0."); + LOG.warn("Reads on references longer than " + GenomicIndexUtil.BIN_GENOMIC_SPAN + + "bp will have bin set to 0."); isReferenceSizeWarningShowed = true; } @@ -281,8 +284,19 @@ public SAMRecord decode() { final byte[] restOfRecord = new byte[recordLength - BAMFileConstants.FIXED_BLOCK_SIZE]; this.binaryCodec.readBytes(restOfRecord); final BAMRecord ret = this.samRecordFactory.createBAMRecord( - header, referenceID, coordinate, readNameLength, mappingQuality, - bin, cigarLen, flags, readLen, mateReferenceID, mateCoordinate, insertSize, restOfRecord); + header, + referenceID, + coordinate, + readNameLength, + mappingQuality, + bin, + cigarLen, + flags, + readLen, + mateReferenceID, + mateCoordinate, + insertSize, + restOfRecord); return ret; } diff --git a/src/main/java/htsjdk/samtools/BAMSBIIndexer.java b/src/main/java/htsjdk/samtools/BAMSBIIndexer.java index 6400f81ff7..ec0eb36813 100644 --- a/src/main/java/htsjdk/samtools/BAMSBIIndexer.java +++ b/src/main/java/htsjdk/samtools/BAMSBIIndexer.java @@ -30,7 +30,6 @@ import htsjdk.samtools.util.FileExtensions; import htsjdk.samtools.util.IOUtil; import htsjdk.samtools.util.RuntimeEOFException; - import java.io.IOException; import java.io.OutputStream; import java.nio.ByteBuffer; @@ -52,7 +51,8 @@ public final class BAMSBIIndexer { */ public static void createIndex(final Path bamFile, final long granularity) throws IOException { final Path splittingBaiFile = IOUtil.addExtension(bamFile, FileExtensions.SBI); - try (SeekableStream in = new SeekablePathStream(bamFile); OutputStream out = Files.newOutputStream(splittingBaiFile)) { + try (SeekableStream in = new SeekablePathStream(bamFile); + OutputStream out = Files.newOutputStream(splittingBaiFile)) { createIndex(in, out, granularity); } } @@ -65,7 +65,8 @@ public static void createIndex(final Path bamFile, final long granularity) throw * @param granularity write the offset of every n-th alignment to the index * @throws IOException as per java IO contract */ - public static void createIndex(final SeekableStream in, final OutputStream out, final long granularity) throws IOException { + public static void createIndex(final SeekableStream in, final OutputStream out, final long granularity) + throws IOException { long recordStart = SAMUtils.findVirtualOffsetOfFirstRecordInBam(in); try (BlockCompressedInputStream blockIn = new BlockCompressedInputStream(in)) { blockIn.seek(recordStart); diff --git a/src/main/java/htsjdk/samtools/BAMStartingAtIteratorFilter.java b/src/main/java/htsjdk/samtools/BAMStartingAtIteratorFilter.java index 8bd8eb51c8..533dabd447 100644 --- a/src/main/java/htsjdk/samtools/BAMStartingAtIteratorFilter.java +++ b/src/main/java/htsjdk/samtools/BAMStartingAtIteratorFilter.java @@ -57,7 +57,7 @@ public FilteringIteratorState compareToFilter(final SAMRecord record) { if (alignmentStart > mRegionStart) { // If scanned beyond target region, end iteration return FilteringIteratorState.STOP_ITERATION; - } else if (alignmentStart == mRegionStart) { + } else if (alignmentStart == mRegionStart) { return FilteringIteratorState.MATCHES_FILTER; } else { return FilteringIteratorState.CONTINUE_ITERATION; diff --git a/src/main/java/htsjdk/samtools/BAMStreamWriter.java b/src/main/java/htsjdk/samtools/BAMStreamWriter.java index c720655fb0..968c91a081 100644 --- a/src/main/java/htsjdk/samtools/BAMStreamWriter.java +++ b/src/main/java/htsjdk/samtools/BAMStreamWriter.java @@ -26,11 +26,10 @@ import htsjdk.samtools.util.BinaryCodec; import htsjdk.samtools.util.BlockCompressedOutputStream; import htsjdk.samtools.util.RuntimeIOException; -import org.apache.commons.compress.utils.CountingOutputStream; - import java.io.IOException; import java.io.OutputStream; import java.nio.file.Path; +import org.apache.commons.compress.utils.CountingOutputStream; /** * Class for writing SAMRecords in BAM format to an output stream. @@ -53,7 +52,12 @@ public class BAMStreamWriter { * @param sbiGranularity the granularity of the SBI index (reads per entry) * @param header the SAM header */ - public BAMStreamWriter(OutputStream outputStream, OutputStream indexStream, OutputStream sbiStream, long sbiGranularity, SAMFileHeader header) { + public BAMStreamWriter( + OutputStream outputStream, + OutputStream indexStream, + OutputStream sbiStream, + long sbiGranularity, + SAMFileHeader header) { countingOut = new CountingOutputStream(outputStream); compressedOut = new BlockCompressedOutputStream(countingOut, (Path) null); bamRecordCodec = new BAMRecordCodec(header); @@ -123,8 +127,7 @@ public void finish(final boolean writeTerminatorBlock) { // If we didn't do this then we would have an invalid virtual file pointer if a BGZF file // were concatenated following this one. if (bamIndexer != null && previousSamRecord != null) { - previousSamRecordChunk = - new Chunk(previousSamRecordChunk.getChunkStart(), finalVirtualOffset); + previousSamRecordChunk = new Chunk(previousSamRecordChunk.getChunkStart(), finalVirtualOffset); previousSamRecord.setFileSource(new SAMFileSource(null, new BAMFileSpan(previousSamRecordChunk))); bamIndexer.processAlignment(previousSamRecord); } diff --git a/src/main/java/htsjdk/samtools/BamConverter.java b/src/main/java/htsjdk/samtools/BamConverter.java index 13d2500565..f5b14d4cac 100644 --- a/src/main/java/htsjdk/samtools/BamConverter.java +++ b/src/main/java/htsjdk/samtools/BamConverter.java @@ -15,15 +15,15 @@ */ public class BamConverter { - private static final String USAGE = String.join("\n", + private static final String USAGE = String.join( + "\n", "Usage: BamConverter [output]", "", "Read and optionally convert a BAM file.", "", "Arguments:", " input Input BAM file", - " output Optional output BAM file (omit to read-only)" - ); + " output Optional output BAM file (omit to read-only)"); /** * Entry point. Parses command-line arguments and performs the read/conversion. @@ -42,9 +42,8 @@ public static void main(final String[] args) { final boolean eager = hasFlag(args, "--eager"); // Collect positional args (non-flag arguments) - final String[] positional = java.util.Arrays.stream(args) - .filter(a -> !a.startsWith("--")) - .toArray(String[]::new); + final String[] positional = + java.util.Arrays.stream(args).filter(a -> !a.startsWith("--")).toArray(String[]::new); if (positional.length < 1) { System.err.println(USAGE); System.exit(1); @@ -58,8 +57,8 @@ public static void main(final String[] args) { System.err.printf("Reading %s (no output%s)%n", inputPath, eager ? ", eager decode" : ""); } - final SamReaderFactory readerFactory = SamReaderFactory.makeDefault() - .validationStringency(ValidationStringency.SILENT); + final SamReaderFactory readerFactory = + SamReaderFactory.makeDefault().validationStringency(ValidationStringency.SILENT); long count = 0; final long startTime = System.currentTimeMillis(); @@ -69,7 +68,8 @@ public static void main(final String[] args) { if (outputPath != null) { final SAMFileWriterFactory writerFactory = new SAMFileWriterFactory(); - try (final SAMFileWriter writer = writerFactory.makeBAMWriter(header, true, new File(outputPath).toPath())) { + try (final SAMFileWriter writer = + writerFactory.makeBAMWriter(header, true, new File(outputPath).toPath())) { for (final SAMRecord record : reader) { if (eager) record.eagerDecode(); writer.addAlignment(record); @@ -97,12 +97,15 @@ public static void main(final String[] args) { if (outputPath != null) { final long outputSize = new File(outputPath).length(); - System.err.printf("Done. %,d records in %.1fs. Input: %,d bytes, Output: %,d bytes (%.1f%%)%n", - count, elapsed / 1000.0, inputSize, outputSize, + System.err.printf( + "Done. %,d records in %.1fs. Input: %,d bytes, Output: %,d bytes (%.1f%%)%n", + count, + elapsed / 1000.0, + inputSize, + outputSize, inputSize > 0 ? (100.0 * outputSize / inputSize) : 0); } else { - System.err.printf("Done. %,d records in %.1fs. Input: %,d bytes%n", - count, elapsed / 1000.0, inputSize); + System.err.printf("Done. %,d records in %.1fs. Input: %,d bytes%n", count, elapsed / 1000.0, inputSize); } } diff --git a/src/main/java/htsjdk/samtools/BamFileIoUtils.java b/src/main/java/htsjdk/samtools/BamFileIoUtils.java index 709c8ed76d..761a22a8f7 100644 --- a/src/main/java/htsjdk/samtools/BamFileIoUtils.java +++ b/src/main/java/htsjdk/samtools/BamFileIoUtils.java @@ -13,14 +13,12 @@ import htsjdk.samtools.util.Md5CalculatingOutputStream; import htsjdk.samtools.util.RuntimeIOException; import htsjdk.utils.ValidationUtils; - import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.List; public class BamFileIoUtils { @@ -40,11 +38,15 @@ public static void reheaderBamFile(final SAMFileHeader samFileHeader, final Path reheaderBamFile(samFileHeader, inputFile, outputFile, true, true); } - /** * Support File input types for backward compatibility. Use the same method with Path inputs below. */ - public static void reheaderBamFile(final SAMFileHeader samFileHeader, final File inputFile, final File outputFile, final boolean createMd5, final boolean createIndex) { + public static void reheaderBamFile( + final SAMFileHeader samFileHeader, + final File inputFile, + final File outputFile, + final boolean createMd5, + final boolean createIndex) { reheaderBamFile(samFileHeader, IOUtil.toPath(inputFile), IOUtil.toPath(outputFile), createMd5, createIndex); } @@ -57,7 +59,12 @@ public static void reheaderBamFile(final SAMFileHeader samFileHeader, final File * @param createMd5 Whether or not to create an MD5 file for the new BAM * @param createIndex Whether or not to create an index file for the new BAM */ - public static void reheaderBamFile(final SAMFileHeader samFileHeader, final Path inputFile, final Path outputFile, final boolean createMd5, final boolean createIndex) { + public static void reheaderBamFile( + final SAMFileHeader samFileHeader, + final Path inputFile, + final Path outputFile, + final boolean createMd5, + final boolean createIndex) { ValidationUtils.nonNull(inputFile); ValidationUtils.nonNull(outputFile); IOUtil.assertFileIsReadable(inputFile); @@ -79,7 +86,11 @@ public static void reheaderBamFile(final SAMFileHeader samFileHeader, final Path } } - public static void blockCopyBamFile(final File inputFile, final OutputStream outputStream, final boolean skipHeader, final boolean skipTerminator) { + public static void blockCopyBamFile( + final File inputFile, + final OutputStream outputStream, + final boolean skipHeader, + final boolean skipTerminator) { blockCopyBamFile(IOUtil.toPath(inputFile), outputStream, skipHeader, skipTerminator); } @@ -91,10 +102,16 @@ public static void blockCopyBamFile(final File inputFile, final OutputStream out * @param skipHeader If true, the header of the input file will not be copied to the output stream * @param skipTerminator If true, the terminator block of the input file will not be written to the output stream */ - public static void blockCopyBamFile(final Path inputFile, final OutputStream outputStream, final boolean skipHeader, final boolean skipTerminator) { - try (final SeekablePathStream in = new SeekablePathStream(inputFile)){ - // a) It's good to check that the end of the file is valid and b) we need to know if there's a terminator block and not copy it if skipTerminator is true - final BlockCompressedInputStream.FileTermination term = BlockCompressedInputStream.checkTermination(inputFile); + public static void blockCopyBamFile( + final Path inputFile, + final OutputStream outputStream, + final boolean skipHeader, + final boolean skipTerminator) { + try (final SeekablePathStream in = new SeekablePathStream(inputFile)) { + // a) It's good to check that the end of the file is valid and b) we need to know if there's a terminator + // block and not copy it if skipTerminator is true + final BlockCompressedInputStream.FileTermination term = + BlockCompressedInputStream.checkTermination(inputFile); if (term == BlockCompressedInputStream.FileTermination.DEFECTIVE) throw new SAMException(inputFile.toUri() + " does not have a valid GZIP block at the end of the file."); @@ -109,7 +126,8 @@ public static void blockCopyBamFile(final Path inputFile, final OutputStream out // If we found the end of the header then write the remainder of this block out as a // new gzip block and then break out of the while loop (tsato: update this comment) if (remainingInBlock >= 0) { - final BlockCompressedOutputStream blockOut = new BlockCompressedOutputStream(outputStream, (Path) null); + final BlockCompressedOutputStream blockOut = + new BlockCompressedOutputStream(outputStream, (Path) null); IOUtil.transferByStream(blockIn, blockOut, remainingInBlock); blockOut.flush(); // Don't close blockOut because closing underlying stream would break everything @@ -119,7 +137,7 @@ public static void blockCopyBamFile(final Path inputFile, final OutputStream out blockIn.close(); // tsato: why doesn't IntelliJ say this is unnecessary? in.seek(pos); - } catch (IOException e){ + } catch (IOException e) { throw new HtsjdkException("Encountered an error.", e); } } @@ -127,8 +145,10 @@ public static void blockCopyBamFile(final Path inputFile, final OutputStream out // Copy remainder of input stream into output stream final long currentPos = in.position(); final long length = Files.size(inputFile); - final long skipLast = ((term == BlockCompressedInputStream.FileTermination.HAS_TERMINATOR_BLOCK) && skipTerminator) ? - BlockCompressedStreamConstants.EMPTY_GZIP_BLOCK.length : 0; + final long skipLast = + ((term == BlockCompressedInputStream.FileTermination.HAS_TERMINATOR_BLOCK) && skipTerminator) + ? BlockCompressedStreamConstants.EMPTY_GZIP_BLOCK.length + : 0; final long bytesToWrite = length - skipLast - currentPos; IOUtil.transferByStream(in, outputStream, bytesToWrite); @@ -143,7 +163,8 @@ public static void blockCopyBamFile(final Path inputFile, final OutputStream out * (often the first block) and re-compress any data remaining in that block into a new block in the output file. Subsequent * blocks (excluding a terminator block if present) are copied directly from input to output. */ - public static void gatherWithBlockCopying(final List bams, final File output, final boolean createIndex, final boolean createMd5) { + public static void gatherWithBlockCopying( + final List bams, final File output, final boolean createIndex, final boolean createMd5) { try { OutputStream out = new FileOutputStream(output); if (createMd5) out = new Md5CalculatingOutputStream(out, new File(output.getAbsolutePath() + ".md5")); @@ -165,12 +186,15 @@ public static void gatherWithBlockCopying(final List bams, final File outp out.write(BlockCompressedStreamConstants.EMPTY_GZIP_BLOCK); out.close(); - // It is possible that the modified time on the index file is ever so slightly older than the original BAM file + // It is possible that the modified time on the index file is ever so slightly older than the original BAM + // file // and this makes ValidateSamFile unhappy. if (createIndex && (output.lastModified() > indexFile.lastModified())) { final boolean success = indexFile.setLastModified(System.currentTimeMillis()); if (!success) { - System.err.print(String.format("Index file is older than BAM file for %s and unable to resolve this", output.getAbsolutePath())); + System.err.print(String.format( + "Index file is older than BAM file for %s and unable to resolve this", + output.getAbsolutePath())); } } } catch (final IOException ioe) { @@ -178,33 +202,39 @@ public static void gatherWithBlockCopying(final List bams, final File outp } } - private static OutputStream buildOutputStream(final File outputFile, final boolean createMd5, final boolean createIndex) throws IOException { + private static OutputStream buildOutputStream( + final File outputFile, final boolean createMd5, final boolean createIndex) throws IOException { return buildOutputStream(IOUtil.toPath(outputFile), createMd5, createIndex); } - private static OutputStream buildOutputStream(final Path outputFile, final boolean createMd5, final boolean createIndex) throws IOException { + private static OutputStream buildOutputStream( + final Path outputFile, final boolean createMd5, final boolean createIndex) throws IOException { OutputStream outputStream = Files.newOutputStream(outputFile); if (createMd5) { - outputStream = new Md5CalculatingOutputStream(outputStream, IOUtil.addExtension(outputFile, FileExtensions.MD5)); + outputStream = + new Md5CalculatingOutputStream(outputStream, IOUtil.addExtension(outputFile, FileExtensions.MD5)); } if (createIndex) { - outputStream = new StreamInflatingIndexingOutputStream(outputStream, outputFile.resolveSibling(outputFile.getFileName() + FileExtensions.BAI_INDEX)); + outputStream = new StreamInflatingIndexingOutputStream( + outputStream, outputFile.resolveSibling(outputFile.getFileName() + FileExtensions.BAI_INDEX)); } return outputStream; } - @Deprecated - private static void assertSortOrdersAreEqual(final SAMFileHeader newHeader, final File inputFile) throws IOException { + private static void assertSortOrdersAreEqual(final SAMFileHeader newHeader, final File inputFile) + throws IOException { assertSortOrdersAreEqual(newHeader, IOUtil.toPath(inputFile)); } - private static void assertSortOrdersAreEqual(final SAMFileHeader newHeader, final Path inputFile) throws IOException { + private static void assertSortOrdersAreEqual(final SAMFileHeader newHeader, final Path inputFile) + throws IOException { final SamReader reader = SamReaderFactory.makeDefault().open(inputFile); final SAMFileHeader origHeader = reader.getFileHeader(); final SAMFileHeader.SortOrder newSortOrder = newHeader.getSortOrder(); if (newSortOrder != SAMFileHeader.SortOrder.unsorted && newSortOrder != origHeader.getSortOrder()) { - throw new SAMException("Sort order of new header does not match the original file, needs to be " + origHeader.getSortOrder()); + throw new SAMException("Sort order of new header does not match the original file, needs to be " + + origHeader.getSortOrder()); } reader.close(); } diff --git a/src/main/java/htsjdk/samtools/BamIndexValidator.java b/src/main/java/htsjdk/samtools/BamIndexValidator.java index f3b5cbe5ae..0295b8c3a2 100644 --- a/src/main/java/htsjdk/samtools/BamIndexValidator.java +++ b/src/main/java/htsjdk/samtools/BamIndexValidator.java @@ -1,204 +1,232 @@ -/* - * The MIT License - * - * Copyright (c) 2010 The Broad Institute - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package htsjdk.samtools; - -import htsjdk.samtools.util.CloseableIterator; - -import java.util.Arrays; -import java.util.List; - -/** - * Class to validate (at two different levels of thoroughness) the index for a BAM file. - * - * This class is [not] thread safe [because it is immutable]. - */ -public class BamIndexValidator { - - public enum IndexValidationStringency { - EXHAUSTIVE, LESS_EXHAUSTIVE, NONE - } - - public static int exhaustivelyTestIndex(final SamReader reader) { // throws Exception { - // look at all chunk offsets in a linear index to make sure they are valid - - if (reader.indexing().hasBrowseableIndex()) { - if (SamIndexes.BAI.fileNameSuffix.endsWith(reader.type().indexExtension())) { - - // content is from an existing bai file - final CachingBAMFileIndex existingIndex = (CachingBAMFileIndex) reader.indexing().getBrowseableIndex(); // new CachingBAMFileIndex(inputBai, null); - final int numRefs = existingIndex.getNumberOfReferences(); - - int chunkCount = 0; - int indexCount = 0; - for (int i = 0; i < numRefs; i++) { - final BAMIndexContent content = existingIndex.getQueryResults(i); - for (final Chunk c : content.getAllChunks()) { - final CloseableIterator iter = ((SamReader.PrimitiveSamReaderToSamReaderAdapter) reader).iterator(new BAMFileSpan(c)); - chunkCount++; - SAMRecord sam = null; - try { - sam = iter.next(); - iter.close(); - } catch (final Exception e) { - throw new SAMException("Exception in BamIndexValidator. Last good record " + sam + " in chunk " + c + " chunkCount=" + chunkCount, e); - } - } - // also seek to every position in the linear index - // final BAMRecordCodec bamRecordCodec = new BAMRecordCodec(reader.getFileHeader()); - // bamRecordCodec.setInputStream(reader.getInputStream()); - - final LinearIndex linearIndex = content.getLinearIndex(); - for (final long l : linearIndex.getIndexEntries()) { - try { - if (l != 0) { - final CloseableIterator iter = ((SamReader.PrimitiveSamReaderToSamReaderAdapter) reader).iterator(new BAMFileSpan(new Chunk(l, l + 1))); - final SAMRecord sam = iter.next(); // read the first record identified by the linear index - indexCount++; - iter.close(); - } - } catch (final Exception e) { - throw new SAMException("Exception in BamIndexValidator. Linear index access failure " + l + " indexCount=" + indexCount, e); - } - - } - } - return chunkCount; - // System.out.println("Found " chunkCount + " chunks in test " + inputBai + - // " linearIndex positions = " + indexCount); - } else if (SamIndexes.CSI.fileNameSuffix.endsWith(reader.type().indexExtension())) { - - final CSIIndex existingIndex = (CSIIndex) reader.indexing().getBrowseableIndex(); // new CachingBAMFileIndex(inputBai, null); - final int numRefs = existingIndex.getNumberOfReferences(); - - int chunkCount = 0; - for (int i = 0; i < numRefs; i++) { - final BAMIndexContent content = existingIndex.getQueryResults(i); - for (final Chunk c : content.getAllChunks()) { - final CloseableIterator iter = ((SamReader.PrimitiveSamReaderToSamReaderAdapter) reader).iterator(new BAMFileSpan(c)); - chunkCount++; - SAMRecord sam = null; - try { - sam = iter.next(); - iter.close(); - } catch (final Exception e) { - throw new SAMException("Exception in BamIndexValidator. Last good record " + sam + " in chunk " + c + " chunkCount=" + chunkCount, e); - } - } - } - return chunkCount; - } - } - // else not a bam file with a browseable index - // System.err.println("No browseableIndex for reader"); - return 0; - } - - /** - * A less time-consuming index validation that only looks at the first and last references in the index - * and the first and last chunks in each of those - * - * @param reader - * @return # of chunks examined, or 0 if there is no browseable index for the reader - */ - public static int lessExhaustivelyTestIndex(final SamReader reader) { - // look at all chunk offsets in a linear index to make sure they are valid - if (reader.indexing().hasBrowseableIndex()) { - if (SamIndexes.BAI.fileNameSuffix.endsWith(reader.type().indexExtension())) { - - // content is from an existing bai file - final CachingBAMFileIndex existingIndex = (CachingBAMFileIndex) reader.indexing().getBrowseableIndex(); - final int numRefs = existingIndex.getNumberOfReferences(); - - int chunkCount = 0; - int indexCount = 0; - for (int i = 0; i < numRefs; i++) { - - final BAMIndexContent content = existingIndex.getQueryResults(i); - - final List chunks = content.getAllChunks(); - final int numChunks = chunks.size(); - // We are looking only at the first and last chunks - for (final int chunkNo : Arrays.asList(0, numChunks - 1)) { - chunkCount++; - - final Chunk c = chunks.get(chunkNo); - final CloseableIterator iter = ((SamReader.PrimitiveSamReaderToSamReaderAdapter) reader).iterator(new BAMFileSpan(c)); - try { - final SAMRecord sam = iter.next(); - iter.close(); - } catch (final Exception e) { - throw new SAMException("Exception querying chunk " + chunkNo + " from reference index " + i, e); - } - } - - // also seek to first and last position in the linear index - final long linearIndexEntries[] = content.getLinearIndex().getIndexEntries(); - for (final int binNo : Arrays.asList(0, linearIndexEntries.length - 1)) { - indexCount++; - final long l = linearIndexEntries[binNo]; - try { - if (l != 0) { - final CloseableIterator iter = ((SamReader.PrimitiveSamReaderToSamReaderAdapter) reader).iterator(new BAMFileSpan(new Chunk(l, l + 1))); - final SAMRecord sam = iter.next(); // read the first record identified by the linear index - iter.close(); - } - } catch (final Exception e) { - throw new SAMException("Exception in BamIndexValidator. Linear index access failure " + l + " indexCount=" + indexCount, e); - } - } - } - return chunkCount; - } else if (SamIndexes.CSI.fileNameSuffix.endsWith(reader.type().indexExtension())) { - - final CSIIndex existingIndex = (CSIIndex) reader.indexing().getBrowseableIndex(); // new CachingBAMFileIndex(inputBai, null); - final int numRefs = existingIndex.getNumberOfReferences(); - - int chunkCount = 0; - for (int i = 0; i < numRefs; i++) { - - final BAMIndexContent content = existingIndex.getQueryResults(i); - - final List chunks = content.getAllChunks(); - final int numChunks = chunks.size(); - // We are looking only at the first and last chunks - for (final int chunkNo : Arrays.asList(0, numChunks - 1)) { - chunkCount++; - - final Chunk c = chunks.get(chunkNo); - final CloseableIterator iter = ((SamReader.PrimitiveSamReaderToSamReaderAdapter) reader).iterator(new BAMFileSpan(c)); - try { - final SAMRecord sam = iter.next(); - iter.close(); - } catch (final Exception e) { - throw new SAMException("Exception querying chunk " + chunkNo + " from reference index " + i, e); - } - } - } - return chunkCount; - } - } - // else it's not a bam file with a browseable index - return 0; - } -} +/* + * The MIT License + * + * Copyright (c) 2010 The Broad Institute + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package htsjdk.samtools; + +import htsjdk.samtools.util.CloseableIterator; +import java.util.Arrays; +import java.util.List; + +/** + * Class to validate (at two different levels of thoroughness) the index for a BAM file. + * + * This class is [not] thread safe [because it is immutable]. + */ +public class BamIndexValidator { + + public enum IndexValidationStringency { + EXHAUSTIVE, + LESS_EXHAUSTIVE, + NONE + } + + public static int exhaustivelyTestIndex(final SamReader reader) { // throws Exception { + // look at all chunk offsets in a linear index to make sure they are valid + + if (reader.indexing().hasBrowseableIndex()) { + if (SamIndexes.BAI.fileNameSuffix.endsWith(reader.type().indexExtension())) { + + // content is from an existing bai file + final CachingBAMFileIndex existingIndex = (CachingBAMFileIndex) + reader.indexing().getBrowseableIndex(); // new CachingBAMFileIndex(inputBai, null); + final int numRefs = existingIndex.getNumberOfReferences(); + + int chunkCount = 0; + int indexCount = 0; + for (int i = 0; i < numRefs; i++) { + final BAMIndexContent content = existingIndex.getQueryResults(i); + for (final Chunk c : content.getAllChunks()) { + final CloseableIterator iter = + ((SamReader.PrimitiveSamReaderToSamReaderAdapter) reader).iterator(new BAMFileSpan(c)); + chunkCount++; + SAMRecord sam = null; + try { + sam = iter.next(); + iter.close(); + } catch (final Exception e) { + throw new SAMException( + "Exception in BamIndexValidator. Last good record " + sam + " in chunk " + c + + " chunkCount=" + chunkCount, + e); + } + } + // also seek to every position in the linear index + // final BAMRecordCodec bamRecordCodec = new BAMRecordCodec(reader.getFileHeader()); + // bamRecordCodec.setInputStream(reader.getInputStream()); + + final LinearIndex linearIndex = content.getLinearIndex(); + for (final long l : linearIndex.getIndexEntries()) { + try { + if (l != 0) { + final CloseableIterator iter = + ((SamReader.PrimitiveSamReaderToSamReaderAdapter) reader) + .iterator(new BAMFileSpan(new Chunk(l, l + 1))); + final SAMRecord sam = + iter.next(); // read the first record identified by the linear index + indexCount++; + iter.close(); + } + } catch (final Exception e) { + throw new SAMException( + "Exception in BamIndexValidator. Linear index access failure " + l + " indexCount=" + + indexCount, + e); + } + } + } + return chunkCount; + // System.out.println("Found " chunkCount + " chunks in test " + inputBai + + // " linearIndex positions = " + indexCount); + } else if (SamIndexes.CSI.fileNameSuffix.endsWith(reader.type().indexExtension())) { + + final CSIIndex existingIndex = + (CSIIndex) reader.indexing().getBrowseableIndex(); // new CachingBAMFileIndex(inputBai, null); + final int numRefs = existingIndex.getNumberOfReferences(); + + int chunkCount = 0; + for (int i = 0; i < numRefs; i++) { + final BAMIndexContent content = existingIndex.getQueryResults(i); + for (final Chunk c : content.getAllChunks()) { + final CloseableIterator iter = + ((SamReader.PrimitiveSamReaderToSamReaderAdapter) reader).iterator(new BAMFileSpan(c)); + chunkCount++; + SAMRecord sam = null; + try { + sam = iter.next(); + iter.close(); + } catch (final Exception e) { + throw new SAMException( + "Exception in BamIndexValidator. Last good record " + sam + " in chunk " + c + + " chunkCount=" + chunkCount, + e); + } + } + } + return chunkCount; + } + } + // else not a bam file with a browseable index + // System.err.println("No browseableIndex for reader"); + return 0; + } + + /** + * A less time-consuming index validation that only looks at the first and last references in the index + * and the first and last chunks in each of those + * + * @param reader + * @return # of chunks examined, or 0 if there is no browseable index for the reader + */ + public static int lessExhaustivelyTestIndex(final SamReader reader) { + // look at all chunk offsets in a linear index to make sure they are valid + if (reader.indexing().hasBrowseableIndex()) { + if (SamIndexes.BAI.fileNameSuffix.endsWith(reader.type().indexExtension())) { + + // content is from an existing bai file + final CachingBAMFileIndex existingIndex = + (CachingBAMFileIndex) reader.indexing().getBrowseableIndex(); + final int numRefs = existingIndex.getNumberOfReferences(); + + int chunkCount = 0; + int indexCount = 0; + for (int i = 0; i < numRefs; i++) { + + final BAMIndexContent content = existingIndex.getQueryResults(i); + + final List chunks = content.getAllChunks(); + final int numChunks = chunks.size(); + // We are looking only at the first and last chunks + for (final int chunkNo : Arrays.asList(0, numChunks - 1)) { + chunkCount++; + + final Chunk c = chunks.get(chunkNo); + final CloseableIterator iter = + ((SamReader.PrimitiveSamReaderToSamReaderAdapter) reader).iterator(new BAMFileSpan(c)); + try { + final SAMRecord sam = iter.next(); + iter.close(); + } catch (final Exception e) { + throw new SAMException( + "Exception querying chunk " + chunkNo + " from reference index " + i, e); + } + } + + // also seek to first and last position in the linear index + final long linearIndexEntries[] = content.getLinearIndex().getIndexEntries(); + for (final int binNo : Arrays.asList(0, linearIndexEntries.length - 1)) { + indexCount++; + final long l = linearIndexEntries[binNo]; + try { + if (l != 0) { + final CloseableIterator iter = + ((SamReader.PrimitiveSamReaderToSamReaderAdapter) reader) + .iterator(new BAMFileSpan(new Chunk(l, l + 1))); + final SAMRecord sam = + iter.next(); // read the first record identified by the linear index + iter.close(); + } + } catch (final Exception e) { + throw new SAMException( + "Exception in BamIndexValidator. Linear index access failure " + l + " indexCount=" + + indexCount, + e); + } + } + } + return chunkCount; + } else if (SamIndexes.CSI.fileNameSuffix.endsWith(reader.type().indexExtension())) { + + final CSIIndex existingIndex = + (CSIIndex) reader.indexing().getBrowseableIndex(); // new CachingBAMFileIndex(inputBai, null); + final int numRefs = existingIndex.getNumberOfReferences(); + + int chunkCount = 0; + for (int i = 0; i < numRefs; i++) { + + final BAMIndexContent content = existingIndex.getQueryResults(i); + + final List chunks = content.getAllChunks(); + final int numChunks = chunks.size(); + // We are looking only at the first and last chunks + for (final int chunkNo : Arrays.asList(0, numChunks - 1)) { + chunkCount++; + + final Chunk c = chunks.get(chunkNo); + final CloseableIterator iter = + ((SamReader.PrimitiveSamReaderToSamReaderAdapter) reader).iterator(new BAMFileSpan(c)); + try { + final SAMRecord sam = iter.next(); + iter.close(); + } catch (final Exception e) { + throw new SAMException( + "Exception querying chunk " + chunkNo + " from reference index " + i, e); + } + } + } + return chunkCount; + } + } + // else it's not a bam file with a browseable index + return 0; + } +} diff --git a/src/main/java/htsjdk/samtools/Bin.java b/src/main/java/htsjdk/samtools/Bin.java index 68d83d6a51..e610b07164 100644 --- a/src/main/java/htsjdk/samtools/Bin.java +++ b/src/main/java/htsjdk/samtools/Bin.java @@ -24,7 +24,6 @@ package htsjdk.samtools; import htsjdk.samtools.util.BlockCompressedFilePointerUtil; - import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -78,10 +77,10 @@ public int getBinNumber() { */ @Override public boolean equals(final Object other) { - if(other == null) return false; - if(!(other instanceof Bin)) return false; + if (other == null) return false; + if (!(other instanceof Bin)) return false; - final Bin otherBin = (Bin)other; + final Bin otherBin = (Bin) other; return this.referenceSequence == otherBin.referenceSequence && this.binNumber == otherBin.binNumber; } @@ -91,7 +90,7 @@ public boolean equals(final Object other) { */ @Override public int hashCode() { - return ((Integer)referenceSequence).hashCode() ^ ((Integer)binNumber).hashCode(); + return ((Integer) referenceSequence).hashCode() ^ ((Integer) binNumber).hashCode(); } /** @@ -109,12 +108,10 @@ public boolean containsChunks() { */ @Override public int compareTo(final Bin other) { - if(other == null) - throw new ClassCastException("Cannot compare to a null object"); + if (other == null) throw new ClassCastException("Cannot compare to a null object"); // Check the reference sequences first. - if(this.referenceSequence != other.referenceSequence) - return referenceSequence - other.referenceSequence; + if (this.referenceSequence != other.referenceSequence) return referenceSequence - other.referenceSequence; // Then check the bin ordering. return binNumber - other.binNumber; @@ -123,7 +120,7 @@ public int compareTo(final Bin other) { /** * Adds the first chunk to the bin */ - public void addInitialChunk(final Chunk newChunk){ + public void addInitialChunk(final Chunk newChunk) { final List oldChunks = new ArrayList(); setChunkList(oldChunks); setLastChunk(newChunk); @@ -146,8 +143,7 @@ public void addChunk(final Chunk newChunk) { // Coalesce chunks that are in the same or adjacent file blocks. // Similar to AbstractBAMFileIndex.optimizeChunkList, // but no need to copy the list, no minimumOffset, and maintain bin.lastChunk - if (BlockCompressedFilePointerUtil.areInSameOrAdjacentBlocks( - lastChunk.getChunkEnd(), chunkStart)) { + if (BlockCompressedFilePointerUtil.areInSameOrAdjacentBlocks(lastChunk.getChunkEnd(), chunkStart)) { lastChunk.setChunkEnd(chunkEnd); // coalesced } else { chunkList.add(newChunk); @@ -159,7 +155,7 @@ public void addChunk(final Chunk newChunk) { /** * Sets the chunks associated with this bin */ - public void setChunkList(final List list){ + public void setChunkList(final List list) { chunkList = list; } @@ -167,16 +163,15 @@ public void setChunkList(final List list){ * Gets the list of chunks associated with this bin. * @return the chunks in this bin. If no chunks are associated, an empty list will be returned. */ - public List getChunkList(){ - if(chunkList == null) - return Collections.emptyList(); + public List getChunkList() { + if (chunkList == null) return Collections.emptyList(); return chunkList; } /** * Optimization to keep lastChunk instead of iterating over all chunks repeatedly */ - public void setLastChunk(final Chunk c){ + public void setLastChunk(final Chunk c) { lastChunk = c; } @@ -185,7 +180,7 @@ public void setLastChunk(final Chunk c){ * (AbstractBAMFileIndex.optimizeChunkList doesn't maintain this) * @return the last Chunk of the chunkList */ - public Chunk getLastChunk(){ + public Chunk getLastChunk() { return lastChunk; } diff --git a/src/main/java/htsjdk/samtools/BinList.java b/src/main/java/htsjdk/samtools/BinList.java index 2111ba403f..8c1b9f7f6c 100644 --- a/src/main/java/htsjdk/samtools/BinList.java +++ b/src/main/java/htsjdk/samtools/BinList.java @@ -107,11 +107,10 @@ public boolean hasNext() { */ @Override public Bin next() { - if(!hasNext()) - throw new NoSuchElementException("This BinIterator is currently empty"); + if (!hasNext()) throw new NoSuchElementException("This BinIterator is currently empty"); int currentBin = nextBin; - nextBin = bins.nextSetBit(nextBin+1); - return new Bin(referenceSequence,currentBin); + nextBin = bins.nextSetBit(nextBin + 1); + return new Bin(referenceSequence, currentBin); } @Override @@ -120,4 +119,3 @@ public void remove() { } } } - diff --git a/src/main/java/htsjdk/samtools/BinaryBAMIndexWriter.java b/src/main/java/htsjdk/samtools/BinaryBAMIndexWriter.java index ec9c7e5371..606f07de87 100644 --- a/src/main/java/htsjdk/samtools/BinaryBAMIndexWriter.java +++ b/src/main/java/htsjdk/samtools/BinaryBAMIndexWriter.java @@ -26,7 +26,6 @@ import htsjdk.samtools.util.BinaryCodec; import htsjdk.samtools.util.IOUtil; - import java.io.File; import java.io.IOException; import java.io.OutputStream; @@ -97,11 +96,11 @@ public void writeReference(final BAMIndexContent content) { return; } - if (content.getReferenceSequence() != count){ - throw new SAMException("Unexpectedly writing reference " + content.getReferenceSequence() + - ", expecting reference " + count); + if (content.getReferenceSequence() != count) { + throw new SAMException("Unexpectedly writing reference " + content.getReferenceSequence() + + ", expecting reference " + count); } - count ++; + count++; // write bins @@ -113,21 +112,19 @@ public void writeReference(final BAMIndexContent content) { return; } - //final List chunks = content.getMetaData() == null ? null + // final List chunks = content.getMetaData() == null ? null // : content.getMetaData().getMetaDataChunks(); final BAMIndexMetaData metaData = content.getMetaData(); - codec.writeInt(size + ((metaData != null)? 1 : 0 )); + codec.writeInt(size + ((metaData != null) ? 1 : 0)); // codec.writeInt(size); - for (final Bin bin : bins) { // note, bins will always be sorted - if (bin.getBinNumber() == GenomicIndexUtil.MAX_BINS) - continue; + for (final Bin bin : bins) { // note, bins will always be sorted + if (bin.getBinNumber() == GenomicIndexUtil.MAX_BINS) continue; writeBin(bin); } - // write metadata "bin" and chunks - if (metaData != null) - writeChunkMetaData(metaData); + // write metadata "bin" and chunks + if (metaData != null) writeChunkMetaData(metaData); // write linear index @@ -149,7 +146,8 @@ public void writeReference(final BAMIndexContent content) { try { codec.getOutputStream().flush(); } catch (final IOException e) { - throw new SAMException("IOException in BinaryBAMIndexWriter reference " + content.getReferenceSequence(), e); + throw new SAMException( + "IOException in BinaryBAMIndexWriter reference " + content.getReferenceSequence(), e); } } @@ -173,12 +171,12 @@ public void close() { private void writeBin(final Bin bin) { final int binNumber = bin.getBinNumber(); - if (binNumber >= GenomicIndexUtil.MAX_BINS){ + if (binNumber >= GenomicIndexUtil.MAX_BINS) { throw new SAMException("Unexpected bin number when writing bam index " + binNumber); } - + codec.writeInt(binNumber); - if (bin.getChunkList() == null){ + if (bin.getChunkList() == null) { codec.writeInt(0); return; } @@ -204,7 +202,6 @@ private void writeChunkMetaData(final BAMIndexMetaData metaData) { codec.writeLong(metaData.getLastOffset()); codec.writeLong(metaData.getAlignedRecordCount()); codec.writeLong(metaData.getUnalignedRecordCount()); - } private void writeHeader() { @@ -215,6 +212,6 @@ private void writeHeader() { } private void writeNullContent() { - codec.writeLong(0); // 0 bins , 0 intv + codec.writeLong(0); // 0 bins , 0 intv } } diff --git a/src/main/java/htsjdk/samtools/BinaryTagCodec.java b/src/main/java/htsjdk/samtools/BinaryTagCodec.java index c0d9d33ee2..94f5c8bdf0 100644 --- a/src/main/java/htsjdk/samtools/BinaryTagCodec.java +++ b/src/main/java/htsjdk/samtools/BinaryTagCodec.java @@ -25,7 +25,6 @@ import htsjdk.samtools.util.BinaryCodec; import htsjdk.samtools.util.StringUtil; - import java.lang.reflect.Array; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -69,7 +68,7 @@ public BinaryTagCodec(final BinaryCodec binaryCodec) { private static int getBinaryValueSize(final Object attributeValue) { switch (getTagValueType(attributeValue)) { case 'Z': - return ((String)attributeValue).length() + 1; + return ((String) attributeValue).length() + 1; case 'A': return 1; case 'I': @@ -84,26 +83,26 @@ private static int getBinaryValueSize(final Object attributeValue) { case 'f': return 4; case 'H': - final byte[] byteArray = (byte[])attributeValue; + final byte[] byteArray = (byte[]) attributeValue; return byteArray.length * 2 + 1; case 'B': final int numElements = Array.getLength(attributeValue); final int elementSize; - if(attributeValue instanceof byte[]) { + if (attributeValue instanceof byte[]) { elementSize = 1; - } else if(attributeValue instanceof short[]) { + } else if (attributeValue instanceof short[]) { elementSize = 2; - } else if(attributeValue instanceof int[]) { + } else if (attributeValue instanceof int[]) { elementSize = 4; - } else if(attributeValue instanceof float[]) { + } else if (attributeValue instanceof float[]) { elementSize = 4; } else { throw new IllegalArgumentException("Unsupported array type: " + attributeValue.getClass()); } return numElements * elementSize + FIXED_BINARY_ARRAY_TAG_SIZE; default: - throw new IllegalArgumentException("When writing BAM, unrecognized tag type " + - attributeValue.getClass().getName()); + throw new IllegalArgumentException("When writing BAM, unrecognized tag type " + + attributeValue.getClass().getName()); } } @@ -127,21 +126,27 @@ static char getTagValueType(final Object value) { } else if (value instanceof Float) { return 'f'; } else if (value instanceof Number) { - if (!(value instanceof Byte || value instanceof Short || value instanceof Integer || value instanceof Long)) { - throw new IllegalArgumentException("Unrecognized tag type " + value.getClass().getName()); + if (!(value instanceof Byte + || value instanceof Short + || value instanceof Integer + || value instanceof Long)) { + throw new IllegalArgumentException( + "Unrecognized tag type " + value.getClass().getName()); } - return getIntegerType(((Number)value).longValue()); + return getIntegerType(((Number) value).longValue()); } /* Note that H tag type is never written anymore, because B style is more compact. else if (value instanceof byte[]) { return 'H'; } - */ - else if (value instanceof byte[] || value instanceof short[] || value instanceof int[] || value instanceof float[]) { + */ else if (value instanceof byte[] + || value instanceof short[] + || value instanceof int[] + || value instanceof float[]) { return 'B'; } else { - throw new IllegalArgumentException("When writing BAM, unrecognized tag type " + - value.getClass().getName()); + throw new IllegalArgumentException("When writing BAM, unrecognized tag type " + + value.getClass().getName()); } } @@ -149,7 +154,7 @@ else if (value instanceof byte[] || value instanceof short[] || value instanceof * @param val Integer tag value. * @return Tag type corresponding to the smallest integer type that will hold the given value. */ - static private char getIntegerType(final long val) { + private static char getIntegerType(final long val) { if (val > MAX_UINT) { throw new IllegalArgumentException("Integer attribute value too large to be encoded in BAM"); } @@ -190,31 +195,31 @@ public void writeTag(final short tag, final Object value, final boolean isUnsign switch (tagValueType) { case 'Z': - binaryCodec.writeString((String)value, false, true); + binaryCodec.writeString((String) value, false, true); break; case 'A': - binaryCodec.writeByte(((Character)value)); + binaryCodec.writeByte(((Character) value)); break; case 'I': - binaryCodec.writeUInt((Long)value); + binaryCodec.writeUInt((Long) value); break; case 'i': - binaryCodec.writeInt(((Number)value).intValue()); + binaryCodec.writeInt(((Number) value).intValue()); break; case 's': - binaryCodec.writeShort(((Number)value).shortValue()); + binaryCodec.writeShort(((Number) value).shortValue()); break; case 'S': - binaryCodec.writeUShort(((Number)value).intValue()); + binaryCodec.writeUShort(((Number) value).intValue()); break; case 'c': - binaryCodec.writeByte(((Number)value).byteValue()); + binaryCodec.writeByte(((Number) value).byteValue()); break; case 'C': - binaryCodec.writeUByte(((Integer)value).shortValue()); + binaryCodec.writeUByte(((Integer) value).shortValue()); break; case 'f': - binaryCodec.writeFloat((Float)value); + binaryCodec.writeFloat((Float) value); break; /* Writing H is no longer supported @@ -227,35 +232,35 @@ public void writeTag(final short tag, final Object value, final boolean isUnsign writeArray(value, isUnsignedArray); break; default: - throw new IllegalArgumentException("When writing BAM, unrecognized tag type " + - value.getClass().getName()); + throw new IllegalArgumentException("When writing BAM, unrecognized tag type " + + value.getClass().getName()); } } private void writeArray(final Object value, final boolean isUnsignedArray) { if (value instanceof byte[]) { - binaryCodec.writeByte(isUnsignedArray? 'C': 'c'); + binaryCodec.writeByte(isUnsignedArray ? 'C' : 'c'); final byte[] array = (byte[]) value; binaryCodec.writeInt(array.length); - for (final byte element: array) binaryCodec.writeByte(element); + for (final byte element : array) binaryCodec.writeByte(element); } else if (value instanceof short[]) { - binaryCodec.writeByte(isUnsignedArray? 'S': 's'); + binaryCodec.writeByte(isUnsignedArray ? 'S' : 's'); final short[] array = (short[]) value; binaryCodec.writeInt(array.length); - for (final short element: array) binaryCodec.writeShort(element); + for (final short element : array) binaryCodec.writeShort(element); } else if (value instanceof int[]) { - binaryCodec.writeByte(isUnsignedArray? 'I': 'i'); + binaryCodec.writeByte(isUnsignedArray ? 'I' : 'i'); final int[] array = (int[]) value; binaryCodec.writeInt(array.length); - for (final int element: array) binaryCodec.writeInt(element); + for (final int element : array) binaryCodec.writeInt(element); } else if (value instanceof float[]) { binaryCodec.writeByte('f'); final float[] array = (float[]) value; binaryCodec.writeInt(array.length); - for (final float element: array) binaryCodec.writeFloat(element); + for (final float element : array) binaryCodec.writeFloat(element); } else throw new SAMException("Unrecognized array value type: " + value.getClass()); } @@ -266,8 +271,11 @@ private void writeArray(final Object value, final boolean isUnsignedArray) { * @param offset Where in binaryRep tags start. * @param length How many bytes in binaryRep are tag storage. */ - public static SAMBinaryTagAndValue readTags(final byte[] binaryRep, final int offset, - final int length, final ValidationStringency validationStringency) { + public static SAMBinaryTagAndValue readTags( + final byte[] binaryRep, + final int offset, + final int length, + final ValidationStringency validationStringency) { final ByteBuffer byteBuffer = ByteBuffer.wrap(binaryRep, offset, length); byteBuffer.order(ByteOrder.LITTLE_ENDIAN); @@ -282,7 +290,8 @@ public static SAMBinaryTagAndValue readTags(final byte[] binaryRep, final int of tmp = new SAMBinaryTagAndValue(tag, readSingleValue(tagType, byteBuffer, validationStringency), true); } else { final TagValueAndUnsignedArrayFlag valueAndFlag = readArray(byteBuffer, validationStringency); - if (valueAndFlag.isUnsignedArray) tmp = new SAMBinaryTagAndUnsignedArrayValue(tag, valueAndFlag.value, true); + if (valueAndFlag.isUnsignedArray) + tmp = new SAMBinaryTagAndUnsignedArrayValue(tag, valueAndFlag.value, true); else tmp = new SAMBinaryTagAndValue(tag, valueAndFlag.value, true); } @@ -292,12 +301,10 @@ public static SAMBinaryTagAndValue readTags(final byte[] binaryRep, final int of if (head == null) { head = tmp; tail = tmp; - } - else if (tmp.tag > tail.tag) { + } else if (tmp.tag > tail.tag) { tail.next = tmp; tail = tmp; - } - else { + } else { head = head.insert(tmp); } } @@ -311,57 +318,58 @@ else if (tmp.tag > tail.tag) { * @param byteBuffer Little-ending byte buffer to read value from. * @return Value in in-memory Object form. */ - private static Object readSingleValue(final byte tagType, final ByteBuffer byteBuffer, - final ValidationStringency validationStringency) { + private static Object readSingleValue( + final byte tagType, final ByteBuffer byteBuffer, final ValidationStringency validationStringency) { switch (tagType) { case 'Z': return readNullTerminatedString(byteBuffer); case 'A': - return (char)byteBuffer.get(); + return (char) byteBuffer.get(); case 'I': final long val = byteBuffer.getInt() & 0xffffffffL; - if ( val <= Integer.MAX_VALUE ) { - return (int)val; + if (val <= Integer.MAX_VALUE) { + return (int) val; } // If it won't fit into a signed integer, but is within range for an unsigned 32-bit integer, // return it directly as a long - if (! SAMUtils.isValidUnsignedIntegerAttribute(val)) { - SAMUtils.processValidationError(new SAMValidationError(SAMValidationError.Type.TAG_VALUE_TOO_LARGE, - "Unsigned integer is out of range for a 32-bit unsigned value: " + val, null), validationStringency); + if (!SAMUtils.isValidUnsignedIntegerAttribute(val)) { + SAMUtils.processValidationError( + new SAMValidationError( + SAMValidationError.Type.TAG_VALUE_TOO_LARGE, + "Unsigned integer is out of range for a 32-bit unsigned value: " + val, + null), + validationStringency); } return val; case 'i': return byteBuffer.getInt(); case 's': - return (int)byteBuffer.getShort(); + return (int) byteBuffer.getShort(); case 'S': // Convert to unsigned short stored in an int return byteBuffer.getShort() & 0xffff; case 'c': - return (int)byteBuffer.get(); + return (int) byteBuffer.get(); case 'C': // Convert to unsigned byte stored in an int - return (int)byteBuffer.get() & 0xff; + return (int) byteBuffer.get() & 0xff; case 'f': return byteBuffer.getFloat(); case 'H': final String hexRep = readNullTerminatedString(byteBuffer); return StringUtil.hexStringToBytes(hexRep); default: - throw new SAMFormatException("Unrecognized tag type: " + (char)tagType); + throw new SAMFormatException("Unrecognized tag type: " + (char) tagType); } } - - - /** * Read value of specified type. * @param byteBuffer Little-ending byte buffer to read value from. * @return CVO containing the value in in-memory Object form, and a flag indicating whether it is unsigned or not. */ - private static TagValueAndUnsignedArrayFlag readArray(final ByteBuffer byteBuffer, - final ValidationStringency validationStringency) { + private static TagValueAndUnsignedArrayFlag readArray( + final ByteBuffer byteBuffer, final ValidationStringency validationStringency) { final byte arrayType = byteBuffer.get(); final boolean isUnsigned = Character.isUpperCase(arrayType); final int length = byteBuffer.getInt(); @@ -401,7 +409,7 @@ private static TagValueAndUnsignedArrayFlag readArray(final ByteBuffer byteBuffe } default: - throw new SAMFormatException("Unrecognized tag array type: " + (char)arrayType); + throw new SAMFormatException("Unrecognized tag array type: " + (char) arrayType); } return new TagValueAndUnsignedArrayFlag(value, isUnsigned); } @@ -412,7 +420,9 @@ private static String readNullTerminatedString(final ByteBuffer byteBuffer) { final int start = byteBuffer.arrayOffset() + byteBuffer.position(); final int limit = byteBuffer.arrayOffset() + byteBuffer.limit(); int end = start; - while (end < limit && array[end] != 0) { end++; } + while (end < limit && array[end] != 0) { + end++; + } if (end >= limit) { throw new SAMFormatException("Null-terminated string tag value is not null terminated."); } diff --git a/src/main/java/htsjdk/samtools/BinningIndexBuilder.java b/src/main/java/htsjdk/samtools/BinningIndexBuilder.java index 3b329d2bc1..76046558fd 100644 --- a/src/main/java/htsjdk/samtools/BinningIndexBuilder.java +++ b/src/main/java/htsjdk/samtools/BinningIndexBuilder.java @@ -23,12 +23,9 @@ */ package htsjdk.samtools; -import htsjdk.samtools.util.BlockCompressedFilePointerUtil; +import static htsjdk.samtools.GenomicIndexUtil.MAX_BINS; import java.util.Arrays; -import java.util.List; - -import static htsjdk.samtools.GenomicIndexUtil.MAX_BINS; /** * Builder for a BinningIndexContent object. @@ -54,7 +51,8 @@ public class BinningIndexBuilder { * if false, leave uninitialized values as -1, which is required when merging index files * (see {@link BAMIndexMerger}) */ - public BinningIndexBuilder(final int referenceSequence, final int sequenceLength, final boolean fillInUninitializedValues) { + public BinningIndexBuilder( + final int referenceSequence, final int sequenceLength, final boolean fillInUninitializedValues) { this.referenceSequence = referenceSequence; this.fillInUninitializedValues = fillInUninitializedValues; // Initially set each window to -1 so we can distinguish between windows that have no overlapping @@ -84,8 +82,11 @@ public BinningIndexBuilder(final int referenceSequence) { */ public interface FeatureToBeIndexed { public int getStart(); + public int getEnd(); + public Integer getIndexingBin(); + public Chunk getChunk(); } @@ -96,7 +97,6 @@ public void processFeature(final FeatureToBeIndexed feature) { final Integer binNumber = feature.getIndexingBin(); final int binNum = binNumber == null ? computeIndexingBin(feature) : binNumber; - // is there a bin already represented for this index? if not, add one final Bin bin; if (bins[binNum] != null) { @@ -120,7 +120,7 @@ public void processFeature(final FeatureToBeIndexed feature) { int startWindow = LinearIndex.convertToLinearIndexOffset(feature.getStart()); // the 16k window final int endWindow; - if (featureEnd == GenomicIndexUtil.UNSET_GENOMIC_LOCATION) { // assume feature uses one position + if (featureEnd == GenomicIndexUtil.UNSET_GENOMIC_LOCATION) { // assume feature uses one position // Next line for C (samtools index) compatibility. Differs only when on a window boundary startWindow = LinearIndex.convertToLinearIndexOffset(feature.getStart() - 1); endWindow = startWindow; @@ -151,16 +151,16 @@ public void processFeature(final FeatureToBeIndexed feature) { */ public BinningIndexContent generateIndexContent() { - // process bins - if (binsSeen == 0) return null; // no bins for this reference + if (binsSeen == 0) return null; // no bins for this reference // process chunks // nothing needed // process linear index // linear index will only be as long as the largest index seen - final long[] newIndex = new long[largestIndexSeen + 1]; // in java1.6 Arrays.copyOf(index, largestIndexSeen + 1); + final long[] newIndex = + new long[largestIndexSeen + 1]; // in java1.6 Arrays.copyOf(index, largestIndexSeen + 1); // C (samtools index) also fills in intermediate 0's with values. This seems unnecessary, but safe long lastNonZeroOffset = 0; @@ -183,7 +183,7 @@ public BinningIndexContent generateIndexContent() { private int computeIndexingBin(final FeatureToBeIndexed feature) { // regionToBin has zero-based, half-open API - final int start = feature.getStart()-1; + final int start = feature.getStart() - 1; int end = feature.getEnd(); if (end <= 0) { // If feature end cannot be determined (e.g. because a read is not really aligned), diff --git a/src/main/java/htsjdk/samtools/BinningIndexContent.java b/src/main/java/htsjdk/samtools/BinningIndexContent.java index bc55ef693d..e2ad018566 100644 --- a/src/main/java/htsjdk/samtools/BinningIndexContent.java +++ b/src/main/java/htsjdk/samtools/BinningIndexContent.java @@ -51,7 +51,6 @@ public class BinningIndexContent { */ private final LinearIndex mLinearIndex; - /** * @param referenceSequence Content corresponds to this reference. * @param binList Array of bins represented by this content, possibly sparse @@ -110,7 +109,6 @@ public LinearIndex getLinearIndex() { return mLinearIndex; } - /** * * @param startPos 1-based, inclusive @@ -118,7 +116,7 @@ public LinearIndex getLinearIndex() { * @return List of Chunks overlapping the given region. May return null if there are none. */ public List getChunksOverlapping(final int startPos, final int endPos) { - final BitSet overlappingBins = GenomicIndexUtil.regionToBins(startPos,endPos); + final BitSet overlappingBins = GenomicIndexUtil.regionToBins(startPos, endPos); if (overlappingBins == null) return null; // System.out.println("# Sequence target TID: " + referenceIndex); @@ -147,7 +145,7 @@ public static class BinList implements Iterable { private final Bin[] mBinArray; public final int numberOfNonNullBins; - public final int maxBinNumber; // invariant: maxBinNumber = mBinArray.length -1 since array is 0 based + public final int maxBinNumber; // invariant: maxBinNumber = mBinArray.length -1 since array is 0 based /** * @param binArray a sparse array representation of the bins. The index into the array is the bin number. @@ -207,8 +205,7 @@ public boolean hasNext() { */ @Override public Bin next() { - if (!hasNext()) - throw new NoSuchElementException("This BinIterator is currently empty"); + if (!hasNext()) throw new NoSuchElementException("This BinIterator is currently empty"); final Bin result = getBin(nextBin); nextBin++; return result; diff --git a/src/main/java/htsjdk/samtools/BrowseableBAMIndex.java b/src/main/java/htsjdk/samtools/BrowseableBAMIndex.java index c6eca51e55..8ebe3d722e 100644 --- a/src/main/java/htsjdk/samtools/BrowseableBAMIndex.java +++ b/src/main/java/htsjdk/samtools/BrowseableBAMIndex.java @@ -21,7 +21,7 @@ public interface BrowseableBAMIndex extends BAMIndex { * @return the level associated with the given bin number. */ public int getLevelForBin(final Bin bin); - + /** * Gets the first locus that this bin can index into. * @param bin The bin to test. @@ -50,5 +50,5 @@ public interface BrowseableBAMIndex extends BAMIndex { * @param bin The bin over which to perform an overlapping query. * @return The file pointers */ - BAMFileSpan getSpanOverlapping(final Bin bin); + BAMFileSpan getSpanOverlapping(final Bin bin); } diff --git a/src/main/java/htsjdk/samtools/CRAMBAIIndexer.java b/src/main/java/htsjdk/samtools/CRAMBAIIndexer.java index 38bdc35b62..496d697ca6 100755 --- a/src/main/java/htsjdk/samtools/CRAMBAIIndexer.java +++ b/src/main/java/htsjdk/samtools/CRAMBAIIndexer.java @@ -1,452 +1,453 @@ -/******************************************************************************* - * Copyright 2013 EMBL-EBI - * - * 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. - ******************************************************************************/ -/* - * The MIT License - * - * Copyright (c) 2014 The Broad Institute - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sub-license, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package htsjdk.samtools; - -import htsjdk.samtools.cram.BAIEntry; -import htsjdk.samtools.cram.CRAIEntry; -import htsjdk.samtools.cram.CRAIIndex; -import htsjdk.samtools.cram.build.CramIO; -import htsjdk.samtools.cram.ref.ReferenceContext; -import htsjdk.samtools.cram.structure.*; -import htsjdk.samtools.seekablestream.SeekableStream; -import htsjdk.samtools.util.BlockCompressedFilePointerUtil; -import htsjdk.samtools.util.Log; -import htsjdk.samtools.util.ProgressLogger; -import htsjdk.samtools.util.RuntimeIOException; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.*; - -/** - * Class for both constructing BAM index content and writing it out. - * - * There are two usage patterns: - * - * 1) Building a bam index (BAI) while building the CRAM file - * 2) Building a bam index (BAI) from an existing CRAI file - * - * 1) is driven by {@link CRAMContainerStreamWriter} and proceeds by calling {@link CRAMBAIIndexer#processContainer} - * after each {@link Container} is built, and {@link CRAMBAIIndexer#finish()} is called at the end. - * - * 2) is driven by {@link CRAIIndex#openCraiFileAsBaiStream(InputStream, SAMSequenceDictionary)} - * and proceeds by processing {@link CRAIEntry} elements obtained from - * {@link CRAMCRAIIndexer#readIndex(InputStream)}. {@link CRAMBAIIndexer#processBAIEntry(BAIEntry)} - * is called on each {@link CRAIEntry} and {@link CRAMBAIIndexer#finish()} is called at the end. - * - * NOTE: a third pattern of building a BAI from a CRAM file is also supported by this class, - * but it is unused. This would be accomplished via {@link #createIndex(SeekableStream, File, Log, ValidationStringency)}. - */ -public class CRAMBAIIndexer implements CRAMIndexer { - - // The number of references (chromosomes) in the BAM file - private final int numReferences; - - // output written as binary, or (for debugging) as text - private final BAMIndexWriter outputWriter; - - private int currentReference = 0; - - // content is built up from the input bam file using this - private final CRAMBAIIndexBuilder indexBuilder; - private final CompressorCache compressorCache = new CompressorCache(); - - /** - * Create a CRAM indexer that writes BAI to a file. - * - * @param output binary BAM Index (.bai) file - * @param fileHeader header for the corresponding bam file - */ - private CRAMBAIIndexer(final File output, final SAMFileHeader fileHeader) { - if (fileHeader.getSortOrder() != SAMFileHeader.SortOrder.coordinate) { - throw new SAMException("CRAM file must be coordinate-sorted for indexing."); - } - numReferences = fileHeader.getSequenceDictionary().size(); - indexBuilder = new CRAMBAIIndexBuilder(fileHeader); - outputWriter = new BinaryBAMIndexWriter(numReferences, output); - } - - /** - * Create a CRAM indexer that writes BAI to a stream. - * - * @param output Index will be written here. output will be closed when finish() method is called. - * @param fileHeader header for the corresponding bam file. - */ - public CRAMBAIIndexer(final OutputStream output, final SAMFileHeader fileHeader) { - if (fileHeader.getSortOrder() != SAMFileHeader.SortOrder.coordinate) { - throw new SAMException("CRAM file mut be coordinate-sorted for indexing."); - } - numReferences = fileHeader.getSequenceDictionary().size(); - indexBuilder = new CRAMBAIIndexBuilder(fileHeader); - outputWriter = new BinaryBAMIndexWriter(numReferences, output); - } - - /** - * Index a container, any of mapped, unmapped and multiple references are allowed. - * The only requirement is sort order by coordinate. - * For multiref containers the method reads the container through unpacking all reads. - * This is slower than single reference but should be faster than normal reading. - * - * @param container container to be indexed - */ - @Override - public void processContainer(final Container container, final ValidationStringency validationStringency) { - container.getBAIEntries(compressorCache).forEach(b -> processBAIEntry(b)); - } - - public final void processBAIEntry(final BAIEntry baiEntry) { - - final ReferenceContext entryContext = baiEntry.getReferenceContext(); - if (entryContext.isMultiRef()) { - throw new SAMException("Expecting a single reference or unmapped slice."); - } - - if (entryContext.isMappedSingleRef()) { - final int reference = entryContext.getReferenceSequenceID(); - if (reference != currentReference) { - // process any completed references - advanceToReference(reference); - } - - // check that it advanced properly - if (reference != currentReference) { - throw new SAMException( - String.format("Unexpected reference %s when constructing index for reference %d for slice", - reference, - currentReference)); - } - } - - indexBuilder.recordBAIEntryIndexMetadata(baiEntry); - - if (entryContext.isMappedSingleRef()) { - indexBuilder.processBAIEntry(baiEntry); - } - } - - /** - * After all the slices have been processed, finish is called. - * Writes any final information and closes the output file. - */ - @Override - public void finish() { - // process any remaining references - advanceToReference(numReferences); - outputWriter.writeNoCoordinateRecordCount(indexBuilder.getNoCoordinateRecordCount()); - outputWriter.close(); - } - - /** - * write out any references between the currentReference and the nextReference - */ - private void advanceToReference(final int nextReference) { - while (currentReference < nextReference) { - final BAMIndexContent content = indexBuilder.processCurrentReference(); - outputWriter.writeReference(content); - currentReference++; - indexBuilder.startNewReference(); - } - } - - /** - * Generates a BAI index file from an input CRAM stream - * - * @param stream CRAM stream to index - * @param output File for output index file - * @param log optional {@link htsjdk.samtools.util.Log} to output progress - */ - public static void createIndex(final SeekableStream stream, - final File output, - final Log log, - final ValidationStringency validationStringency) { - - final CramHeader cramHeader = CramIO.readCramHeader(stream); - final SAMFileHeader samFileHeader = Container.readSAMFileHeaderContainer(cramHeader.getCRAMVersion(), stream, null); - if (samFileHeader.getSortOrder() != SAMFileHeader.SortOrder.coordinate) { - throw new SAMException(String.format( - "Input must be coordinate sorted (found %s) to create an index.", - samFileHeader.getSortOrder())); - } - final CRAMBAIIndexer indexer = new CRAMBAIIndexer(output, samFileHeader); - - Container container = null; - final ProgressLogger progressLogger = new ProgressLogger(log, 1, "indexed", "slices"); - do { - try { - container = new Container(cramHeader.getCRAMVersion(), stream, stream.position()); - } catch (final IOException e) { - throw new RuntimeIOException("error getting stream position", e); - } - if (container == null || container.isEOF()) { - break; - } - - indexer.processContainer(container, validationStringency); - - if (null != log) { - String sequenceName; - final AlignmentContext alignmentContext = container.getAlignmentContext(); - final ReferenceContext containerReferenceContext = alignmentContext.getReferenceContext(); - switch (containerReferenceContext.getType()) { - case UNMAPPED_UNPLACED_TYPE: - sequenceName = "?"; - break; - case MULTIPLE_REFERENCE_TYPE: - sequenceName = "???"; - break; - default: - sequenceName = samFileHeader.getSequence( - containerReferenceContext.getReferenceSequenceID()).getSequenceName(); - break; - } - progressLogger.record(sequenceName, alignmentContext.getAlignmentStart()); - } - - } while (!container.isEOF()); - - indexer.finish(); - } - - /** - * Class for constructing BAM index files. - * One instance is used to construct an entire index. - * processAlignment is called for each alignment until a new reference is encountered, then - * processReference is called when all records for the reference have been processed. - */ - private class CRAMBAIIndexBuilder { - - private final SAMFileHeader bamHeader; - - // the bins for the current reference - private Bin[] bins; // made only as big as needed for each reference - private int binsSeen = 0; - - // linear index for the current reference - private final long[] index = new long[LinearIndex.MAX_LINEAR_INDEX_SIZE]; - private int largestIndexSeen = -1; - - // information in meta data - private final BAMIndexMetaData indexStats = new BAMIndexMetaData(); - - /** - * @param header SAMFileHeader used for reference name (in index stats) and for max bin number - */ - private CRAMBAIIndexBuilder(final SAMFileHeader header) { - this.bamHeader = header; - } - - private SAMFileHeader getBamHeader() { - return bamHeader; - } - - private void recordBAIEntryIndexMetadata(final BAIEntry baiEntry) { - indexStats.recordMetaData(baiEntry); - } - - private int computeIndexingBin(final BAIEntry baiEntry) { - // regionToBin has zero-based, half-open API - //final AlignmentContext sliceAlignmentContext = baiEntry.getAlignmentContext(); - final int alignmentStart = baiEntry.getAlignmentStart() - 1; - int alignmentEnd = baiEntry.getAlignmentStart() + baiEntry.getAlignmentSpan() - 1; - if (alignmentEnd <= alignmentStart) { - // If alignment end cannot be determined (e.g. because this read is not really aligned), - // then treat this as a one base alignment for indexing purposes. - alignmentEnd = alignmentStart + 1; - } - return GenomicIndexUtil.regionToBin(alignmentStart, alignmentEnd); - } - - /** - * Record any index information for a given CRAM slice - * - * Reads these Slice fields: - * sequenceId, alignmentStart, alignmentSpan, containerByteOffset, index - * - //* @param slice CRAM slice, single ref only. - */ - private void processBAIEntry(final BAIEntry baiEntry) { - final ReferenceContext sliceContext = baiEntry.getReferenceContext(); - if (! sliceContext.isMappedSingleRef()) { - return; // do nothing for records without coordinates, but count them - } - - // various checks - final int reference = sliceContext.getReferenceSequenceID(); - if (reference != currentReference) { - throw new SAMException( - String.format("Unexpected reference %s when constructing index for reference %d for slice", - reference, - currentReference)); - } - - // process bins - - final int binNum = computeIndexingBin(baiEntry); - - // has the bins array been allocated? If not, do so - if (bins == null) { - final SAMSequenceRecord seq = bamHeader.getSequence(reference); - if (seq == null) { - bins = new Bin[GenomicIndexUtil.MAX_BINS + 1]; - } else { - bins = new Bin[AbstractBAMFileIndex.getMaxBinNumberForSequenceLength(seq.getSequenceLength()) + 1]; - } - } - - // is there a bin already represented for this index? if not, add one - final Bin bin; - if (bins[binNum] != null) { - bin = bins[binNum]; - } else { - bin = new Bin(reference, binNum); - bins[binNum] = bin; - binsSeen++; - } - - // process chunks - - final long chunkStart = (baiEntry.getContainerStartByteOffset() << 16) | baiEntry.getLandmarkIndex(); - final long chunkEnd = ((baiEntry.getContainerStartByteOffset() << 16) | baiEntry.getLandmarkIndex()) + 1; - - final Chunk newChunk = new Chunk(chunkStart, chunkEnd); - - final List oldChunks = bin.getChunkList(); - if (!bin.containsChunks()) { - bin.addInitialChunk(newChunk); - - } else { - final Chunk lastChunk = bin.getLastChunk(); - - // Coalesce chunks that are in the same or adjacent file blocks. - // Similar to AbstractBAMFileIndex.optimizeChunkList, - // but no need to copy the list, no minimumOffset, and maintain bin.lastChunk - if (BlockCompressedFilePointerUtil.areInSameOrAdjacentBlocks(lastChunk.getChunkEnd(), chunkStart)) { - lastChunk.setChunkEnd(chunkEnd); // coalesced - } else { - oldChunks.add(newChunk); - bin.setLastChunk(newChunk); - } - } - - // process linear index - - // the smallest file offset that appears in the 16k window for this bin - final int alignmentStart = baiEntry.getAlignmentStart(); - final int alignmentEnd = baiEntry.getAlignmentStart() + baiEntry.getAlignmentSpan(); - int startWindow = LinearIndex.convertToLinearIndexOffset(alignmentStart); // the 16k window - final int endWindow; - - if (alignmentEnd == SAMRecord.NO_ALIGNMENT_START) { // assume alignment uses one position - // Next line for C (samtools index) compatibility. Differs only when on a window boundary - startWindow = LinearIndex.convertToLinearIndexOffset(alignmentStart - 1); - endWindow = startWindow; - } else { - endWindow = LinearIndex.convertToLinearIndexOffset(alignmentEnd); - } - - if (endWindow > largestIndexSeen) { - largestIndexSeen = endWindow; - } - - // set linear index at every 16K window that this alignment overlaps - for (int win = startWindow; win <= endWindow; win++) { - if (index[win] == 0 || chunkStart < index[win]) { - index[win] = chunkStart; - } - } - } - - /** - * Creates the BAMIndexContent for this reference. - * Requires all alignments of the reference have already been processed. - */ - private BAMIndexContent processCurrentReference() { - - // process bins - if (binsSeen == 0) { - return null; // no bins for this reference - } - - // process chunks - // nothing needed - - // process linear index - // linear index will only be as long as the largest index seen - final long[] newIndex = new long[largestIndexSeen + 1]; // in java1.6 Arrays.copyOf(index, largestIndexSeen + 1); - - // C (samtools index) also fills in intermediate 0's with values. This seems unnecessary, but safe - long lastNonZeroOffset = 0; - for (int i = 0; i <= largestIndexSeen; i++) { - if (index[i] == 0) { - index[i] = lastNonZeroOffset; // not necessary, but C (samtools index) does this - // note, if you remove the above line BAMIndexWriterTest.compareTextual and compareBinary will have to change - } else { - lastNonZeroOffset = index[i]; - } - newIndex[i] = index[i]; - } - - final LinearIndex linearIndex = new LinearIndex(currentReference, 0, newIndex); - - return new BAMIndexContent(currentReference, bins, binsSeen, indexStats, linearIndex); - } - - /** - * @return the count of records with no coordinate positions - */ - private long getNoCoordinateRecordCount() { - return indexStats.getNoCoordinateRecordCount(); - } - - /** - * reinitialize all data structures when the reference changes - */ - private void startNewReference() { - bins = null; - if (binsSeen > 0) { - Arrays.fill(index, 0); - } - binsSeen = 0; - largestIndexSeen = -1; - indexStats.newReference(); - } - } -} +/******************************************************************************* + * Copyright 2013 EMBL-EBI + * + * 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. + ******************************************************************************/ +/* + * The MIT License + * + * Copyright (c) 2014 The Broad Institute + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sub-license, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package htsjdk.samtools; + +import htsjdk.samtools.cram.BAIEntry; +import htsjdk.samtools.cram.CRAIEntry; +import htsjdk.samtools.cram.CRAIIndex; +import htsjdk.samtools.cram.build.CramIO; +import htsjdk.samtools.cram.ref.ReferenceContext; +import htsjdk.samtools.cram.structure.*; +import htsjdk.samtools.seekablestream.SeekableStream; +import htsjdk.samtools.util.BlockCompressedFilePointerUtil; +import htsjdk.samtools.util.Log; +import htsjdk.samtools.util.ProgressLogger; +import htsjdk.samtools.util.RuntimeIOException; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.*; + +/** + * Class for both constructing BAM index content and writing it out. + * + * There are two usage patterns: + * + * 1) Building a bam index (BAI) while building the CRAM file + * 2) Building a bam index (BAI) from an existing CRAI file + * + * 1) is driven by {@link CRAMContainerStreamWriter} and proceeds by calling {@link CRAMBAIIndexer#processContainer} + * after each {@link Container} is built, and {@link CRAMBAIIndexer#finish()} is called at the end. + * + * 2) is driven by {@link CRAIIndex#openCraiFileAsBaiStream(InputStream, SAMSequenceDictionary)} + * and proceeds by processing {@link CRAIEntry} elements obtained from + * {@link CRAMCRAIIndexer#readIndex(InputStream)}. {@link CRAMBAIIndexer#processBAIEntry(BAIEntry)} + * is called on each {@link CRAIEntry} and {@link CRAMBAIIndexer#finish()} is called at the end. + * + * NOTE: a third pattern of building a BAI from a CRAM file is also supported by this class, + * but it is unused. This would be accomplished via {@link #createIndex(SeekableStream, File, Log, ValidationStringency)}. + */ +public class CRAMBAIIndexer implements CRAMIndexer { + + // The number of references (chromosomes) in the BAM file + private final int numReferences; + + // output written as binary, or (for debugging) as text + private final BAMIndexWriter outputWriter; + + private int currentReference = 0; + + // content is built up from the input bam file using this + private final CRAMBAIIndexBuilder indexBuilder; + private final CompressorCache compressorCache = new CompressorCache(); + + /** + * Create a CRAM indexer that writes BAI to a file. + * + * @param output binary BAM Index (.bai) file + * @param fileHeader header for the corresponding bam file + */ + private CRAMBAIIndexer(final File output, final SAMFileHeader fileHeader) { + if (fileHeader.getSortOrder() != SAMFileHeader.SortOrder.coordinate) { + throw new SAMException("CRAM file must be coordinate-sorted for indexing."); + } + numReferences = fileHeader.getSequenceDictionary().size(); + indexBuilder = new CRAMBAIIndexBuilder(fileHeader); + outputWriter = new BinaryBAMIndexWriter(numReferences, output); + } + + /** + * Create a CRAM indexer that writes BAI to a stream. + * + * @param output Index will be written here. output will be closed when finish() method is called. + * @param fileHeader header for the corresponding bam file. + */ + public CRAMBAIIndexer(final OutputStream output, final SAMFileHeader fileHeader) { + if (fileHeader.getSortOrder() != SAMFileHeader.SortOrder.coordinate) { + throw new SAMException("CRAM file mut be coordinate-sorted for indexing."); + } + numReferences = fileHeader.getSequenceDictionary().size(); + indexBuilder = new CRAMBAIIndexBuilder(fileHeader); + outputWriter = new BinaryBAMIndexWriter(numReferences, output); + } + + /** + * Index a container, any of mapped, unmapped and multiple references are allowed. + * The only requirement is sort order by coordinate. + * For multiref containers the method reads the container through unpacking all reads. + * This is slower than single reference but should be faster than normal reading. + * + * @param container container to be indexed + */ + @Override + public void processContainer(final Container container, final ValidationStringency validationStringency) { + container.getBAIEntries(compressorCache).forEach(b -> processBAIEntry(b)); + } + + public final void processBAIEntry(final BAIEntry baiEntry) { + + final ReferenceContext entryContext = baiEntry.getReferenceContext(); + if (entryContext.isMultiRef()) { + throw new SAMException("Expecting a single reference or unmapped slice."); + } + + if (entryContext.isMappedSingleRef()) { + final int reference = entryContext.getReferenceSequenceID(); + if (reference != currentReference) { + // process any completed references + advanceToReference(reference); + } + + // check that it advanced properly + if (reference != currentReference) { + throw new SAMException(String.format( + "Unexpected reference %s when constructing index for reference %d for slice", + reference, currentReference)); + } + } + + indexBuilder.recordBAIEntryIndexMetadata(baiEntry); + + if (entryContext.isMappedSingleRef()) { + indexBuilder.processBAIEntry(baiEntry); + } + } + + /** + * After all the slices have been processed, finish is called. + * Writes any final information and closes the output file. + */ + @Override + public void finish() { + // process any remaining references + advanceToReference(numReferences); + outputWriter.writeNoCoordinateRecordCount(indexBuilder.getNoCoordinateRecordCount()); + outputWriter.close(); + } + + /** + * write out any references between the currentReference and the nextReference + */ + private void advanceToReference(final int nextReference) { + while (currentReference < nextReference) { + final BAMIndexContent content = indexBuilder.processCurrentReference(); + outputWriter.writeReference(content); + currentReference++; + indexBuilder.startNewReference(); + } + } + + /** + * Generates a BAI index file from an input CRAM stream + * + * @param stream CRAM stream to index + * @param output File for output index file + * @param log optional {@link htsjdk.samtools.util.Log} to output progress + */ + public static void createIndex( + final SeekableStream stream, + final File output, + final Log log, + final ValidationStringency validationStringency) { + + final CramHeader cramHeader = CramIO.readCramHeader(stream); + final SAMFileHeader samFileHeader = + Container.readSAMFileHeaderContainer(cramHeader.getCRAMVersion(), stream, null); + if (samFileHeader.getSortOrder() != SAMFileHeader.SortOrder.coordinate) { + throw new SAMException(String.format( + "Input must be coordinate sorted (found %s) to create an index.", samFileHeader.getSortOrder())); + } + final CRAMBAIIndexer indexer = new CRAMBAIIndexer(output, samFileHeader); + + Container container = null; + final ProgressLogger progressLogger = new ProgressLogger(log, 1, "indexed", "slices"); + do { + try { + container = new Container(cramHeader.getCRAMVersion(), stream, stream.position()); + } catch (final IOException e) { + throw new RuntimeIOException("error getting stream position", e); + } + if (container == null || container.isEOF()) { + break; + } + + indexer.processContainer(container, validationStringency); + + if (null != log) { + String sequenceName; + final AlignmentContext alignmentContext = container.getAlignmentContext(); + final ReferenceContext containerReferenceContext = alignmentContext.getReferenceContext(); + switch (containerReferenceContext.getType()) { + case UNMAPPED_UNPLACED_TYPE: + sequenceName = "?"; + break; + case MULTIPLE_REFERENCE_TYPE: + sequenceName = "???"; + break; + default: + sequenceName = samFileHeader + .getSequence(containerReferenceContext.getReferenceSequenceID()) + .getSequenceName(); + break; + } + progressLogger.record(sequenceName, alignmentContext.getAlignmentStart()); + } + + } while (!container.isEOF()); + + indexer.finish(); + } + + /** + * Class for constructing BAM index files. + * One instance is used to construct an entire index. + * processAlignment is called for each alignment until a new reference is encountered, then + * processReference is called when all records for the reference have been processed. + */ + private class CRAMBAIIndexBuilder { + + private final SAMFileHeader bamHeader; + + // the bins for the current reference + private Bin[] bins; // made only as big as needed for each reference + private int binsSeen = 0; + + // linear index for the current reference + private final long[] index = new long[LinearIndex.MAX_LINEAR_INDEX_SIZE]; + private int largestIndexSeen = -1; + + // information in meta data + private final BAMIndexMetaData indexStats = new BAMIndexMetaData(); + + /** + * @param header SAMFileHeader used for reference name (in index stats) and for max bin number + */ + private CRAMBAIIndexBuilder(final SAMFileHeader header) { + this.bamHeader = header; + } + + private SAMFileHeader getBamHeader() { + return bamHeader; + } + + private void recordBAIEntryIndexMetadata(final BAIEntry baiEntry) { + indexStats.recordMetaData(baiEntry); + } + + private int computeIndexingBin(final BAIEntry baiEntry) { + // regionToBin has zero-based, half-open API + // final AlignmentContext sliceAlignmentContext = baiEntry.getAlignmentContext(); + final int alignmentStart = baiEntry.getAlignmentStart() - 1; + int alignmentEnd = baiEntry.getAlignmentStart() + baiEntry.getAlignmentSpan() - 1; + if (alignmentEnd <= alignmentStart) { + // If alignment end cannot be determined (e.g. because this read is not really aligned), + // then treat this as a one base alignment for indexing purposes. + alignmentEnd = alignmentStart + 1; + } + return GenomicIndexUtil.regionToBin(alignmentStart, alignmentEnd); + } + + /** + * Record any index information for a given CRAM slice + * + * Reads these Slice fields: + * sequenceId, alignmentStart, alignmentSpan, containerByteOffset, index + * + * //* @param slice CRAM slice, single ref only. + */ + private void processBAIEntry(final BAIEntry baiEntry) { + final ReferenceContext sliceContext = baiEntry.getReferenceContext(); + if (!sliceContext.isMappedSingleRef()) { + return; // do nothing for records without coordinates, but count them + } + + // various checks + final int reference = sliceContext.getReferenceSequenceID(); + if (reference != currentReference) { + throw new SAMException(String.format( + "Unexpected reference %s when constructing index for reference %d for slice", + reference, currentReference)); + } + + // process bins + + final int binNum = computeIndexingBin(baiEntry); + + // has the bins array been allocated? If not, do so + if (bins == null) { + final SAMSequenceRecord seq = bamHeader.getSequence(reference); + if (seq == null) { + bins = new Bin[GenomicIndexUtil.MAX_BINS + 1]; + } else { + bins = new Bin[AbstractBAMFileIndex.getMaxBinNumberForSequenceLength(seq.getSequenceLength()) + 1]; + } + } + + // is there a bin already represented for this index? if not, add one + final Bin bin; + if (bins[binNum] != null) { + bin = bins[binNum]; + } else { + bin = new Bin(reference, binNum); + bins[binNum] = bin; + binsSeen++; + } + + // process chunks + + final long chunkStart = (baiEntry.getContainerStartByteOffset() << 16) | baiEntry.getLandmarkIndex(); + final long chunkEnd = ((baiEntry.getContainerStartByteOffset() << 16) | baiEntry.getLandmarkIndex()) + 1; + + final Chunk newChunk = new Chunk(chunkStart, chunkEnd); + + final List oldChunks = bin.getChunkList(); + if (!bin.containsChunks()) { + bin.addInitialChunk(newChunk); + + } else { + final Chunk lastChunk = bin.getLastChunk(); + + // Coalesce chunks that are in the same or adjacent file blocks. + // Similar to AbstractBAMFileIndex.optimizeChunkList, + // but no need to copy the list, no minimumOffset, and maintain bin.lastChunk + if (BlockCompressedFilePointerUtil.areInSameOrAdjacentBlocks(lastChunk.getChunkEnd(), chunkStart)) { + lastChunk.setChunkEnd(chunkEnd); // coalesced + } else { + oldChunks.add(newChunk); + bin.setLastChunk(newChunk); + } + } + + // process linear index + + // the smallest file offset that appears in the 16k window for this bin + final int alignmentStart = baiEntry.getAlignmentStart(); + final int alignmentEnd = baiEntry.getAlignmentStart() + baiEntry.getAlignmentSpan(); + int startWindow = LinearIndex.convertToLinearIndexOffset(alignmentStart); // the 16k window + final int endWindow; + + if (alignmentEnd == SAMRecord.NO_ALIGNMENT_START) { // assume alignment uses one position + // Next line for C (samtools index) compatibility. Differs only when on a window boundary + startWindow = LinearIndex.convertToLinearIndexOffset(alignmentStart - 1); + endWindow = startWindow; + } else { + endWindow = LinearIndex.convertToLinearIndexOffset(alignmentEnd); + } + + if (endWindow > largestIndexSeen) { + largestIndexSeen = endWindow; + } + + // set linear index at every 16K window that this alignment overlaps + for (int win = startWindow; win <= endWindow; win++) { + if (index[win] == 0 || chunkStart < index[win]) { + index[win] = chunkStart; + } + } + } + + /** + * Creates the BAMIndexContent for this reference. + * Requires all alignments of the reference have already been processed. + */ + private BAMIndexContent processCurrentReference() { + + // process bins + if (binsSeen == 0) { + return null; // no bins for this reference + } + + // process chunks + // nothing needed + + // process linear index + // linear index will only be as long as the largest index seen + final long[] newIndex = + new long[largestIndexSeen + 1]; // in java1.6 Arrays.copyOf(index, largestIndexSeen + 1); + + // C (samtools index) also fills in intermediate 0's with values. This seems unnecessary, but safe + long lastNonZeroOffset = 0; + for (int i = 0; i <= largestIndexSeen; i++) { + if (index[i] == 0) { + index[i] = lastNonZeroOffset; // not necessary, but C (samtools index) does this + // note, if you remove the above line BAMIndexWriterTest.compareTextual and compareBinary will have + // to change + } else { + lastNonZeroOffset = index[i]; + } + newIndex[i] = index[i]; + } + + final LinearIndex linearIndex = new LinearIndex(currentReference, 0, newIndex); + + return new BAMIndexContent(currentReference, bins, binsSeen, indexStats, linearIndex); + } + + /** + * @return the count of records with no coordinate positions + */ + private long getNoCoordinateRecordCount() { + return indexStats.getNoCoordinateRecordCount(); + } + + /** + * reinitialize all data structures when the reference changes + */ + private void startNewReference() { + bins = null; + if (binsSeen > 0) { + Arrays.fill(index, 0); + } + binsSeen = 0; + largestIndexSeen = -1; + indexStats.newReference(); + } + } +} diff --git a/src/main/java/htsjdk/samtools/CRAMCRAIIndexer.java b/src/main/java/htsjdk/samtools/CRAMCRAIIndexer.java index aaff4847fe..4b03425ee6 100644 --- a/src/main/java/htsjdk/samtools/CRAMCRAIIndexer.java +++ b/src/main/java/htsjdk/samtools/CRAMCRAIIndexer.java @@ -7,11 +7,10 @@ import htsjdk.samtools.cram.structure.*; import htsjdk.samtools.seekablestream.SeekableStream; import htsjdk.samtools.util.RuntimeIOException; - import java.io.BufferedOutputStream; +import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.IOException; import java.util.Collection; import java.util.Scanner; import java.util.zip.GZIPInputStream; @@ -28,8 +27,8 @@ */ public class CRAMCRAIIndexer implements CRAMIndexer { - final private CRAIIndex craiIndex = new CRAIIndex(); - final private GZIPOutputStream os; + private final CRAIIndex craiIndex = new CRAIIndex(); + private final GZIPOutputStream os; /** * Create a CRAMCRAIIndexer that writes to the given output stream. @@ -43,8 +42,7 @@ public CRAMCRAIIndexer(final OutputStream os, final SAMFileHeader samHeader) { } try { this.os = new GZIPOutputStream(new BufferedOutputStream(os)); - } - catch (IOException e) { + } catch (IOException e) { throw new RuntimeIOException("Error opening CRAI index output stream"); } } @@ -57,9 +55,7 @@ public CRAMCRAIIndexer(final OutputStream os, final SAMFileHeader samHeader) { * @param samHeader SAMFileHeader - user to verify sort order * @param entries the CRAI entries to index */ - public CRAMCRAIIndexer(final OutputStream os, - final SAMFileHeader samHeader, - final Collection entries) { + public CRAMCRAIIndexer(final OutputStream os, final SAMFileHeader samHeader, final Collection entries) { this(os, samHeader); craiIndex.addEntries(entries); } @@ -73,9 +69,7 @@ public void processContainer(final Container container) { } @Override - public void processContainer( - final Container container, - final ValidationStringency validationStringency) { + public void processContainer(final Container container, final ValidationStringency validationStringency) { processContainer(container); } @@ -88,8 +82,7 @@ public void finish() { craiIndex.writeIndex(os); os.flush(); os.close(); - } - catch (IOException e) { + } catch (IOException e) { throw new RuntimeIOException("Error writing CRAI index to output stream"); } } @@ -102,11 +95,11 @@ public void finish() { */ public static void writeIndex(final SeekableStream cramStream, OutputStream craiStream) { final CramHeader cramHeader = CramIO.readCramHeader(cramStream); - final SAMFileHeader samFileHeader = Container.readSAMFileHeaderContainer(cramHeader.getCRAMVersion(), cramStream, null); + final SAMFileHeader samFileHeader = + Container.readSAMFileHeaderContainer(cramHeader.getCRAMVersion(), cramStream, null); if (samFileHeader.getSortOrder() != SAMFileHeader.SortOrder.coordinate) { throw new SAMException(String.format( - "Input must be coordinate sorted (found %s) to create an index.", - samFileHeader.getSortOrder())); + "Input must be coordinate sorted (found %s) to create an index.", samFileHeader.getSortOrder())); } final CRAMCRAIIndexer indexer = new CRAMCRAIIndexer(craiStream, samFileHeader); final CRAMVersion cramVersion = cramHeader.getCRAMVersion(); @@ -141,11 +134,9 @@ public static CRAIIndex readIndex(final InputStream is) { final String line = scanner.nextLine(); craiIndex.addEntry(new CRAIEntry(line)); } - } - catch (IOException e) { + } catch (IOException e) { throw new RuntimeIOException("Error reading CRAI index from output stream"); - } - finally { + } finally { if (null != scanner) { scanner.close(); } @@ -153,5 +144,4 @@ public static CRAIIndex readIndex(final InputStream is) { return craiIndex; } - -} \ No newline at end of file +} diff --git a/src/main/java/htsjdk/samtools/CRAMContainerStreamWriter.java b/src/main/java/htsjdk/samtools/CRAMContainerStreamWriter.java index 85d1f0f8c7..85db82e02a 100644 --- a/src/main/java/htsjdk/samtools/CRAMContainerStreamWriter.java +++ b/src/main/java/htsjdk/samtools/CRAMContainerStreamWriter.java @@ -6,7 +6,6 @@ import htsjdk.samtools.cram.ref.CRAMReferenceSource; import htsjdk.samtools.cram.structure.*; import htsjdk.samtools.util.RuntimeIOException; - import java.io.IOException; import java.io.OutputStream; @@ -39,13 +38,14 @@ public CRAMContainerStreamWriter( final CRAMReferenceSource source, final SAMFileHeader samFileHeader, final String outputIdentifier) { - this(recordOutputStream, + this( + recordOutputStream, source, samFileHeader, outputIdentifier, - indexOutputStream == null ? - null : - new CRAMBAIIndexer(indexOutputStream, samFileHeader)); // default to BAI index + indexOutputStream == null + ? null + : new CRAMBAIIndexer(indexOutputStream, samFileHeader)); // default to BAI index } /** @@ -111,7 +111,8 @@ public void writeAlignment(final SAMRecord alignment) { public void writeHeader(final SAMFileHeader requestedSAMFileHeader) { final CramHeader cramHeader = new CramHeader(cramVersion, outputStreamIdentifier); streamOffset = CramIO.writeCramHeader(cramHeader, outputStream); - streamOffset += Container.writeSAMFileHeaderContainer(cramHeader.getCRAMVersion(), requestedSAMFileHeader, outputStream); + streamOffset += Container.writeSAMFileHeaderContainer( + cramHeader.getCRAMVersion(), requestedSAMFileHeader, outputStream); } /** @@ -150,8 +151,7 @@ protected void writeContainer(final Container container) { if (cramIndexer != null) { // using silent validation here because the reads have been through validation already or // they have been generated somehow through the htsjdk - cramIndexer.processContainer(container, ValidationStringency.SILENT); + cramIndexer.processContainer(container, ValidationStringency.SILENT); } } - } diff --git a/src/main/java/htsjdk/samtools/CRAMFileReader.java b/src/main/java/htsjdk/samtools/CRAMFileReader.java index 126b4b0829..730aa3f504 100644 --- a/src/main/java/htsjdk/samtools/CRAMFileReader.java +++ b/src/main/java/htsjdk/samtools/CRAMFileReader.java @@ -23,7 +23,6 @@ import htsjdk.samtools.seekablestream.SeekableStream; import htsjdk.samtools.util.*; import htsjdk.utils.ValidationUtils; - import java.io.*; import java.util.ArrayList; import java.util.Arrays; @@ -48,7 +47,7 @@ public class CRAMFileReader extends SamReader.ReaderImplementation implements Sa private ValidationStringency validationStringency; - private final static Log log = Log.getInstance(CRAMFileReader.class); + private static final Log log = Log.getInstance(CRAMFileReader.class); /** * Create a CRAMFileReader from either a file or input stream using the reference source returned by @@ -76,11 +75,10 @@ public CRAMFileReader(final File cramFile, final InputStream inputStream) { * @throws IllegalArgumentException if the {@code cramFile} and the {@code inputStream} are both null * or if the {@code CRAMReferenceSource} is null */ - public CRAMFileReader(final File cramFile, - final InputStream inputStream, - final CRAMReferenceSource referenceSource) { - ValidationUtils.validateArg(cramFile != null || inputStream != null, - "Either file or input stream is required."); + public CRAMFileReader( + final File cramFile, final InputStream inputStream, final CRAMReferenceSource referenceSource) { + ValidationUtils.validateArg( + cramFile != null || inputStream != null, "Either file or input stream is required."); this.cramFile = cramFile; this.inputStream = new BufferedInputStream(inputStream); @@ -101,10 +99,8 @@ public CRAMFileReader(final File cramFile, * reference sequences. May not be null. * @throws IllegalArgumentException if the {@code cramFile} or the {@code CRAMReferenceSource} is null */ - public CRAMFileReader(final File cramFile, - final File indexFile, - final CRAMReferenceSource referenceSource) { - ValidationUtils.nonNull(cramFile,"File is required."); + public CRAMFileReader(final File cramFile, final File indexFile, final CRAMReferenceSource referenceSource) { + ValidationUtils.nonNull(cramFile, "File is required."); this.cramFile = cramFile; mIndexFile = findIndexForFile(indexFile, cramFile); @@ -122,7 +118,7 @@ public CRAMFileReader(final File cramFile, * @throws IllegalArgumentException if the {@code cramFile} or the {@code CRAMReferenceSource} is null */ public CRAMFileReader(final File cramFile, final CRAMReferenceSource referenceSource) { - ValidationUtils.nonNull(cramFile,"File is required."); + ValidationUtils.nonNull(cramFile, "File is required."); this.cramFile = cramFile; this.referenceSource = referenceSource; @@ -143,10 +139,12 @@ public CRAMFileReader(final File cramFile, final CRAMReferenceSource referenceSo * * @throws IllegalArgumentException if the {@code inputStream} or the {@code CRAMReferenceSource} is null */ - public CRAMFileReader(final InputStream inputStream, - final SeekableStream indexInputStream, - final CRAMReferenceSource referenceSource, - final ValidationStringency validationStringency) throws IOException { + public CRAMFileReader( + final InputStream inputStream, + final SeekableStream indexInputStream, + final CRAMReferenceSource referenceSource, + final ValidationStringency validationStringency) + throws IOException { ValidationUtils.nonNull(inputStream, "Input stream can not be null for CRAM reader"); this.referenceSource = referenceSource; initWithStreams(inputStream, indexInputStream, validationStringency); @@ -164,11 +162,17 @@ public CRAMFileReader(final InputStream inputStream, * * @throws IllegalArgumentException if the {@code inputStream} or the {@code CRAMReferenceSource} is null */ - public CRAMFileReader(final InputStream stream, - final File indexFile, - final CRAMReferenceSource referenceSource, - final ValidationStringency validationStringency) throws IOException { - this(stream, indexFile == null ? null : new SeekableFileStream(indexFile), referenceSource, validationStringency); + public CRAMFileReader( + final InputStream stream, + final File indexFile, + final CRAMReferenceSource referenceSource, + final ValidationStringency validationStringency) + throws IOException { + this( + stream, + indexFile == null ? null : new SeekableFileStream(indexFile), + referenceSource, + validationStringency); } /** @@ -183,8 +187,12 @@ public CRAMFileReader(final InputStream stream, * * @throws IllegalArgumentException if the {@code cramFile} or the {@code CRAMReferenceSource} is null */ - public CRAMFileReader(final File cramFile, final File indexFile, final CRAMReferenceSource referenceSource, - final ValidationStringency validationStringency) throws IOException { + public CRAMFileReader( + final File cramFile, + final File indexFile, + final CRAMReferenceSource referenceSource, + final ValidationStringency validationStringency) + throws IOException { ValidationUtils.nonNull(cramFile, "Input file can not be null for CRAM reader"); this.cramFile = cramFile; @@ -194,17 +202,21 @@ public CRAMFileReader(final File cramFile, final File indexFile, final CRAMRefer initWithStreams(new BufferedInputStream(new FileInputStream(cramFile)), indexStream, validationStringency); } - private void initWithStreams(final InputStream inputStream, final SeekableStream indexInputStream, - final ValidationStringency validationStringency) throws IOException { + private void initWithStreams( + final InputStream inputStream, + final SeekableStream indexInputStream, + final ValidationStringency validationStringency) + throws IOException { this.inputStream = inputStream; this.validationStringency = validationStringency; iterator = new CRAMIterator(inputStream, referenceSource, validationStringency); if (indexInputStream != null) { - SeekableStream baiStream = SamIndexes.asBaiSeekableStreamOrNull(indexInputStream, iterator.getSAMFileHeader().getSequenceDictionary()); - if (null != baiStream) { - mIndex = new CachingBAMFileIndex(baiStream, iterator.getSAMFileHeader().getSequenceDictionary()); - } - else { + SeekableStream baiStream = SamIndexes.asBaiSeekableStreamOrNull( + indexInputStream, iterator.getSAMFileHeader().getSequenceDictionary()); + if (null != baiStream) { + mIndex = new CachingBAMFileIndex( + baiStream, iterator.getSAMFileHeader().getSequenceDictionary()); + } else { throw new IllegalArgumentException("CRAM index must be a BAI or CRAI stream"); } } @@ -213,8 +225,8 @@ private void initWithStreams(final InputStream inputStream, final SeekableStream private File findIndexForFile(File indexFile, final File cramFile) { indexFile = indexFile == null ? SamFiles.findIndex(cramFile) : indexFile; if (indexFile != null && indexFile.lastModified() < cramFile.lastModified()) { - log.warn("CRAM index file " + indexFile.getAbsolutePath() + - " is older than CRAM " + cramFile.getAbsolutePath()); + log.warn("CRAM index file " + indexFile.getAbsolutePath() + " is older than CRAM " + + cramFile.getAbsolutePath()); } return indexFile; } @@ -237,8 +249,7 @@ void enableCrcChecking(final boolean enabled) { } @Override - void setSAMRecordFactory(final SAMRecordFactory factory) { - } + void setSAMRecordFactory(final SAMRecordFactory factory) {} @Override public boolean hasIndex() { @@ -253,9 +264,9 @@ public BAMIndex getIndex() { if (mIndex == null) { final SAMSequenceDictionary dictionary = getFileHeader().getSequenceDictionary(); if (mIndexFile.getName().endsWith(FileExtensions.BAI_INDEX)) { - mIndex = mEnableIndexCaching ? - new CachingBAMFileIndex(mIndexFile, dictionary, mEnableIndexMemoryMapping) : - new DiskBasedBAMFileIndex(mIndexFile, dictionary, mEnableIndexMemoryMapping); + mIndex = mEnableIndexCaching + ? new CachingBAMFileIndex(mIndexFile, dictionary, mEnableIndexMemoryMapping) + : new DiskBasedBAMFileIndex(mIndexFile, dictionary, mEnableIndexMemoryMapping); return mIndex; } @@ -270,18 +281,22 @@ public BAMIndex getIndex() { throw new RuntimeException(e); } - mIndex = mEnableIndexCaching ? - new CachingBAMFileIndex(baiStream, getFileHeader().getSequenceDictionary()) : - new DiskBasedBAMFileIndex(baiStream, getFileHeader().getSequenceDictionary()); + mIndex = mEnableIndexCaching + ? new CachingBAMFileIndex(baiStream, getFileHeader().getSequenceDictionary()) + : new DiskBasedBAMFileIndex(baiStream, getFileHeader().getSequenceDictionary()); } return mIndex; } @Override - public boolean hasBrowseableIndex() { return false; } + public boolean hasBrowseableIndex() { + return false; + } @Override - public BrowseableBAMIndex getBrowseableIndex() { return null; } + public BrowseableBAMIndex getBrowseableIndex() { + return null; + } @Override public SAMRecordIterator iterator(final SAMFileSpan fileSpan) { @@ -297,7 +312,9 @@ public SAMRecordIterator iterator(final SAMFileSpan fileSpan) { } @Override - public SAMFileHeader getFileHeader() { return iterator.getSAMFileHeader(); } + public SAMFileHeader getFileHeader() { + return iterator.getSAMFileHeader(); + } @Override public SAMRecordIterator getIterator() { @@ -306,7 +323,8 @@ public SAMRecordIterator getIterator() { } try { if (cramFile != null) { - iterator = new CRAMIterator(new BufferedInputStream(new FileInputStream(cramFile)), referenceSource, validationStringency); + iterator = new CRAMIterator( + new BufferedInputStream(new FileInputStream(cramFile)), referenceSource, validationStringency); } else { iterator = new CRAMIterator(inputStream, referenceSource, validationStringency); } @@ -348,8 +366,7 @@ public void remove() { } @Override - public void close() { - } + public void close() {} @Override public SAMRecordIterator assertSorted(final SortOrder sortOrder) { @@ -358,8 +375,7 @@ public SAMRecordIterator assertSorted(final SortOrder sortOrder) { }; @Override - public CloseableIterator queryAlignmentStart(final String sequence, - final int start) { + public CloseableIterator queryAlignmentStart(final String sequence, final int start) { final SAMFileHeader fileHeader = getFileHeader(); final int referenceIndex = fileHeader.getSequenceIndex(sequence); // alignment start requires a filtering iterator to ensure that records in the @@ -381,7 +397,8 @@ public CloseableIterator queryUnmapped() { } boolean atAlignments; do { - atAlignments = iterator.advanceToAlignmentInContainer(SAMRecord.NO_ALIGNMENT_REFERENCE_INDEX, SAMRecord.NO_ALIGNMENT_START); + atAlignments = iterator.advanceToAlignmentInContainer( + SAMRecord.NO_ALIGNMENT_REFERENCE_INDEX, SAMRecord.NO_ALIGNMENT_START); } while (!atAlignments && iterator.hasNext()); } catch (final IOException e) { throw new RuntimeEOFException(e); @@ -429,19 +446,29 @@ public DeferredCloseSeekableStream(final SeekableStream delegateStream) { } } - public SeekableStream getDelegate() { return delegateStream; } + public SeekableStream getDelegate() { + return delegateStream; + } @Override - public long length() { return delegateStream.length(); } + public long length() { + return delegateStream.length(); + } @Override - public long position() throws IOException { return delegateStream.position(); } + public long position() throws IOException { + return delegateStream.position(); + } @Override - public void seek(long position) throws IOException { delegateStream.seek(position); } + public void seek(long position) throws IOException { + delegateStream.seek(position); + } @Override - public int read() throws IOException { return delegateStream.read(); } + public int read() throws IOException { + return delegateStream.read(); + } @Override public int read(byte[] buffer, int offset, int length) throws IOException { @@ -455,10 +482,14 @@ public void close() throws IOException { } @Override - public boolean eof() throws IOException { return delegateStream.eof(); } + public boolean eof() throws IOException { + return delegateStream.eof(); + } @Override - public String getSource() { return delegateStream.getSource(); } + public String getSource() { + return delegateStream.getSource(); + } } @Override @@ -486,8 +517,7 @@ public ValidationStringency getValidationStringency() { } @Override - public CloseableIterator query(final QueryInterval[] intervals, - final boolean contained) { + public CloseableIterator query(final QueryInterval[] intervals, final boolean contained) { return new CRAMIntervalIterator(intervals, contained); } @@ -511,16 +541,16 @@ void enableFileSource(final SamReader reader, final boolean enabled) { * @param filePointers file pointer pairs corresponding to chunk boundaries for the * intervals */ - public CloseableIterator createIndexIterator(final QueryInterval[] intervals, - final boolean contained, - final long[] filePointers) { + public CloseableIterator createIndexIterator( + final QueryInterval[] intervals, final boolean contained, final long[] filePointers) { return new CRAMIntervalIterator(intervals, contained, filePointers); } // convert queries -> merged BAMFileSpan -> coordinate array private static long[] coordinatesFromQueryIntervals(BAMIndex index, QueryInterval[] queries) { ArrayList spanList = new ArrayList<>(1); - Arrays.asList(queries).forEach(qi -> spanList.add(index.getSpanOverlapping(qi.referenceIndex, qi.start, qi.end))); + Arrays.asList(queries) + .forEach(qi -> spanList.add(index.getSpanOverlapping(qi.referenceIndex, qi.start, qi.end))); BAMFileSpan spanArray[] = new BAMFileSpan[spanList.size()]; for (int i = 0; i < spanList.size(); i++) { spanArray[i] = spanList.get(i); @@ -561,8 +591,7 @@ protected void initializeIterator(final QueryInterval[] queryIntervals, final lo referenceSource, validationStringency, queryIntervals, - coordinates - ); + coordinates); getNextRecord(); // advance to the first record that matches the filter criteria } } @@ -630,7 +659,7 @@ private class CRAMAlignmentStartIterator extends CRAMIntervalIteratorBase { final BAMStartingAtIteratorFilter startingAtIteratorFilter; public CRAMAlignmentStartIterator(final int referenceIndex, final int start) { - super(new QueryInterval[]{new QueryInterval(referenceIndex, start, -1)}, true); + super(new QueryInterval[] {new QueryInterval(referenceIndex, start, -1)}, true); startingAtIteratorFilter = new BAMStartingAtIteratorFilter(referenceIndex, start); initializeIterator(intervals, coordinatesFromQueryIntervals(getIndex(), intervals)); } diff --git a/src/main/java/htsjdk/samtools/CRAMFileWriter.java b/src/main/java/htsjdk/samtools/CRAMFileWriter.java index 15c5c20a84..5342a377d2 100644 --- a/src/main/java/htsjdk/samtools/CRAMFileWriter.java +++ b/src/main/java/htsjdk/samtools/CRAMFileWriter.java @@ -19,7 +19,6 @@ import htsjdk.samtools.cram.structure.CRAMEncodingStrategy; import htsjdk.samtools.util.BufferedLineReader; import htsjdk.samtools.util.Log; - import java.io.OutputStream; public class CRAMFileWriter extends SAMFileWriterImpl { @@ -44,8 +43,7 @@ public CRAMFileWriter( final OutputStream outputStream, final CRAMReferenceSource referenceSource, final SAMFileHeader samFileHeader, - final String fileName) - { + final String fileName) { this(outputStream, null, referenceSource, samFileHeader, fileName); // defaults to presorted == true } @@ -66,8 +64,7 @@ public CRAMFileWriter( final OutputStream indexOS, final CRAMReferenceSource referenceSource, final SAMFileHeader samFileHeader, - final String fileName) - { + final String fileName) { this(outputStream, indexOS, true, referenceSource, samFileHeader, fileName); // defaults to presorted==true } @@ -83,24 +80,29 @@ public CRAMFileWriter( * * @throws IllegalArgumentException if the {@code outputStream}, {@code referenceSource} or {@code samFileHeader} are null */ - public CRAMFileWriter(final OutputStream outputStream, final OutputStream indexOS, final boolean presorted, - final CRAMReferenceSource referenceSource, final SAMFileHeader samFileHeader, final String fileName) { - this( new CRAMEncodingStrategy(), outputStream, indexOS, presorted, referenceSource, samFileHeader, fileName); + public CRAMFileWriter( + final OutputStream outputStream, + final OutputStream indexOS, + final boolean presorted, + final CRAMReferenceSource referenceSource, + final SAMFileHeader samFileHeader, + final String fileName) { + this(new CRAMEncodingStrategy(), outputStream, indexOS, presorted, referenceSource, samFileHeader, fileName); } /** - * Create a CRAMFileWriter and optional index on output streams. - * - * @param encodingStrategy encoding strategy to use when writing - * @param outputStream where to write the output. Can not be null. - * @param indexOS where to write the output index. Can be null if no index is required. - * @param presorted if true records written to this writer must already be sorted in the order specified by the header - * @param referenceSource reference source - * @param samFileHeader {@link SAMFileHeader} to be used. Can not be null. Sort order is determined by the sortOrder property of this arg. - * @param fileName used for display in error message display - * - * @throws IllegalArgumentException if the {@code outputStream}, {@code referenceSource} or {@code samFileHeader} are null - */ + * Create a CRAMFileWriter and optional index on output streams. + * + * @param encodingStrategy encoding strategy to use when writing + * @param outputStream where to write the output. Can not be null. + * @param indexOS where to write the output index. Can be null if no index is required. + * @param presorted if true records written to this writer must already be sorted in the order specified by the header + * @param referenceSource reference source + * @param samFileHeader {@link SAMFileHeader} to be used. Can not be null. Sort order is determined by the sortOrder property of this arg. + * @param fileName used for display in error message display + * + * @throws IllegalArgumentException if the {@code outputStream}, {@code referenceSource} or {@code samFileHeader} are null + */ public CRAMFileWriter( final CRAMEncodingStrategy encodingStrategy, final OutputStream outputStream, @@ -142,7 +144,8 @@ protected void writeAlignment(final SAMRecord alignment) { @Override protected void writeHeader(final String textHeader) { - writeHeader(new SAMTextHeaderCodec().decode(BufferedLineReader.fromString(textHeader),fileName != null ? fileName : null)); + writeHeader(new SAMTextHeaderCodec() + .decode(BufferedLineReader.fromString(textHeader), fileName != null ? fileName : null)); } @Override @@ -164,5 +167,4 @@ protected void finish() { protected String getFilename() { return fileName; } - } diff --git a/src/main/java/htsjdk/samtools/CRAMIndexer.java b/src/main/java/htsjdk/samtools/CRAMIndexer.java index 5e332a87ea..f58a2d8ce8 100644 --- a/src/main/java/htsjdk/samtools/CRAMIndexer.java +++ b/src/main/java/htsjdk/samtools/CRAMIndexer.java @@ -1,6 +1,5 @@ package htsjdk.samtools; -import htsjdk.samtools.cram.structure.CompressorCache; import htsjdk.samtools.cram.structure.Container; /** diff --git a/src/main/java/htsjdk/samtools/CRAMIterator.java b/src/main/java/htsjdk/samtools/CRAMIterator.java index 730c52b16b..2dc693c879 100644 --- a/src/main/java/htsjdk/samtools/CRAMIterator.java +++ b/src/main/java/htsjdk/samtools/CRAMIterator.java @@ -23,13 +23,11 @@ import htsjdk.samtools.cram.ref.CRAMReferenceSource; import htsjdk.samtools.cram.structure.*; import htsjdk.samtools.seekablestream.SeekableStream; - +import htsjdk.samtools.util.RuntimeIOException; import java.io.Closeable; import java.io.InputStream; import java.util.*; -import htsjdk.samtools.util.RuntimeIOException; - public class CRAMIterator implements SAMRecordIterator, Closeable { private final CountingInputStream countingInputStream; private final CramContainerIterator containerIterator; @@ -54,11 +52,13 @@ public class CRAMIterator implements SAMRecordIterator, Closeable { * (for identification by the validator which records are invalid) */ private long samRecordIndex; + private Iterator samRecordIterator = Collections.EMPTY_LIST.iterator(); - public CRAMIterator(final InputStream inputStream, - final CRAMReferenceSource referenceSource, - final ValidationStringency validationStringency) { + public CRAMIterator( + final InputStream inputStream, + final CRAMReferenceSource referenceSource, + final ValidationStringency validationStringency) { this.countingInputStream = new CountingInputStream(inputStream); this.containerIterator = new CramContainerIterator(this.countingInputStream); @@ -71,11 +71,12 @@ public CRAMIterator(final InputStream inputStream, this.queryIntervals = null; } - public CRAMIterator(final SeekableStream seekableStream, - final CRAMReferenceSource referenceSource, - final ValidationStringency validationStringency, - final QueryInterval[] queryIntervals, - final long[] coordinates) { + public CRAMIterator( + final SeekableStream seekableStream, + final CRAMReferenceSource referenceSource, + final ValidationStringency validationStringency, + final QueryInterval[] queryIntervals, + final long[] coordinates) { this.countingInputStream = new CountingInputStream(seekableStream); this.containerIterator = CramSpanContainerIterator.fromFileSpan(seekableStream, coordinates); @@ -110,10 +111,7 @@ private BAMIteratorFilter.FilteringIteratorState nextContainer() { if (containerMatchesQuery(container)) { samRecords = container.getSAMRecords( - validationStringency, - cramReferenceRegion, - compressorCache, - getSAMFileHeader()); + validationStringency, cramReferenceRegion, compressorCache, getSAMFileHeader()); samRecordIterator = samRecords.iterator(); // A container may match the query but produce no records (e.g. a container with // only a compression header and no slices). Skip to the next container in that case. @@ -132,21 +130,25 @@ private boolean containerMatchesQuery(final Container container) { // binary search our query intervals to see if the alignment span of this container // overlaps any query - it doesn't matter which one, we only care whether or not there is a match final AlignmentContext alignmentContext = container.getAlignmentContext(); - return (!alignmentContext.getReferenceContext().isMappedSingleRef() || - Arrays.binarySearch( - queryIntervals, - new QueryInterval( - alignmentContext.getReferenceContext().getReferenceContextID(), - alignmentContext.getAlignmentStart(), - alignmentContext.getAlignmentStart() + alignmentContext.getAlignmentSpan() - 1 - ), - overlapsContainerSpan) >= 0); + return (!alignmentContext.getReferenceContext().isMappedSingleRef() + || Arrays.binarySearch( + queryIntervals, + new QueryInterval( + alignmentContext + .getReferenceContext() + .getReferenceContextID(), + alignmentContext.getAlignmentStart(), + alignmentContext.getAlignmentStart() + + alignmentContext.getAlignmentSpan() + - 1), + overlapsContainerSpan) + >= 0); } } - //TODO: this should filter at the slice level! - //we don't actually care which QueryInterval overlaps with the container; we just want to know if there is one... - private final static Comparator overlapsContainerSpan = (queryInterval, containerInterval) -> { + // TODO: this should filter at the slice level! + // we don't actually care which QueryInterval overlaps with the container; we just want to know if there is one... + private static final Comparator overlapsContainerSpan = (queryInterval, containerInterval) -> { int comp = queryInterval.referenceIndex - containerInterval.referenceIndex; if (comp != 0) { return comp; @@ -154,9 +156,7 @@ private boolean containerMatchesQuery(final Container container) { if (queryInterval.end <= 0) { // our query interval specifies a symbolic end, so call it a match if the container span // overlaps the start of the queryInterval - return containerInterval.end <= queryInterval.start ? - -1 : - 0; + return containerInterval.end <= queryInterval.start ? -1 : 0; } else if (containerInterval.overlaps(queryInterval)) { return 0; // there is overlap so call it a match } @@ -169,7 +169,7 @@ private boolean containerMatchesQuery(final Container container) { * @param refIndex reference sequence index * @param pos alignment start to skip to */ - //TODO: this should first select the correct slice so we don't decode all slices unnecessarily + // TODO: this should first select the correct slice so we don't decode all slices unnecessarily public boolean advanceToAlignmentInContainer(final int refIndex, final int pos) { if (!hasNext()) return false; int i = 0; @@ -204,7 +204,7 @@ public boolean hasNext() { if (!samRecordIterator.hasNext()) { BAMIteratorFilter.FilteringIteratorState nextContainerPasses = BAMIteratorFilter.FilteringIteratorState.CONTINUE_ITERATION; - while (nextContainerPasses == BAMIteratorFilter.FilteringIteratorState.CONTINUE_ITERATION){ + while (nextContainerPasses == BAMIteratorFilter.FilteringIteratorState.CONTINUE_ITERATION) { nextContainerPasses = nextContainer(); } return nextContainerPasses == BAMIteratorFilter.FilteringIteratorState.MATCHES_FILTER; @@ -238,7 +238,8 @@ public void close() { if (countingInputStream != null) { countingInputStream.close(); } - } catch (final RuntimeIOException e) { } + } catch (final RuntimeIOException e) { + } } public long getFirstContainerOffset() { @@ -273,5 +274,4 @@ public void setFileSource(final SamReader mReader) { public SAMFileHeader getSAMFileHeader() { return samFileHeader; } - } diff --git a/src/main/java/htsjdk/samtools/CSIIndex.java b/src/main/java/htsjdk/samtools/CSIIndex.java index 706eb450f8..4e34900e54 100644 --- a/src/main/java/htsjdk/samtools/CSIIndex.java +++ b/src/main/java/htsjdk/samtools/CSIIndex.java @@ -3,7 +3,6 @@ import htsjdk.samtools.seekablestream.SeekablePathStream; import htsjdk.samtools.seekablestream.SeekableStream; import htsjdk.samtools.util.RuntimeIOException; - import java.io.File; import java.io.IOException; import java.nio.file.Path; @@ -23,6 +22,7 @@ public class CSIIndex extends AbstractBAMFileIndex implements BrowseableBAMIndex * the superclass constructor. */ private int binDepth; + private int minShift; private int maxBins; private int maxSpan; @@ -33,7 +33,6 @@ public class CSIIndex extends AbstractBAMFileIndex implements BrowseableBAMIndex /** * Constructors */ - public CSIIndex(final SeekableStream stream, final SAMSequenceDictionary dictionary) { this(IndexFileBufferFactory.getBuffer(stream), stream.getSource(), dictionary); } @@ -46,7 +45,8 @@ public CSIIndex(final File file, boolean enableMemoryMapping, final SAMSequenceD this(IndexFileBufferFactory.getBuffer(file, enableMemoryMapping), file.getName(), dictionary); } - private CSIIndex(final IndexFileBuffer indexFileBuffer, final String source, final SAMSequenceDictionary dictionary) { + private CSIIndex( + final IndexFileBuffer indexFileBuffer, final String source, final SAMSequenceDictionary dictionary) { super(indexFileBuffer, source, dictionary); } @@ -62,7 +62,9 @@ public int getBinDepth() { return binDepth; } - private void setBinDepth(int binDepth) { this.binDepth = binDepth; } + private void setBinDepth(int binDepth) { + this.binDepth = binDepth; + } /** * 2^(min shift) is the smallest width of a bin @@ -79,24 +81,34 @@ public int getMaxBins() { return maxBins; } - private void setMaxBins(int binDepth) { this.maxBins = ((1<<3*binDepth) - 1)/7; } + private void setMaxBins(int binDepth) { + this.maxBins = ((1 << 3 * binDepth) - 1) / 7; + } public int getMaxSpan() { return maxSpan; } private void setMaxSpan(int binDepth, int minShift) { - this.maxSpan = 1<<(minShift + 3*(binDepth - 1)); + this.maxSpan = 1 << (minShift + 3 * (binDepth - 1)); } - public byte[] getAuxData() { return auxData; } + public byte[] getAuxData() { + return auxData; + } - private void setAuxData(byte[] auxData) { this.auxData = auxData; } + private void setAuxData(byte[] auxData) { + this.auxData = auxData; + } @Override - public int getNumberOfReferences() { return nReferences; } + public int getNumberOfReferences() { + return nReferences; + } - private void setNumberOfReferences(int nReferences) { this.nReferences = nReferences; } + private void setNumberOfReferences(int nReferences) { + this.nReferences = nReferences; + } /** * Computes the number of bins on the given level. @@ -106,9 +118,10 @@ private void setMaxSpan(int binDepth, int minShift) { @Override public int getLevelSize(final int levelNumber) { if (levelNumber >= getBinDepth()) { - throw new SAMException("Level number (" + levelNumber + ") is greater than or equal to maximum (" + getBinDepth() + ")."); + throw new SAMException( + "Level number (" + levelNumber + ") is greater than or equal to maximum (" + getBinDepth() + ")."); } - return 1<<3*(levelNumber); + return 1 << 3 * (levelNumber); } /** @@ -117,46 +130,47 @@ public int getLevelSize(final int levelNumber) { */ public int getFirstBinInLevelForCSI(final int levelNumber) { if (levelNumber >= getBinDepth()) { - throw new SAMException("Level number (" + levelNumber + ") is greater than or equal to maximum (" + getBinDepth() + ")."); + throw new SAMException( + "Level number (" + levelNumber + ") is greater than or equal to maximum (" + getBinDepth() + ")."); } - return ((1<<3*levelNumber) - 1)/7; + return ((1 << 3 * levelNumber) - 1) / 7; } @Override public int getLevelForBin(Bin bin) { - if(bin == null || bin.getBinNumber() > getMaxBins()) { - throw new SAMException("Tried to get level for invalid bin: " + bin); + if (bin == null || bin.getBinNumber() > getMaxBins()) { + throw new SAMException("Tried to get level for invalid bin: " + bin); } - for (int i = getBinDepth()-1; i > -1 ; i--) { - if (bin.getBinNumber() >= getFirstBinInLevelForCSI(i)) { - return i; - } + for (int i = getBinDepth() - 1; i > -1; i--) { + if (bin.getBinNumber() >= getFirstBinInLevelForCSI(i)) { + return i; + } } throw new SAMException("Unable to find correct level for bin: " + bin); } @Override public int getFirstLocusInBin(Bin bin) { - if(bin == null || bin.getBinNumber() > getMaxBins()) { + if (bin == null || bin.getBinNumber() > getMaxBins()) { throw new SAMException("Tried to get first locus for invalid bin: " + bin); } int level = getLevelForBin(bin); int firstBinOnLevel = getFirstBinInLevelForCSI(level); int levelSize = getLevelSize(level); - return (bin.getBinNumber() - firstBinOnLevel)*(getMaxSpan()/levelSize) + 1; + return (bin.getBinNumber() - firstBinOnLevel) * (getMaxSpan() / levelSize) + 1; } @Override public int getLastLocusInBin(Bin bin) { - if(bin == null || bin.getBinNumber() > getMaxBins()) { + if (bin == null || bin.getBinNumber() > getMaxBins()) { throw new SAMException("Tried to get last locus for invalid bin: " + bin); } int level = getLevelForBin(bin); int firstBinOnLevel = getFirstBinInLevelForCSI(level); int levelSize = getLevelSize(level); - return (bin.getBinNumber() - firstBinOnLevel + 1)*(getMaxSpan()/levelSize); + return (bin.getBinNumber() - firstBinOnLevel + 1) * (getMaxSpan() / levelSize); } @Override @@ -165,7 +179,7 @@ public BinList getBinsOverlapping(int referenceIndex, int startPos, int endPos) if (regionBins == null) { return null; } - return new BinList(referenceIndex,regionBins); + return new BinList(referenceIndex, regionBins); } @Override @@ -175,28 +189,27 @@ public BAMFileSpan getSpanOverlapping(int referenceIndex, int startPos, int endP long minimumOffset = 0L; Bin targetBin; - if(queryResults == null) { + if (queryResults == null) { return null; } /** Compute 'minimumOffset' by searching the lowest level bin containing 'startPos'. - If the computed bin is not in the index, try the next bin to the left, belonging - to the same parent. If it is the first sibling bin, try the parent bin. + * If the computed bin is not in the index, try the next bin to the left, belonging + * to the same parent. If it is the first sibling bin, try the parent bin. */ - do { int firstBinNumber; targetBin = queryResults.getBins().getBin(initialBinNumber); if (targetBin != null) { break; } - firstBinNumber = (getParentBinNumber(initialBinNumber)<<3) + 1; + firstBinNumber = (getParentBinNumber(initialBinNumber) << 3) + 1; if (initialBinNumber > firstBinNumber) { initialBinNumber--; } else { initialBinNumber = getParentBinNumber(initialBinNumber); } - } while(initialBinNumber != 0); + } while (initialBinNumber != 0); if (initialBinNumber == 0) { targetBin = queryResults.getBins().getBin(initialBinNumber); @@ -207,7 +220,7 @@ public BAMFileSpan getSpanOverlapping(int referenceIndex, int startPos, int endP } List chunkList = new ArrayList(); - for(final Chunk chunk: queryResults.getAllChunks()) { + for (final Chunk chunk : queryResults.getAllChunks()) { chunkList.add(chunk.clone()); } @@ -217,42 +230,41 @@ public BAMFileSpan getSpanOverlapping(int referenceIndex, int startPos, int endP @Override public BAMFileSpan getSpanOverlapping(final Bin bin) { - if(bin == null) { + if (bin == null) { return null; } final int referenceSequence = bin.getReferenceSequence(); final BAMIndexContent queryResults = getQueryResults(referenceSequence); - if(queryResults == null) { + if (queryResults == null) { return null; } final int binLevel = getLevelForBin(bin); final int firstLocusInBin = getFirstLocusInBin(bin); - long minimumOffset = bin instanceof BinWithOffset ? ((BinWithOffset)bin).getlOffset() : 0L; + long minimumOffset = bin instanceof BinWithOffset ? ((BinWithOffset) bin).getlOffset() : 0L; // Add the specified bin to the tree if it exists. final List binTree = new ArrayList(); - if(queryResults.containsBin(bin)) { + if (queryResults.containsBin(bin)) { binTree.add(queryResults.getBins().getBin(bin.getBinNumber())); } int currentBinLevel = binLevel; - while(--currentBinLevel >= 0) { + while (--currentBinLevel >= 0) { final int binStart = getFirstBinInLevelForCSI(currentBinLevel); - final int binWidth = getMaxSpan()/getLevelSize(currentBinLevel); - final int parentBinNumber = firstLocusInBin/binWidth + binStart; + final int binWidth = getMaxSpan() / getLevelSize(currentBinLevel); + final int parentBinNumber = firstLocusInBin / binWidth + binStart; final Bin parentBin = queryResults.getBins().getBin(parentBinNumber); - if(parentBin != null && queryResults.containsBin(parentBin)) { + if (parentBin != null && queryResults.containsBin(parentBin)) { binTree.add(parentBin); } } List chunkList = new ArrayList(); - for(final Bin coveringBin: binTree) { - for(final Chunk chunk: coveringBin.getChunkList()) - chunkList.add(chunk.clone()); + for (final Bin coveringBin : binTree) { + for (final Chunk chunk : coveringBin.getChunkList()) chunkList.add(chunk.clone()); } chunkList = Chunk.optimizeChunkList(chunkList, minimumOffset); @@ -291,8 +303,8 @@ protected void verifyIndexMagicNumber(final String sourceName) { final byte[] buffer = new byte[BAMFileConstants.CSI_MINSHIFT_OFFSET]; readBytes(buffer); // magic if (!Arrays.equals(buffer, BAMFileConstants.CSI_INDEX_MAGIC)) { - throw new RuntimeIOException("Invalid file header in BAM CSI index " + sourceName + - ": " + new String(buffer)); + throw new RuntimeIOException( + "Invalid file header in BAM CSI index " + sourceName + ": " + new String(buffer)); } } @@ -310,7 +322,7 @@ private void readAuxDataAndNRef() { if (BAMFileConstants.CSI_AUXDATA_OFFSET != position()) { seek(BAMFileConstants.CSI_AUXDATA_OFFSET); } - //set the aux data length first + // set the aux data length first byte[] auxData = new byte[readInteger()]; // l_aux readBytes(auxData); // aux setAuxData(auxData); @@ -379,11 +391,11 @@ protected BAMIndexContent query(final int referenceSequence, final int startPos, final int binCount = readInteger(); // n_bin boolean metaDataSeen = false; - final Bin[] bins = new BinWithOffset[getMaxBinNumberForReference(referenceSequence) +1]; + final Bin[] bins = new BinWithOffset[getMaxBinNumberForReference(referenceSequence) + 1]; for (int binNumber = 0; binNumber < binCount; binNumber++) { final int indexBin = readInteger(); // bin final long lOffset = readLong(); // l_offset - final int nChunks = readInteger(); // n_chunk + final int nChunks = readInteger(); // n_chunk List chunks; Chunk lastChunk = null; @@ -406,7 +418,8 @@ protected BAMIndexContent query(final int referenceSequence, final int startPos, bins[indexBin] = bin; } - return new BAMIndexContent(referenceSequence, bins, binCount - (metaDataSeen? 1 : 0), new BAMIndexMetaData(metaDataChunks), null); + return new BAMIndexContent( + referenceSequence, bins, binCount - (metaDataSeen ? 1 : 0), new BAMIndexMetaData(metaDataChunks), null); } /** @@ -472,12 +485,13 @@ public BAMIndexContent getQueryResults(final int referenceSequence) { @Override protected void skipToSequence(final int sequenceIndex) { - if(sequenceIndex > getNumberOfReferences()) { - throw new SAMException("Sequence index (" + sequenceIndex + ") is greater than maximum (" + getNumberOfReferences() + ")."); + if (sequenceIndex > getNumberOfReferences()) { + throw new SAMException("Sequence index (" + sequenceIndex + ") is greater than maximum (" + + getNumberOfReferences() + ")."); } - //Use sequence position cache if available - if(sequenceIndexes[sequenceIndex] != -1){ + // Use sequence position cache if available + if (sequenceIndexes[sequenceIndex] != -1) { seek(sequenceIndexes[sequenceIndex]); return; } @@ -497,7 +511,7 @@ protected void skipToSequence(final int sequenceIndex) { } } - //Update sequence position cache + // Update sequence position cache sequenceIndexes[sequenceIndex] = position(); } } diff --git a/src/main/java/htsjdk/samtools/CachingBAMFileIndex.java b/src/main/java/htsjdk/samtools/CachingBAMFileIndex.java index 4a1a264d92..2bffd3f4d3 100644 --- a/src/main/java/htsjdk/samtools/CachingBAMFileIndex.java +++ b/src/main/java/htsjdk/samtools/CachingBAMFileIndex.java @@ -24,7 +24,6 @@ package htsjdk.samtools; import htsjdk.samtools.seekablestream.SeekableStream; - import java.io.File; import java.util.ArrayList; import java.util.BitSet; @@ -34,8 +33,7 @@ * Class for reading BAM file indices, caching each contig as it's loaded and * dropping values when the next contig is loaded. */ -class CachingBAMFileIndex extends AbstractBAMFileIndex implements BrowseableBAMIndex -{ +class CachingBAMFileIndex extends AbstractBAMFileIndex implements BrowseableBAMIndex { // Since null is a valid return value for this index, it's possible to have lastReferenceIndex != null and // lastReference == null, this is effectively caching the return value null private Integer lastReferenceIndex = null; @@ -52,7 +50,8 @@ public CachingBAMFileIndex(final SeekableStream stream, final SAMSequenceDiction super(stream, dictionary); } - public CachingBAMFileIndex(final File file, final SAMSequenceDictionary dictionary, final boolean useMemoryMapping) { + public CachingBAMFileIndex( + final File file, final SAMSequenceDictionary dictionary, final boolean useMemoryMapping) { super(file, dictionary, useMemoryMapping); } @@ -69,8 +68,7 @@ public CachingBAMFileIndex(final File file, final SAMSequenceDictionary dictiona public BAMFileSpan getSpanOverlapping(final int referenceIndex, final int startPos, final int endPos) { final BAMIndexContent queryResults = getQueryResults(referenceIndex); - if(queryResults == null) - return null; + if (queryResults == null) return null; final List chunkList = queryResults.getChunksOverlapping(startPos, endPos); if (chunkList == null) return null; @@ -91,7 +89,7 @@ public BinList getBinsOverlapping(final int referenceIndex, final int startPos, if (regionBins == null) { return null; } - return new BinList(referenceIndex,regionBins); + return new BinList(referenceIndex, regionBins); } /** @@ -101,62 +99,59 @@ public BinList getBinsOverlapping(final int referenceIndex, final int startPos, */ @Override public BAMFileSpan getSpanOverlapping(final Bin bin) { - if(bin == null) - return null; + if (bin == null) return null; final int referenceSequence = bin.getReferenceSequence(); final BAMIndexContent indexQuery = getQueryResults(referenceSequence); - if(indexQuery == null) - return null; + if (indexQuery == null) return null; final int binLevel = getLevelForBin(bin); final int firstLocusInBin = getFirstLocusInBin(bin); // Add the specified bin to the tree if it exists. final List binTree = new ArrayList<>(); - if(indexQuery.containsBin(bin)) - binTree.add(indexQuery.getBins().getBin(bin.getBinNumber())); + if (indexQuery.containsBin(bin)) binTree.add(indexQuery.getBins().getBin(bin.getBinNumber())); int currentBinLevel = binLevel; - while(--currentBinLevel >= 0) { + while (--currentBinLevel >= 0) { final int binStart = getFirstBinInLevel(currentBinLevel); - final int binWidth = getMaxAddressibleGenomicLocation()/getLevelSize(currentBinLevel); - final int binNumber = firstLocusInBin/binWidth + binStart; + final int binWidth = getMaxAddressibleGenomicLocation() / getLevelSize(currentBinLevel); + final int binNumber = firstLocusInBin / binWidth + binStart; final Bin parentBin = indexQuery.getBins().getBin(binNumber); - if(parentBin != null && indexQuery.containsBin(parentBin)) - binTree.add(parentBin); + if (parentBin != null && indexQuery.containsBin(parentBin)) binTree.add(parentBin); } List chunkList = new ArrayList(); - for(final Bin coveringBin: binTree) { - for(final Chunk chunk: coveringBin.getChunkList()) - chunkList.add(chunk.clone()); + for (final Bin coveringBin : binTree) { + for (final Chunk chunk : coveringBin.getChunkList()) chunkList.add(chunk.clone()); } final int start = getFirstLocusInBin(bin); - chunkList = Chunk.optimizeChunkList(chunkList,indexQuery.getLinearIndex().getMinimumOffset(start)); + chunkList = + Chunk.optimizeChunkList(chunkList, indexQuery.getLinearIndex().getMinimumOffset(start)); return new BAMFileSpan(chunkList); } /** * Looks up the cached BAM query results if they're still in the cache and not expired. Otherwise, * retrieves the cache results from disk. - * @param referenceIndex The reference to load. CachingBAMFileIndex only stores index data for entire references. + * @param referenceIndex The reference to load. CachingBAMFileIndex only stores index data for entire references. * @return The index information for this reference or null if no index information is available for the given index. */ @Override protected BAMIndexContent getQueryResults(final int referenceIndex) { // If this query is for the same reference index as the last query, return it. - // This compares a boxed Integer to an int with == which is ok because the Integer will be unboxed to the primitive value - if(lastReferenceIndex!=null && lastReferenceIndex == referenceIndex){ + // This compares a boxed Integer to an int with == which is ok because the Integer will be unboxed to the + // primitive value + if (lastReferenceIndex != null && lastReferenceIndex == referenceIndex) { cacheHits++; return lastReference; } // If not attempt to load it from disk. - final BAMIndexContent queryResults = query(referenceIndex,1,-1); + final BAMIndexContent queryResults = query(referenceIndex, 1, -1); cacheMisses++; lastReferenceIndex = referenceIndex; lastReference = queryResults; diff --git a/src/main/java/htsjdk/samtools/CachingBamFileIndexOptimizedForMerging.java b/src/main/java/htsjdk/samtools/CachingBamFileIndexOptimizedForMerging.java index ae0ae98056..04bb820794 100644 --- a/src/main/java/htsjdk/samtools/CachingBamFileIndexOptimizedForMerging.java +++ b/src/main/java/htsjdk/samtools/CachingBamFileIndexOptimizedForMerging.java @@ -7,28 +7,28 @@ * null BAMIndexContent objects if all bins are empty. */ class CachingBamFileIndexOptimizedForMerging extends CachingBAMFileIndex { - CachingBamFileIndexOptimizedForMerging(SeekableStream stream, SAMSequenceDictionary dictionary) { - super(stream, dictionary); - } + CachingBamFileIndexOptimizedForMerging(SeekableStream stream, SAMSequenceDictionary dictionary) { + super(stream, dictionary); + } - @Override - protected BAMIndexContent query(final int referenceSequence, final int startPos, final int endPos) { - seek(4); + @Override + protected BAMIndexContent query(final int referenceSequence, final int startPos, final int endPos) { + seek(4); - final int sequenceCount = readInteger(); + final int sequenceCount = readInteger(); - if (referenceSequence >= sequenceCount) { - return null; - } + if (referenceSequence >= sequenceCount) { + return null; + } - skipToSequence(referenceSequence); + skipToSequence(referenceSequence); - final int binCount = readInteger(); + final int binCount = readInteger(); - if (binCount == 0) { - return null; - } + if (binCount == 0) { + return null; + } - return super.query(referenceSequence, startPos, endPos); - } + return super.query(referenceSequence, startPos, endPos); + } } diff --git a/src/main/java/htsjdk/samtools/ChainedDownsamplingIterator.java b/src/main/java/htsjdk/samtools/ChainedDownsamplingIterator.java index 4fa3a7d86f..b400091ca2 100644 --- a/src/main/java/htsjdk/samtools/ChainedDownsamplingIterator.java +++ b/src/main/java/htsjdk/samtools/ChainedDownsamplingIterator.java @@ -56,16 +56,16 @@ class ChainedDownsamplingIterator extends HighAccuracyDownsamplingIterator { * Uses an assumed number of reads tested as this is often not known until after the fact. */ private static double adjustProportion(final double p) { - final double ciAdjustment99_9 = 3.3 * Math.sqrt(p/MIN_ACCURATE_INPUT_READS); + final double ciAdjustment99_9 = 3.3 * Math.sqrt(p / MIN_ACCURATE_INPUT_READS); return Math.min(1, p + ciAdjustment99_9); } - /** * Resets statistics before reading from the underlying iterator. */ @Override - protected void readFromUnderlyingIterator(final List recs, final Set names, final int templatesToRead) { + protected void readFromUnderlyingIterator( + final List recs, final Set names, final int templatesToRead) { // Reset the stats on the underlying iterator ((ConstantMemoryDownsamplingIterator) getUnderlyingIterator()).resetStatistics(); @@ -79,7 +79,7 @@ protected int calculateTemplatesToKeep(final int templatesRead, final double ove final ConstantMemoryDownsamplingIterator iter = (ConstantMemoryDownsamplingIterator) getUnderlyingIterator(); final double priorProportion = iter.getAcceptedFraction(); final double p = Math.max(0, Math.min(1, overallProportion / priorProportion)); - final int retval = super.calculateTemplatesToKeep(templatesRead, p); + final int retval = super.calculateTemplatesToKeep(templatesRead, p); // Record all the discarded records to keep the overall statistics accurate, but do it after // the call to super() so it doesn't affect the proportion calculation. diff --git a/src/main/java/htsjdk/samtools/Chunk.java b/src/main/java/htsjdk/samtools/Chunk.java index 8a6d4bf802..cdc919bbd6 100644 --- a/src/main/java/htsjdk/samtools/Chunk.java +++ b/src/main/java/htsjdk/samtools/Chunk.java @@ -1,7 +1,6 @@ package htsjdk.samtools; import htsjdk.samtools.util.BlockCompressedFilePointerUtil; - import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; @@ -17,7 +16,7 @@ * * See the SAM/BAM spec for more details. */ -public class Chunk implements Cloneable, Serializable,Comparable { +public class Chunk implements Cloneable, Serializable, Comparable { private static final long serialVersionUID = 1L; /** @@ -40,7 +39,7 @@ public Chunk(final long start, final long end) { @Override public Chunk clone() { - return new Chunk(mChunkStart,mChunkEnd); + return new Chunk(mChunkStart, mChunkEnd); } public long getChunkStart() { @@ -88,12 +87,11 @@ public boolean equals(final Object o) { */ public boolean overlaps(final Chunk other) { final int comparison = this.compareTo(other); - if(comparison == 0) - return true; + if (comparison == 0) return true; // "sort" the two chunks using the comparator. - final Chunk leftMost = comparison==-1 ? this : other; - final Chunk rightMost = comparison==1 ? this : other; + final Chunk leftMost = comparison == -1 ? this : other; + final Chunk rightMost = comparison == 1 ? this : other; final long leftMostBlockAddress = BlockCompressedFilePointerUtil.getBlockAddress(leftMost.getChunkEnd()); final long rightMostBlockAddress = BlockCompressedFilePointerUtil.getBlockAddress(rightMost.getChunkStart()); @@ -101,15 +99,12 @@ public boolean overlaps(final Chunk other) { // If the left block's address is after the right block's address, compare the two blocks. // If the two blocks are identical, compare the block offsets. // If the right block is after the left block, no overlap is possible. - if(leftMostBlockAddress > rightMostBlockAddress) - return true; - else if(leftMostBlockAddress == rightMostBlockAddress) { + if (leftMostBlockAddress > rightMostBlockAddress) return true; + else if (leftMostBlockAddress == rightMostBlockAddress) { final int leftMostOffset = BlockCompressedFilePointerUtil.getBlockOffset(leftMost.getChunkEnd()); final int rightMostOffset = BlockCompressedFilePointerUtil.getBlockOffset(rightMost.getChunkStart()); return leftMostOffset > rightMostOffset; - } - else - return false; + } else return false; } /** @@ -118,12 +113,17 @@ else if(leftMostBlockAddress == rightMostBlockAddress) { * @return True if the two chunks are adjacent. Returns false if the chunks overlap or are discontinuous. */ public boolean isAdjacentTo(final Chunk other) { - // Simpler implementation would be to == the chunk end of one to the chunk start of the other. Chose this implementation to ensure that all chunk - // comparisons point directly to the - return (BlockCompressedFilePointerUtil.getBlockAddress(this.getChunkEnd()) == BlockCompressedFilePointerUtil.getBlockAddress(other.getChunkStart()) && - BlockCompressedFilePointerUtil.getBlockOffset(this.getChunkEnd()) == BlockCompressedFilePointerUtil.getBlockOffset(other.getChunkStart())) || - (BlockCompressedFilePointerUtil.getBlockAddress(this.getChunkStart()) == BlockCompressedFilePointerUtil.getBlockAddress(other.getChunkEnd()) && - BlockCompressedFilePointerUtil.getBlockOffset(this.getChunkStart()) == BlockCompressedFilePointerUtil.getBlockOffset(other.getChunkEnd())); + // Simpler implementation would be to == the chunk end of one to the chunk start of the other. Chose this + // implementation to ensure that all chunk + // comparisons point directly to the + return (BlockCompressedFilePointerUtil.getBlockAddress(this.getChunkEnd()) + == BlockCompressedFilePointerUtil.getBlockAddress(other.getChunkStart()) + && BlockCompressedFilePointerUtil.getBlockOffset(this.getChunkEnd()) + == BlockCompressedFilePointerUtil.getBlockOffset(other.getChunkStart())) + || (BlockCompressedFilePointerUtil.getBlockAddress(this.getChunkStart()) + == BlockCompressedFilePointerUtil.getBlockAddress(other.getChunkEnd()) + && BlockCompressedFilePointerUtil.getBlockOffset(this.getChunkStart()) + == BlockCompressedFilePointerUtil.getBlockOffset(other.getChunkEnd())); } /** @@ -148,7 +148,8 @@ public int hashCode() { @Override public String toString() { - return String.format("%d:%d-%d:%d",mChunkStart >> 16,mChunkStart & 0xFFFF,mChunkEnd >> 16,mChunkEnd & 0xFFFF); + return String.format( + "%d:%d-%d:%d", mChunkStart >> 16, mChunkStart & 0xFFFF, mChunkEnd >> 16, mChunkEnd & 0xFFFF); } /** @@ -161,7 +162,7 @@ public static List optimizeChunkList(final List chunks, final long final List result = new ArrayList(); for (final Chunk chunk : chunks) { if (chunk.getChunkEnd() <= minimumOffset) { - continue; // linear index optimization + continue; // linear index optimization } if (result.isEmpty()) { result.add(chunk); diff --git a/src/main/java/htsjdk/samtools/Cigar.java b/src/main/java/htsjdk/samtools/Cigar.java index 8fafd639f1..5eb3259cd8 100644 --- a/src/main/java/htsjdk/samtools/Cigar.java +++ b/src/main/java/htsjdk/samtools/Cigar.java @@ -43,8 +43,7 @@ public class Cigar implements Serializable, Iterable { private final List cigarElements = new ArrayList(); - public Cigar() { - } + public Cigar() {} public Cigar(final List cigarElements) { this.cigarElements.addAll(cigarElements); @@ -84,7 +83,8 @@ public int getReferenceLength() { case X: length += element.getLength(); break; - default: break; + default: + break; } } return length; @@ -105,7 +105,8 @@ public int getPaddedReferenceLength() { case P: length += element.getLength(); break; - default: break; + default: + break; } } return length; @@ -124,8 +125,8 @@ public int getReadLength() { public static int getReadLength(final List cigarElements) { int length = 0; for (final CigarElement element : cigarElements) { - if (element.getOperator().consumesReadBases()){ - length += element.getLength(); + if (element.getOperator().consumesReadBases()) { + length += element.getLength(); } } return length; @@ -149,8 +150,11 @@ public List isValid(final String readName, final long record final CigarElement element = cigarElements.get(i); if (element.getLength() == 0) { if (ret == null) ret = new ArrayList(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_CIGAR, - "CIGAR element with zero length", readName, recordNumber)); + ret.add(new SAMValidationError( + SAMValidationError.Type.INVALID_CIGAR, + "CIGAR element with zero length", + readName, + recordNumber)); } // clipping operator can only be at start or end of CIGAR final CigarOperator op = element.getOperator(); @@ -158,8 +162,11 @@ public List isValid(final String readName, final long record if (op == CigarOperator.H) { if (i != 0 && i != cigarElements.size() - 1) { if (ret == null) ret = new ArrayList(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_CIGAR, - "Hard clipping operator not at start or end of CIGAR", readName, recordNumber)); + ret.add(new SAMValidationError( + SAMValidationError.Type.INVALID_CIGAR, + "Hard clipping operator not at start or end of CIGAR", + readName, + recordNumber)); } } else { if (op != CigarOperator.S) throw new IllegalStateException("Should never happen: " + op.name()); @@ -171,40 +178,49 @@ public List isValid(final String readName, final long record // from the end. } else if (cigarElements.get(0).getOperator() != CigarOperator.H) { if (ret == null) ret = new ArrayList(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_CIGAR, - "Soft clipping CIGAR operator can only be inside of hard clipping operator", - readName, recordNumber)); + ret.add(new SAMValidationError( + SAMValidationError.Type.INVALID_CIGAR, + "Soft clipping CIGAR operator can only be inside of hard clipping operator", + readName, + recordNumber)); } } else if (i == cigarElements.size() - 2) { if (cigarElements.get(cigarElements.size() - 1).getOperator() != CigarOperator.H) { if (ret == null) ret = new ArrayList(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_CIGAR, - "Soft clipping CIGAR operator can only be inside of hard clipping operator", - readName, recordNumber)); + ret.add(new SAMValidationError( + SAMValidationError.Type.INVALID_CIGAR, + "Soft clipping CIGAR operator can only be inside of hard clipping operator", + readName, + recordNumber)); } } else { if (ret == null) ret = new ArrayList(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_CIGAR, - "Soft clipping CIGAR operator can at start or end of read, or be inside of hard clipping operator", - readName, recordNumber)); + ret.add(new SAMValidationError( + SAMValidationError.Type.INVALID_CIGAR, + "Soft clipping CIGAR operator can at start or end of read, or be inside of hard clipping operator", + readName, + recordNumber)); } - } } else if (isRealOperator(op)) { // Must be at least one real operator (MIDN) seenRealOperator = true; // There should be an M or P operator between any pair of IDN operators if (isInDelOperator(op)) { - for (int j = i+1; j < cigarElements.size(); ++j) { + for (int j = i + 1; j < cigarElements.size(); ++j) { final CigarOperator nextOperator = cigarElements.get(j).getOperator(); // Allow - if ((isRealOperator(nextOperator) && !isInDelOperator(nextOperator)) || isPaddingOperator(nextOperator)) { + if ((isRealOperator(nextOperator) && !isInDelOperator(nextOperator)) + || isPaddingOperator(nextOperator)) { break; } if (isInDelOperator(nextOperator) && op == nextOperator) { if (ret == null) ret = new ArrayList(); - ret.add(new SAMValidationError(SAMValidationError.Type.ADJACENT_INDEL_IN_CIGAR, - "No M or N operator between pair of " + op.name() + " operators in CIGAR", readName, recordNumber)); + ret.add(new SAMValidationError( + SAMValidationError.Type.ADJACENT_INDEL_IN_CIGAR, + "No M or N operator between pair of " + op.name() + " operators in CIGAR", + readName, + recordNumber)); } } } @@ -214,42 +230,55 @@ public List isValid(final String readName, final long record * Removed restriction that padding not be the first operator because if a read starts in the middle of a pad * in a padded reference, it is necessary to precede the read with padding so that alignment start refers to a * position on the unpadded reference. - */ + */ } else if (i == cigarElements.size() - 1) { if (ret == null) ret = new ArrayList(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_CIGAR, - "Padding operator not valid at end of CIGAR", readName, recordNumber)); - } else if (!isRealOperator(cigarElements.get(i-1).getOperator()) || - !isRealOperator(cigarElements.get(i+1).getOperator())) { + ret.add(new SAMValidationError( + SAMValidationError.Type.INVALID_CIGAR, + "Padding operator not valid at end of CIGAR", + readName, + recordNumber)); + } else if (!isRealOperator(cigarElements.get(i - 1).getOperator()) + || !isRealOperator(cigarElements.get(i + 1).getOperator())) { if (ret == null) ret = new ArrayList(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_CIGAR, - "Padding operator not between real operators in CIGAR", readName, recordNumber)); + ret.add(new SAMValidationError( + SAMValidationError.Type.INVALID_CIGAR, + "Padding operator not between real operators in CIGAR", + readName, + recordNumber)); } } } if (!seenRealOperator) { if (ret == null) ret = new ArrayList(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_CIGAR, - "No real operator (M|I|D|N) in CIGAR", readName, recordNumber)); + ret.add(new SAMValidationError( + SAMValidationError.Type.INVALID_CIGAR, + "No real operator (M|I|D|N) in CIGAR", + readName, + recordNumber)); } return ret; } private static boolean isRealOperator(final CigarOperator op) { - return op == CigarOperator.M || op == CigarOperator.EQ || op == CigarOperator.X || - op == CigarOperator.I || op == CigarOperator.D || op == CigarOperator.N; + return op == CigarOperator.M + || op == CigarOperator.EQ + || op == CigarOperator.X + || op == CigarOperator.I + || op == CigarOperator.D + || op == CigarOperator.N; } private static boolean isInDelOperator(final CigarOperator op) { - return op !=null && op.isIndel(); + return op != null && op.isIndel(); } private static boolean isClippingOperator(final CigarOperator op) { - return op !=null && op.isClipping(); + return op != null && op.isClipping(); } private static boolean isPaddingOperator(final CigarOperator op) { - return op !=null && op.isPadding(); + return op != null && op.isPadding(); } @Override @@ -261,27 +290,27 @@ public boolean equals(final Object o) { return cigarElements.equals(cigar.cigarElements); } - + /** build a new Cigar object from a list of cigar operators. * This can be used if you have the operators associated to * each base in the read. - * + * * e.g: read length =10 with cigar= [M,M,M,M,M,M,M,M,M,M], here * fromCigarOperators would generate the cigar '10M' - * + * * later the user resolved the 'M' to '=' or 'X', the array is now - * + * * [=,=,=,=,=,X,X,=,=,=] - * + * * fromCigarOperators would generate the cigar '5M2X3M' - * + * * */ public static Cigar fromCigarOperators(final List cigarOperators) { if (cigarOperators == null) throw new IllegalArgumentException("cigarOperators is null"); final List cigarElementList = new ArrayList<>(); int i = 0; // find adjacent operators and build list of cigar elements - while (i < cigarOperators.size() ) { + while (i < cigarOperators.size()) { final CigarOperator currentOp = cigarOperators.get(i); int j = i + 1; while (j < cigarOperators.size() && cigarOperators.get(j).equals(currentOp)) { @@ -299,31 +328,31 @@ public static Cigar fromCigarOperators(final List cigarOperators) * @param cigarString A SAM formatted CIGAR string. * @return a new Cigar */ - public static Cigar fromCigarString(String cigarString){ + public static Cigar fromCigarString(String cigarString) { return TextCigarCodec.decode(cigarString); } - + /** shortcut to getCigarElements().iterator() */ @Override public Iterator iterator() { return this.getCigarElements().iterator(); } - + /** returns true if the cigar string contains the given operator */ public boolean containsOperator(final CigarOperator operator) { - return this.cigarElements.stream().anyMatch( element -> element.getOperator() == operator); + return this.cigarElements.stream().anyMatch(element -> element.getOperator() == operator); } - + /** returns the first cigar element */ public CigarElement getFirstCigarElement() { - return isEmpty() ? null : this.cigarElements.get(0); + return isEmpty() ? null : this.cigarElements.get(0); } - + /** returns the last cigar element */ public CigarElement getLastCigarElement() { - return isEmpty() ? null : this.cigarElements.get(this.numCigarElements() - 1 ); + return isEmpty() ? null : this.cigarElements.get(this.numCigarElements() - 1); } - + /** returns true if the cigar string starts With a clipping operator */ public boolean isLeftClipped() { return !isEmpty() && isClippingOperator(getFirstCigarElement().getOperator()); @@ -338,7 +367,7 @@ public boolean isRightClipped() { public boolean isClipped() { return isLeftClipped() || isRightClipped(); } - + @Override public int hashCode() { return cigarElements.hashCode(); diff --git a/src/main/java/htsjdk/samtools/CigarElement.java b/src/main/java/htsjdk/samtools/CigarElement.java index 016956c565..2dc761d54a 100644 --- a/src/main/java/htsjdk/samtools/CigarElement.java +++ b/src/main/java/htsjdk/samtools/CigarElement.java @@ -36,7 +36,10 @@ public class CigarElement implements Serializable { private final CigarOperator operator; public CigarElement(final int length, final CigarOperator operator) { - if (length < 0) throw new IllegalArgumentException(String.format("Cigar element being constructed with negative length: %d and operation: %s" , length, operator.name())); + if (length < 0) + throw new IllegalArgumentException(String.format( + "Cigar element being constructed with negative length: %d and operation: %s", + length, operator.name())); this.length = length; this.operator = operator; } @@ -68,9 +71,9 @@ public int hashCode() { result = 31 * result + (operator != null ? operator.hashCode() : 0); return result; } - + @Override public String toString() { - return String.valueOf(this.length)+this.operator; + return String.valueOf(this.length) + this.operator; } } diff --git a/src/main/java/htsjdk/samtools/CigarOperator.java b/src/main/java/htsjdk/samtools/CigarOperator.java index 46ea539d4a..af1d5c684e 100644 --- a/src/main/java/htsjdk/samtools/CigarOperator.java +++ b/src/main/java/htsjdk/samtools/CigarOperator.java @@ -28,24 +28,23 @@ */ public enum CigarOperator { /** Match or mismatch */ - M(true, true, 'M'), + M(true, true, 'M'), /** Insertion vs. the reference. */ - I(true, false, 'I'), + I(true, false, 'I'), /** Deletion vs. the reference. */ - D(false, true, 'D'), + D(false, true, 'D'), /** Skipped region from the reference. */ - N(false, true, 'N'), + N(false, true, 'N'), /** Soft clip. */ - S(true, false, 'S'), + S(true, false, 'S'), /** Hard clip. */ H(false, false, 'H'), /** Padding. */ P(false, false, 'P'), /** Matches the reference. */ - EQ(true, true, '='), + EQ(true, true, '='), /** Mismatches the reference. */ - X(true, true, 'X') - ; + X(true, true, 'X'); // Representation of CigarOperator in BAM file private static final byte OP_M = 0; @@ -81,10 +80,14 @@ public enum CigarOperator { } /** If true, represents that this cigar operator "consumes" bases from the read bases. */ - public boolean consumesReadBases() { return consumesReadBases; } + public boolean consumesReadBases() { + return consumesReadBases; + } /** If true, represents that this cigar operator "consumes" bases from the reference sequence. */ - public boolean consumesReferenceBases() { return consumesReferenceBases; } + public boolean consumesReferenceBases() { + return consumesReferenceBases; + } /** * @param b CIGAR operator in character form as appears in a text CIGAR string @@ -92,26 +95,26 @@ public enum CigarOperator { */ public static CigarOperator characterToEnum(final int b) { switch (b) { - case 'M': - return M; - case 'I': - return I; - case 'D': - return D; - case 'N': - return N; - case 'S': - return S; - case 'H': - return H; - case 'P': - return P; - case '=': - return EQ; - case 'X': - return X; - default: - throw new IllegalArgumentException("Unrecognized CigarOperator: " + b); + case 'M': + return M; + case 'I': + return I; + case 'D': + return D; + case 'N': + return N; + case 'S': + return S; + case 'H': + return H; + case 'P': + return P; + case '=': + return EQ; + case 'X': + return X; + default: + throw new IllegalArgumentException("Unrecognized CigarOperator: " + b); } } @@ -120,7 +123,7 @@ public static CigarOperator characterToEnum(final int b) { * @return CigarOperator enum value corresponding to the given int value. */ public static CigarOperator binaryToEnum(final int i) { - switch(i) { + switch (i) { case OP_M: return M; case OP_I: @@ -150,7 +153,7 @@ public static CigarOperator binaryToEnum(final int i) { * @return CIGAR operator corresponding to the enum value in binary form as appears in a BAMRecord. */ public static int enumToBinary(final CigarOperator e) { - switch(e) { + switch (e) { case M: return OP_M; case I: @@ -198,14 +201,15 @@ public boolean isIndelOrSkippedRegion() { public boolean isAlignment() { return this == M || this == X || this == EQ; } - + /** Returns true if the operator is a Padding operator */ public boolean isPadding() { return this == P; } - + /** Returns the cigar operator as it would be seen in a SAM file. */ - @Override public String toString() { + @Override + public String toString() { return this.string; } } diff --git a/src/main/java/htsjdk/samtools/ComparableSamRecordIterator.java b/src/main/java/htsjdk/samtools/ComparableSamRecordIterator.java index cb2da892cb..e69c8f06aa 100644 --- a/src/main/java/htsjdk/samtools/ComparableSamRecordIterator.java +++ b/src/main/java/htsjdk/samtools/ComparableSamRecordIterator.java @@ -25,7 +25,6 @@ import htsjdk.samtools.util.CloseableIterator; import htsjdk.samtools.util.PeekableIterator; - import java.util.Comparator; /** @@ -33,7 +32,8 @@ * The comparison is performed by comparing the next record in the iterator to the next * record in another iterator and returning the ordering between those SAM records. */ -class ComparableSamRecordIterator extends PeekableIterator implements Comparable { +class ComparableSamRecordIterator extends PeekableIterator + implements Comparable { private final Comparator comparator; private final SamReader reader; @@ -44,7 +44,8 @@ class ComparableSamRecordIterator extends PeekableIterator implements * @param iterator the wrapped iterator. * @param comparator the Comparator to use to provide ordering fo SAMRecords */ - public ComparableSamRecordIterator(final SamReader sam, final CloseableIterator iterator, final Comparator comparator) { + public ComparableSamRecordIterator( + final SamReader sam, final CloseableIterator iterator, final Comparator comparator) { super(iterator); this.reader = sam; this.comparator = comparator; @@ -66,8 +67,8 @@ public SamReader getReader() { @Override public int compareTo(final ComparableSamRecordIterator that) { if (this.comparator.getClass() != that.comparator.getClass()) { - throw new IllegalStateException("Attempt to compare two ComparableSAMRecordIterators that " + - "have different orderings internally"); + throw new IllegalStateException("Attempt to compare two ComparableSAMRecordIterators that " + + "have different orderings internally"); } final SAMRecord record = this.peek(); @@ -85,6 +86,7 @@ public boolean equals(final Object o) { @Override public int hashCode() { - throw new UnsupportedOperationException("ComparableSamRecordIterator should not be hashed because it can change value"); + throw new UnsupportedOperationException( + "ComparableSamRecordIterator should not be hashed because it can change value"); } } diff --git a/src/main/java/htsjdk/samtools/CompressedIndexFileBuffer.java b/src/main/java/htsjdk/samtools/CompressedIndexFileBuffer.java index 2c208b4f6c..c16f97c39a 100644 --- a/src/main/java/htsjdk/samtools/CompressedIndexFileBuffer.java +++ b/src/main/java/htsjdk/samtools/CompressedIndexFileBuffer.java @@ -4,7 +4,6 @@ import htsjdk.samtools.util.BinaryCodec; import htsjdk.samtools.util.BlockCompressedInputStream; import htsjdk.samtools.util.RuntimeIOException; - import java.io.File; import java.io.IOException; @@ -22,7 +21,7 @@ class CompressedIndexFileBuffer implements IndexFileBuffer { mCompressedStream = new BlockCompressedInputStream(file); binaryCodec = new BinaryCodec(mCompressedStream); } catch (IOException ioe) { - throw(new RuntimeIOException("Construction error of CSI compressed stream: " + ioe)); + throw (new RuntimeIOException("Construction error of CSI compressed stream: " + ioe)); } } @@ -55,7 +54,7 @@ public void skipBytes(final int count) { try { mCompressedStream.skip(count); } catch (IOException ioe) { - throw(new RuntimeIOException("Skip error in CSI compressed stream: " + ioe)); + throw (new RuntimeIOException("Skip error in CSI compressed stream: " + ioe)); } } @@ -68,7 +67,7 @@ public void seek(final long position) { try { mCompressedStream.seek(position); } catch (IOException ioe) { - throw(new RuntimeIOException("Seek error in CSI compressed stream: " + ioe)); + throw (new RuntimeIOException("Seek error in CSI compressed stream: " + ioe)); } } @@ -90,8 +89,7 @@ public void close() { try { mCompressedStream.close(); } catch (IOException ioe) { - throw(new RuntimeIOException("Close error in CSI compressed stream: " + ioe)); + throw (new RuntimeIOException("Close error in CSI compressed stream: " + ioe)); } } - } diff --git a/src/main/java/htsjdk/samtools/ConstantMemoryDownsamplingIterator.java b/src/main/java/htsjdk/samtools/ConstantMemoryDownsamplingIterator.java index c6e0de49e0..047ea65550 100644 --- a/src/main/java/htsjdk/samtools/ConstantMemoryDownsamplingIterator.java +++ b/src/main/java/htsjdk/samtools/ConstantMemoryDownsamplingIterator.java @@ -25,7 +25,6 @@ import htsjdk.samtools.util.Murmur3; import htsjdk.samtools.util.PeekableIterator; - import java.util.Iterator; /** @@ -46,7 +45,6 @@ class ConstantMemoryDownsamplingIterator extends DownsamplingIterator { private final int maxHashValue; private final Murmur3 hasher; - /** Constructs a downsampling iterator upon the supplied iterator, using the Random as the source of randomness. */ ConstantMemoryDownsamplingIterator(final Iterator iterator, final double proportion, final int seed) { super(proportion); @@ -60,7 +58,8 @@ class ConstantMemoryDownsamplingIterator extends DownsamplingIterator { } /** Returns true if there is another record available post-downsampling, false otherwise. */ - @Override public boolean hasNext() { + @Override + public boolean hasNext() { // The underlying iterator is always left at the next return-able read, so if it has a next read, so do we return this.underlyingIterator.hasNext(); } @@ -70,7 +69,8 @@ class ConstantMemoryDownsamplingIterator extends DownsamplingIterator { * @return true if there is at least one emittable record ready for emission, false otherwise */ private boolean advanceToNextAcceptedRead() { - while (this.underlyingIterator.hasNext() && this.hasher.hashUnencodedChars(this.underlyingIterator.peek().getReadName()) > this.maxHashValue) { + while (this.underlyingIterator.hasNext() + && this.hasher.hashUnencodedChars(this.underlyingIterator.peek().getReadName()) > this.maxHashValue) { this.underlyingIterator.next(); recordDiscardedRecord(); } @@ -79,7 +79,8 @@ private boolean advanceToNextAcceptedRead() { } /** Returns the next record from the iterator, or throws an exception if there is no next record. */ - @Override public SAMRecord next() { + @Override + public SAMRecord next() { final SAMRecord rec = this.underlyingIterator.next(); recordAcceptedRecord(); advanceToNextAcceptedRead(); diff --git a/src/main/java/htsjdk/samtools/CoordinateSortedPairInfoMap.java b/src/main/java/htsjdk/samtools/CoordinateSortedPairInfoMap.java index f28b003e69..94002e0f67 100644 --- a/src/main/java/htsjdk/samtools/CoordinateSortedPairInfoMap.java +++ b/src/main/java/htsjdk/samtools/CoordinateSortedPairInfoMap.java @@ -27,7 +27,6 @@ import htsjdk.samtools.util.CloserUtil; import htsjdk.samtools.util.FileAppendStreamLRUCache; import htsjdk.samtools.util.IOUtil; - import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -57,6 +56,7 @@ public class CoordinateSortedPairInfoMap implements Iterable mapInRam = null; private final FileAppendStreamLRUCache outputStreams; @@ -120,8 +120,7 @@ private void ensureSequenceLoaded(final int sequenceIndex) { } final Integer numRecords = sizeOfMapOnDisk.remove(sequenceIndex); if (mapOnDisk.exists()) { - if (numRecords == null) - throw new IllegalStateException("null numRecords for " + mapOnDisk); + if (numRecords == null) throw new IllegalStateException("null numRecords for " + mapOnDisk); FileInputStream is = null; try { is = new FileInputStream(mapOnDisk); @@ -129,8 +128,8 @@ private void ensureSequenceLoaded(final int sequenceIndex) { for (int i = 0; i < numRecords; ++i) { final Map.Entry keyAndRecord = elementCodec.decode(); if (mapInRam.containsKey(keyAndRecord.getKey())) - throw new SAMException("Value was put into PairInfoMap more than once. " + - sequenceIndex + ": " + keyAndRecord.getKey()); + throw new SAMException("Value was put into PairInfoMap more than once. " + sequenceIndex + + ": " + keyAndRecord.getKey()); mapInRam.put(keyAndRecord.getKey(), keyAndRecord.getValue()); } } finally { @@ -156,8 +155,8 @@ public void put(final int sequenceIndex, final KEY key, final REC record) { if (sequenceIndex == sequenceIndexOfMapInRam) { // Store in RAM map if (mapInRam.containsKey(key)) - throw new IllegalArgumentException("Putting value into PairInfoMap that already existed. " + - sequenceIndex + ": " + key); + throw new IllegalArgumentException( + "Putting value into PairInfoMap that already existed. " + sequenceIndex + ": " + key); mapInRam.put(key, record); } else { // Append to file @@ -166,7 +165,7 @@ public void put(final int sequenceIndex, final KEY key, final REC record) { elementCodec.encode(key, record); Integer prevCount = sizeOfMapOnDisk.get(sequenceIndex); if (prevCount == null) prevCount = 0; - sizeOfMapOnDisk.put(sequenceIndex, prevCount + 1); + sizeOfMapOnDisk.put(sequenceIndex, prevCount + 1); } } @@ -194,7 +193,7 @@ public int size() { * @return number of elements stored in RAM. Always <= size() */ public int sizeInRam() { - return mapInRam != null? mapInRam.size(): 0; + return mapInRam != null ? mapInRam.size() : 0; } /** @@ -216,8 +215,7 @@ private class MapIterator implements CloseableIterator> { private Iterator> currentReferenceIterator = null; private MapIterator() { - if (sequenceIndexOfMapInRam != INVALID_SEQUENCE_INDEX) - referenceIndices.add(sequenceIndexOfMapInRam); + if (sequenceIndexOfMapInRam != INVALID_SEQUENCE_INDEX) referenceIndices.add(sequenceIndexOfMapInRam); referenceIndexIterator = referenceIndices.iterator(); advanceToNextNonEmptyReferenceIndex(); } @@ -297,6 +295,5 @@ public interface Codec { * a record. */ Map.Entry decode(); - } } diff --git a/src/main/java/htsjdk/samtools/CustomReaderFactory.java b/src/main/java/htsjdk/samtools/CustomReaderFactory.java index bb00da74e3..1f16c2f388 100644 --- a/src/main/java/htsjdk/samtools/CustomReaderFactory.java +++ b/src/main/java/htsjdk/samtools/CustomReaderFactory.java @@ -24,120 +24,117 @@ package htsjdk.samtools; import htsjdk.samtools.util.Log; - import java.net.URL; import java.net.URLClassLoader; - /** - * Factory for creating custom readers for accessing API based resources, + * Factory for creating custom readers for accessing API based resources, * e.g. ga4gh. * The configuration is controlled via custom_reader property (@see Defaults). * This allows injection of such readers from code bases outside HTSJDK. */ public class CustomReaderFactory { - private final static Log LOG = Log.getInstance(CustomReaderFactory.class); - /** - * Interface to be implemented by custom factory classes that register - * themselves with this factory and are loaded dynamically. - */ - public interface ICustomReaderFactory { - SamReader open(URL url); - } - - private static final CustomReaderFactory DEFAULT_FACTORY; - private static CustomReaderFactory currentFactory; - - private String urlPrefix = ""; - private String factoryClassName = ""; - private String jarFile = ""; - private ICustomReaderFactory factory; - - static { - DEFAULT_FACTORY = new CustomReaderFactory(); - currentFactory = DEFAULT_FACTORY; - } + private static final Log LOG = Log.getInstance(CustomReaderFactory.class); + /** + * Interface to be implemented by custom factory classes that register + * themselves with this factory and are loaded dynamically. + */ + public interface ICustomReaderFactory { + SamReader open(URL url); + } + + private static final CustomReaderFactory DEFAULT_FACTORY; + private static CustomReaderFactory currentFactory; + + private String urlPrefix = ""; + private String factoryClassName = ""; + private String jarFile = ""; + private ICustomReaderFactory factory; - public static void setInstance(final CustomReaderFactory factory){ - currentFactory = factory; - } - - public static void resetToDefaultInstance() { - setInstance(DEFAULT_FACTORY); - } + static { + DEFAULT_FACTORY = new CustomReaderFactory(); + currentFactory = DEFAULT_FACTORY; + } + + public static void setInstance(final CustomReaderFactory factory) { + currentFactory = factory; + } + + public static void resetToDefaultInstance() { + setInstance(DEFAULT_FACTORY); + } - public static CustomReaderFactory getInstance(){ - return currentFactory; - } - - /** - * Initializes factory based on the custom_reader property specification. - */ - private CustomReaderFactory() { - this(Defaults.CUSTOM_READER_FACTORY); - } - - CustomReaderFactory(String cfg) { - final String[] cfgComponents = cfg.split(","); - if (cfgComponents.length < 2) { - return; + public static CustomReaderFactory getInstance() { + return currentFactory; } - urlPrefix = cfgComponents[0].toLowerCase(); - factoryClassName = cfgComponents[1]; - if (cfgComponents.length > 2) { - jarFile = cfgComponents[2]; + + /** + * Initializes factory based on the custom_reader property specification. + */ + private CustomReaderFactory() { + this(Defaults.CUSTOM_READER_FACTORY); } - } - - /** - * Lazily creates factory based on the configuration. - * @return null if creation fails, factory instance otherwise. - */ - private synchronized ICustomReaderFactory getFactory() { - if (factory == null) { - try { - Class clazz = null; - - if (!jarFile.isEmpty()) { - LOG.info("Attempting to load factory class " + factoryClassName + - " from " + jarFile); - final URL jarURL = new URL("file:///"+jarFile); - clazz = Class.forName(factoryClassName, true, - new URLClassLoader (new URL[] { jarURL }, - this.getClass().getClassLoader())); - } else { - LOG.info("Attempting to load factory class " + factoryClassName); - clazz = Class.forName(factoryClassName); + + CustomReaderFactory(String cfg) { + final String[] cfgComponents = cfg.split(","); + if (cfgComponents.length < 2) { + return; + } + urlPrefix = cfgComponents[0].toLowerCase(); + factoryClassName = cfgComponents[1]; + if (cfgComponents.length > 2) { + jarFile = cfgComponents[2]; } - - factory = (ICustomReaderFactory)clazz.newInstance(); - LOG.info("Created custom factory for " + urlPrefix + " from " + - factoryClassName + " loaded from " + (jarFile.isEmpty() ? - " this jar" : jarFile)); - } catch (Exception e) { - LOG.error(e); - return null; - } } - return factory; - } - - /** - * Check if the url is supposed to be handled by the custom factory and if so - * attempt to create reader via an instance of this custom factory. - * - * @return null if the url is not handled by this factory, SamReader otherwise. - */ - public SamReader maybeOpen(URL url) { - if (urlPrefix.isEmpty() || - !url.toString().toLowerCase().startsWith(urlPrefix)) { - return null; + + /** + * Lazily creates factory based on the configuration. + * @return null if creation fails, factory instance otherwise. + */ + private synchronized ICustomReaderFactory getFactory() { + if (factory == null) { + try { + Class clazz = null; + + if (!jarFile.isEmpty()) { + LOG.info("Attempting to load factory class " + factoryClassName + " from " + jarFile); + final URL jarURL = new URL("file:///" + jarFile); + clazz = Class.forName( + factoryClassName, + true, + new URLClassLoader( + new URL[] {jarURL}, this.getClass().getClassLoader())); + } else { + LOG.info("Attempting to load factory class " + factoryClassName); + clazz = Class.forName(factoryClassName); + } + + factory = (ICustomReaderFactory) clazz.newInstance(); + LOG.info("Created custom factory for " + urlPrefix + " from " + factoryClassName + " loaded from " + + (jarFile.isEmpty() ? " this jar" : jarFile)); + } catch (Exception e) { + LOG.error(e); + return null; + } + } + return factory; } - LOG.info("Attempting to open " + url + " with custom factory"); - final ICustomReaderFactory factory = getFactory(); - if (factory == null) { - return null; + + /** + * Check if the url is supposed to be handled by the custom factory and if so + * attempt to create reader via an instance of this custom factory. + * + * @return null if the url is not handled by this factory, SamReader otherwise. + */ + public SamReader maybeOpen(URL url) { + if (urlPrefix.isEmpty() || !url.toString().toLowerCase().startsWith(urlPrefix)) { + return null; + } + LOG.info("Attempting to open " + url + " with custom factory"); + final ICustomReaderFactory factory = getFactory(); + if (factory == null) { + return null; + } + return factory.open(url); } - return factory.open(url); - } } diff --git a/src/main/java/htsjdk/samtools/DefaultSAMRecordFactory.java b/src/main/java/htsjdk/samtools/DefaultSAMRecordFactory.java index 707cc6ec12..6df651db31 100644 --- a/src/main/java/htsjdk/samtools/DefaultSAMRecordFactory.java +++ b/src/main/java/htsjdk/samtools/DefaultSAMRecordFactory.java @@ -8,9 +8,9 @@ public class DefaultSAMRecordFactory implements SAMRecordFactory { private static final DefaultSAMRecordFactory INSTANCE = new DefaultSAMRecordFactory(); - + public static DefaultSAMRecordFactory getInstance() { - return INSTANCE; + return INSTANCE; } /** Create a new SAMRecord to be filled in */ @@ -25,32 +25,34 @@ public SAMRecord createSAMRecord(final SAMFileHeader header) { * dictionary in the header argument. */ @Override - public BAMRecord createBAMRecord (final SAMFileHeader header, - final int referenceSequenceIndex, - final int alignmentStart, - final short readNameLength, - final short mappingQuality, - final int indexingBin, - final int cigarLen, - final int flags, - final int readLen, - final int mateReferenceSequenceIndex, - final int mateAlignmentStart, - final int insertSize, - final byte[] variableLengthBlock) { + public BAMRecord createBAMRecord( + final SAMFileHeader header, + final int referenceSequenceIndex, + final int alignmentStart, + final short readNameLength, + final short mappingQuality, + final int indexingBin, + final int cigarLen, + final int flags, + final int readLen, + final int mateReferenceSequenceIndex, + final int mateAlignmentStart, + final int insertSize, + final byte[] variableLengthBlock) { - return new BAMRecord(header, - referenceSequenceIndex, - alignmentStart, - readNameLength, - mappingQuality, - indexingBin, - cigarLen, - flags, - readLen, - mateReferenceSequenceIndex, - mateAlignmentStart, - insertSize, - variableLengthBlock); + return new BAMRecord( + header, + referenceSequenceIndex, + alignmentStart, + readNameLength, + mappingQuality, + indexingBin, + cigarLen, + flags, + readLen, + mateReferenceSequenceIndex, + mateAlignmentStart, + insertSize, + variableLengthBlock); } } diff --git a/src/main/java/htsjdk/samtools/Defaults.java b/src/main/java/htsjdk/samtools/Defaults.java index bfda62db9e..e26509d60f 100644 --- a/src/main/java/htsjdk/samtools/Defaults.java +++ b/src/main/java/htsjdk/samtools/Defaults.java @@ -1,7 +1,6 @@ package htsjdk.samtools; import htsjdk.samtools.util.Log; - import java.io.File; import java.util.Collections; import java.util.Optional; @@ -15,8 +14,8 @@ * @author Tim Fennell */ public class Defaults { - private static final Log log = Log.getInstance(Defaults.class); - + private static final Log log = Log.getInstance(Defaults.class); + /** Should BAM index files be created when writing out coordinate sorted BAM files? Default = false. */ public static final boolean CREATE_INDEX; @@ -102,7 +101,6 @@ public class Defaults { */ public static final boolean SRA_LIBRARIES_DOWNLOAD; - /** * Whether to attempt to use jlibdeflate (libdeflate via JNI) for DEFLATE compression and decompression. * When true, the default deflater/inflater factories will try to load the native library and fall back @@ -117,13 +115,13 @@ public class Defaults { public static final String OPTIMISTIC_VCF_4_4_PROPERTY = "optimistic_vcf_4_4"; - /** * Disable use of the Snappy compressor. Default = false. */ public static final boolean DISABLE_SNAPPY_COMPRESSOR; public static final String SAMJDK_PREFIX = "samjdk."; + static { CREATE_INDEX = getBooleanProperty("create_index", false); CREATE_MD5 = getBooleanProperty("create_md5", false); @@ -143,7 +141,8 @@ public class Defaults { USE_CRAM_REF_DOWNLOAD = getBooleanProperty("use_cram_ref_download", false); EBI_REFERENCE_SERVICE_URL_MASK = "https://www.ebi.ac.uk/ena/cram/md5/%s"; CUSTOM_READER_FACTORY = getStringProperty("custom_reader", ""); - SAM_FLAG_FIELD_FORMAT = SamFlagField.valueOf(getStringProperty("sam_flag_field_format", SamFlagField.DECIMAL.name())); + SAM_FLAG_FIELD_FORMAT = + SamFlagField.valueOf(getStringProperty("sam_flag_field_format", SamFlagField.DECIMAL.name())); SRA_LIBRARIES_DOWNLOAD = getBooleanProperty("sra_libraries_download", false); USE_LIBDEFLATE = getBooleanProperty("use_libdeflate", true); DISABLE_SNAPPY_COMPRESSOR = getBooleanProperty(DISABLE_SNAPPY_PROPERTY_NAME, false); @@ -155,7 +154,7 @@ public class Defaults { * The returned map is unmodifiable. * This function is useful for example when logging all defaults. */ - public static SortedMap allDefaults(){ + public static SortedMap allDefaults() { final SortedMap result = new TreeMap<>(); result.put("CREATE_INDEX", CREATE_INDEX); result.put("CREATE_MD5", CREATE_MD5); @@ -175,14 +174,17 @@ public static SortedMap allDefaults(){ return Collections.unmodifiableSortedMap(result); } - /** Gets a string system property, prefixed with "samjdk." using the default + /** Gets a string system property, prefixed with "samjdk." using the default * if the property does not exist or if the java.security manager raises an exception for * applications started with -Djava.security.manager . */ private static String getStringProperty(final String name, final String def) { try { return System.getProperty(Defaults.SAMJDK_PREFIX + name, def); } catch (final SecurityException error) { - log.warn(error,"java Security Manager forbids 'System.getProperty(\"" + name + "\")' , returning default value: " + def ); + log.warn( + error, + "java Security Manager forbids 'System.getProperty(\"" + name + "\")' , returning default value: " + + def); return def; } } @@ -190,11 +192,11 @@ private static String getStringProperty(final String name, final String def) { /** Checks whether a string system property, prefixed with "samjdk.", exists. * If the property does not exist or if the java.security manager raises an exception for * applications started with -Djava.security.manager this method returns false. */ - private static boolean hasProperty(final String name){ + private static boolean hasProperty(final String name) { try { return null != System.getProperty(Defaults.SAMJDK_PREFIX + name); } catch (final SecurityException error) { - log.warn(error,"java Security Manager forbids 'System.getProperty(\"" + name + "\")' , returning false"); + log.warn(error, "java Security Manager forbids 'System.getProperty(\"" + name + "\")' , returning false"); return false; } } @@ -217,7 +219,9 @@ private static File getFileProperty(final String name, final String def) { Optional maybeFile = Optional.ofNullable(value).map(File::new); maybeFile.ifPresent(f -> { if (!f.exists()) { - log.warn(String.format("File property for %s has value %s. However file %s doesn't exist.", SAMJDK_PREFIX + name, value, f.getAbsolutePath())); + log.warn(String.format( + "File property for %s has value %s. However file %s doesn't exist.", + SAMJDK_PREFIX + name, value, f.getAbsolutePath())); } else { log.info(String.format("Found file for property %s: %s ", SAMJDK_PREFIX + name, f.getAbsolutePath())); } diff --git a/src/main/java/htsjdk/samtools/DiskBasedBAMFileIndex.java b/src/main/java/htsjdk/samtools/DiskBasedBAMFileIndex.java index 1eddddde31..321b26dbe9 100644 --- a/src/main/java/htsjdk/samtools/DiskBasedBAMFileIndex.java +++ b/src/main/java/htsjdk/samtools/DiskBasedBAMFileIndex.java @@ -24,7 +24,6 @@ package htsjdk.samtools; import htsjdk.samtools.seekablestream.SeekableStream; - import java.io.File; import java.util.ArrayList; import java.util.List; @@ -32,8 +31,7 @@ /** * A class for reading BAM file indices, hitting the disk once per query. */ -public class DiskBasedBAMFileIndex extends AbstractBAMFileIndex -{ +public class DiskBasedBAMFileIndex extends AbstractBAMFileIndex { public DiskBasedBAMFileIndex(final File file, final SAMSequenceDictionary dictionary) { super(file, dictionary); } @@ -42,7 +40,8 @@ public DiskBasedBAMFileIndex(final SeekableStream stream, final SAMSequenceDicti super(stream, dictionary); } - public DiskBasedBAMFileIndex(final File file, final SAMSequenceDictionary dictionary, final boolean useMemoryMapping) { + public DiskBasedBAMFileIndex( + final File file, final SAMSequenceDictionary dictionary, final boolean useMemoryMapping) { super(file, dictionary, useMemoryMapping); } @@ -58,23 +57,23 @@ public DiskBasedBAMFileIndex(final File file, final SAMSequenceDictionary dictio */ @Override public BAMFileSpan getSpanOverlapping(final int referenceIndex, final int startPos, final int endPos) { - final BAMIndexContent queryResults = query(referenceIndex,startPos,endPos); + final BAMIndexContent queryResults = query(referenceIndex, startPos, endPos); - if(queryResults == null) - return null; + if (queryResults == null) return null; List chunkList = new ArrayList(); - for(final Chunk chunk: queryResults.getAllChunks()) - chunkList.add(chunk.clone()); - chunkList = Chunk.optimizeChunkList(chunkList,queryResults.getLinearIndex().getMinimumOffset(startPos)); + for (final Chunk chunk : queryResults.getAllChunks()) chunkList.add(chunk.clone()); + chunkList = + Chunk.optimizeChunkList(chunkList, queryResults.getLinearIndex().getMinimumOffset(startPos)); return new BAMFileSpan(chunkList); } - @Override - protected BAMIndexContent getQueryResults(final int reference){ - throw new UnsupportedOperationException(); - // todo: there ought to be a way to support this using the first startPos for the reference and the last - // return query(reference, 1, -1); - // If this were implemented, BAMIndexer.createAndWriteIndex could extend DiskBasedBAMFileIndex -or- CachingBAMFileIndex + @Override + protected BAMIndexContent getQueryResults(final int reference) { + throw new UnsupportedOperationException(); + // todo: there ought to be a way to support this using the first startPos for the reference and the last + // return query(reference, 1, -1); + // If this were implemented, BAMIndexer.createAndWriteIndex could extend DiskBasedBAMFileIndex -or- + // CachingBAMFileIndex } } diff --git a/src/main/java/htsjdk/samtools/DownsamplingIterator.java b/src/main/java/htsjdk/samtools/DownsamplingIterator.java index 8ca0d84cae..5056964f40 100644 --- a/src/main/java/htsjdk/samtools/DownsamplingIterator.java +++ b/src/main/java/htsjdk/samtools/DownsamplingIterator.java @@ -49,22 +49,35 @@ public DownsamplingIterator(final double targetProportion) { } /** Does nothing. */ - @Override public void close() { /** No Op. */ } + @Override + public void close() { + /** No Op. */ + } /** Returns the number of records seen, including accepted and discarded, since creation of the last call to resetStatistics. */ - public long getSeenCount() { return this.recordsSeen; } + public long getSeenCount() { + return this.recordsSeen; + } /** Returns the number of records returned since creation of the last call to resetStatistics. */ - public long getAcceptedCount() { return this.recordsAccepted; } + public long getAcceptedCount() { + return this.recordsAccepted; + } /** Returns the number of records discarded since creation of the last call to resetStatistics. */ - public long getDiscardedCount() { return this.recordsSeen - this.recordsAccepted; } + public long getDiscardedCount() { + return this.recordsSeen - this.recordsAccepted; + } /** Gets the fraction of records discarded since creation or the last call to resetStatistics(). */ - public double getDiscardedFraction() { return getDiscardedCount() / (double) getSeenCount(); } + public double getDiscardedFraction() { + return getDiscardedCount() / (double) getSeenCount(); + } /** Gets the fraction of records accepted since creation or the last call to resetStatistics(). */ - public double getAcceptedFraction() { return getAcceptedCount() / (double) getSeenCount(); } + public double getAcceptedFraction() { + return getAcceptedCount() / (double) getSeenCount(); + } /** Resets the statistics for records seen/accepted/discarded. */ public void resetStatistics() { @@ -78,13 +91,18 @@ public double getTargetProportion() { } /** Method for subclasses to record a record as being discarded. */ - protected final void recordDiscardedRecord() { this.recordsSeen++; } + protected final void recordDiscardedRecord() { + this.recordsSeen++; + } /** * Method for subclasses to record a specific record as being accepted. Null may be passed if a record * was discarded but access to the object is no longer available. */ - protected final void recordAcceptedRecord() { this.recordsSeen++; this.recordsAccepted++; } + protected final void recordAcceptedRecord() { + this.recordsSeen++; + this.recordsAccepted++; + } /** Record one or more records as having been discarded. */ protected final void recordDiscardRecords(final long n) { @@ -107,7 +125,8 @@ public boolean isHigherAccuracy() { } /** Not supported. */ - @Override public void remove() { + @Override + public void remove() { throw new UnsupportedOperationException("remove() not supported in DownsamplingIterators"); } } diff --git a/src/main/java/htsjdk/samtools/DownsamplingIteratorFactory.java b/src/main/java/htsjdk/samtools/DownsamplingIteratorFactory.java index 66debdaba9..6c7c0c7014 100644 --- a/src/main/java/htsjdk/samtools/DownsamplingIteratorFactory.java +++ b/src/main/java/htsjdk/samtools/DownsamplingIteratorFactory.java @@ -24,7 +24,6 @@ package htsjdk.samtools; import htsjdk.samtools.util.IOUtil; - import java.io.File; import java.util.Iterator; @@ -36,24 +35,24 @@ */ public class DownsamplingIteratorFactory { public static final String HIGH_ACCURACY_DESCRIPTION = - "Attempts (but does not guarantee) to provide accuracy up to a specified limit. Accuracy is defined as emitting " + - "a proportion of reads as close to the requested proportion as possible. In order to do so this strategy requires " + - "memory that is proportional to the number of template names in the incoming stream of reads, and will thus require " + - "large amounts of memory when running on large input files."; + "Attempts (but does not guarantee) to provide accuracy up to a specified limit. Accuracy is defined as emitting " + + "a proportion of reads as close to the requested proportion as possible. In order to do so this strategy requires " + + "memory that is proportional to the number of template names in the incoming stream of reads, and will thus require " + + "large amounts of memory when running on large input files."; public static final String CONSTANT_MEMORY_DESCRPTION = - "Downsamples a stream or file of SAMRecords using a hash-projection strategy such that it can run in constant memory. " + - "The downsampling is stochastic, and therefore the actual retained proportion will vary around the requested proportion. Due " + - "to working in fixed memory this strategy is good for large inputs, and due to the stochastic nature the accuracy of this strategy " + - "is highest with a high number of output records, and diminishes at low output volumes."; + "Downsamples a stream or file of SAMRecords using a hash-projection strategy such that it can run in constant memory. " + + "The downsampling is stochastic, and therefore the actual retained proportion will vary around the requested proportion. Due " + + "to working in fixed memory this strategy is good for large inputs, and due to the stochastic nature the accuracy of this strategy " + + "is highest with a high number of output records, and diminishes at low output volumes."; public static final String CHAINED_DESCRIPTION = - "Attempts to provide a compromise strategy that offers some of the advantages of both the ConstantMemory and HighAccuracy strategies. " + - "Uses a ConstantMemory strategy to downsample the incoming stream to approximately the desired proportion, and then a HighAccuracy " + - "strategy to finish. Works in a single pass, and will provide accuracy close to (but often not as good as) HighAccuracy while requiring " + - "memory proportional to the set of reads emitted from the ConstantMemory strategy to the HighAccuracy strategy. Works well when downsampling " + - "large inputs to small proportions (e.g. downsampling hundreds of millions of reads and retaining only 2%. Should be accurate 99.9% of the time " + - "when the input contains more than 50,000 templates (read names). For smaller inputs, HighAccuracy is recommended instead."; + "Attempts to provide a compromise strategy that offers some of the advantages of both the ConstantMemory and HighAccuracy strategies. " + + "Uses a ConstantMemory strategy to downsample the incoming stream to approximately the desired proportion, and then a HighAccuracy " + + "strategy to finish. Works in a single pass, and will provide accuracy close to (but often not as good as) HighAccuracy while requiring " + + "memory proportional to the set of reads emitted from the ConstantMemory strategy to the HighAccuracy strategy. Works well when downsampling " + + "large inputs to small proportions (e.g. downsampling hundreds of millions of reads and retaining only 2%. Should be accurate 99.9% of the time " + + "when the input contains more than 50,000 templates (read names). For smaller inputs, HighAccuracy is recommended instead."; /** Describes the available downsampling strategies. */ public enum Strategy { @@ -85,17 +84,26 @@ public String getDescription() { * is within proportion +/0 0.0001. * @param seed The seed value to use for any random process used in down-sampling. */ - public static DownsamplingIterator make(final Iterator iterator, final Strategy strategy, final double proportion, final double accuracy, final int seed) { + public static DownsamplingIterator make( + final Iterator iterator, + final Strategy strategy, + final double proportion, + final double accuracy, + final int seed) { if (strategy == null) throw new IllegalArgumentException("strategy may not be null"); if (iterator == null) throw new IllegalArgumentException("iterator may not be null"); if (proportion < 0) throw new IllegalArgumentException("proportion must be greater than 0"); if (proportion > 1) throw new IllegalArgumentException("proportion must be less than 1"); switch (strategy) { - case HighAccuracy: return new HighAccuracyDownsamplingIterator(iterator, proportion, seed).setTargetAccuracy(accuracy); - case ConstantMemory: return new ConstantMemoryDownsamplingIterator(iterator, proportion, seed); - case Chained: return new ChainedDownsamplingIterator(iterator, proportion, seed).setTargetAccuracy(accuracy); - default: throw new IllegalStateException("Unexpected value for Strategy enum in switch statement. Bug!!"); + case HighAccuracy: + return new HighAccuracyDownsamplingIterator(iterator, proportion, seed).setTargetAccuracy(accuracy); + case ConstantMemory: + return new ConstantMemoryDownsamplingIterator(iterator, proportion, seed); + case Chained: + return new ChainedDownsamplingIterator(iterator, proportion, seed).setTargetAccuracy(accuracy); + default: + throw new IllegalStateException("Unexpected value for Strategy enum in switch statement. Bug!!"); } } @@ -103,7 +111,12 @@ public static DownsamplingIterator make(final Iterator iterator, fina * Convenience method that constructs a downsampling iterator for all the reads in a SAM file. * See {@link DownsamplingIteratorFactory#make(Iterator, Strategy, double, double, int)} for detailed parameter information. */ - public static DownsamplingIterator make(final File samFile, final Strategy strategy, final double proportion, final double accuracy, final int seed) { + public static DownsamplingIterator make( + final File samFile, + final Strategy strategy, + final double proportion, + final double accuracy, + final int seed) { IOUtil.assertFileIsReadable(samFile); return make(SamReaderFactory.makeDefault().open(samFile), strategy, proportion, accuracy, seed); } @@ -112,7 +125,12 @@ public static DownsamplingIterator make(final File samFile, final Strategy strat * Convenience method that constructs a downsampling iterator for all the reads available from a SamReader. * See {@link DownsamplingIteratorFactory#make(Iterator, Strategy, double, double, int)} for detailed parameter information. */ - public static DownsamplingIterator make(final SamReader reader, final Strategy strategy, final double proportion, final double accuracy, final int seed) { + public static DownsamplingIterator make( + final SamReader reader, + final Strategy strategy, + final double proportion, + final double accuracy, + final int seed) { return make(reader.iterator(), strategy, proportion, accuracy, seed); } } diff --git a/src/main/java/htsjdk/samtools/DuplicateScoringStrategy.java b/src/main/java/htsjdk/samtools/DuplicateScoringStrategy.java index 26c83a5842..6fc7706f93 100644 --- a/src/main/java/htsjdk/samtools/DuplicateScoringStrategy.java +++ b/src/main/java/htsjdk/samtools/DuplicateScoringStrategy.java @@ -43,7 +43,9 @@ public enum ScoringStrategy { private static final Murmur3 hasher = new Murmur3(1); /** An enum to use for storing temporary attributes on SAMRecords. */ - private static enum Attr { DuplicateScore } + private static enum Attr { + DuplicateScore + } /** Calculates a score for the read which is the sum of scores over Q15. */ private static int getSumOfBaseQualities(final SAMRecord rec) { @@ -70,11 +72,12 @@ public static short computeDuplicateScore(final SAMRecord record, final ScoringS * If true is given to assumeMateCigar, then any score that can use the mate cigar to compute the mate's score will return the score * computed on both ends. */ - public static short computeDuplicateScore(final SAMRecord record, final ScoringStrategy scoringStrategy, final boolean assumeMateCigar) { + public static short computeDuplicateScore( + final SAMRecord record, final ScoringStrategy scoringStrategy, final boolean assumeMateCigar) { Short storedScore = (Short) record.getTransientAttribute(Attr.DuplicateScore); if (storedScore == null) { - short score=0; + short score = 0; switch (scoringStrategy) { case SUM_OF_BASE_QUALITIES: // two (very) long reads worth of high-quality bases can go over Short.MAX_VALUE/2 @@ -87,7 +90,8 @@ public static short computeDuplicateScore(final SAMRecord record, final ScoringS score = (short) Math.min(record.getCigar().getReferenceLength(), Short.MAX_VALUE / 2); } if (assumeMateCigar && record.getReadPairedFlag() && !record.getMateUnmappedFlag()) { - score += (short) Math.min(SAMUtils.getMateCigar(record).getReferenceLength(), Short.MAX_VALUE / 2); + score += (short) + Math.min(SAMUtils.getMateCigar(record).getReferenceLength(), Short.MAX_VALUE / 2); } break; // The RANDOM score gives the same score to both reads so that they get filtered together. @@ -124,13 +128,18 @@ public static short computeDuplicateScore(final SAMRecord record, final ScoringS * * We allow different scoring strategies. We return <0 if rec1 has a better strategy than rec2. */ - public static int compare(final SAMRecord rec1, final SAMRecord rec2, final ScoringStrategy scoringStrategy, final boolean assumeMateCigar) { + public static int compare( + final SAMRecord rec1, + final SAMRecord rec2, + final ScoringStrategy scoringStrategy, + final boolean assumeMateCigar) { int cmp; // always prefer paired over non-paired if (rec1.getReadPairedFlag() != rec2.getReadPairedFlag()) return rec1.getReadPairedFlag() ? -1 : 1; - cmp = computeDuplicateScore(rec2, scoringStrategy, assumeMateCigar) - computeDuplicateScore(rec1, scoringStrategy, assumeMateCigar); + cmp = computeDuplicateScore(rec2, scoringStrategy, assumeMateCigar) + - computeDuplicateScore(rec1, scoringStrategy, assumeMateCigar); /** * Finally, use library ID and read name @@ -152,5 +161,4 @@ public static int compare(final SAMRecord rec1, final SAMRecord rec2, final Scor public static int compare(final SAMRecord rec1, final SAMRecord rec2, final ScoringStrategy scoringStrategy) { return compare(rec1, rec2, scoringStrategy, false); } - } diff --git a/src/main/java/htsjdk/samtools/DuplicateSet.java b/src/main/java/htsjdk/samtools/DuplicateSet.java index 83330695fa..8af88c1b89 100644 --- a/src/main/java/htsjdk/samtools/DuplicateSet.java +++ b/src/main/java/htsjdk/samtools/DuplicateSet.java @@ -28,9 +28,9 @@ import java.util.List; /** - * Stores a set of records that are duplicates of each other. The first records in the list of records is - * considered the representative of the duplicate, and typically does not have it's duplicate flag set. - * The records' duplicate flag will be set appropriately as records are added. This behavior can be + * Stores a set of records that are duplicates of each other. The first records in the list of records is + * considered the representative of the duplicate, and typically does not have it's duplicate flag set. + * The records' duplicate flag will be set appropriately as records are added. This behavior can be * turned off. * * At this time, this set does not track optical duplicates. @@ -88,8 +88,7 @@ public int add(final SAMRecord record) { if (0 < this.comparator.compare(this.representative, record)) { this.representative = record; } - } - else { + } else { this.representative = record; } @@ -108,7 +107,9 @@ private void sort() { if (setDuplicateFlag) { // reset duplicate flags for (final SAMRecord record : records) { - if (!record.getReadUnmappedFlag() && !record.isSecondaryOrSupplementary() && !record.getReadName().equals(representative.getReadName())) { + if (!record.getReadUnmappedFlag() + && !record.isSecondaryOrSupplementary() + && !record.getReadName().equals(representative.getReadName())) { record.setDuplicateReadFlag(true); } } @@ -116,8 +117,8 @@ private void sort() { } if (!records.get(0).equals(this.representative)) { - throw new SAMException("BUG: the representative was not the first record after sorting." - + "\nFIRST: " + records.get(0).getSAMString() + "\nSECOND: " + this.representative.getSAMString()); + throw new SAMException("BUG: the representative was not the first record after sorting." + "\nFIRST: " + + records.get(0).getSAMString() + "\nSECOND: " + this.representative.getSAMString()); } } needsSorting = false; // this could be in the if above if you think hard about it @@ -180,5 +181,7 @@ public boolean isEmpty() { /** * Controls if we should update the duplicate flag of the records in this set. */ - public void setDuplicateFlag(final boolean setDuplicateFlag) { this.setDuplicateFlag = setDuplicateFlag; } -} \ No newline at end of file + public void setDuplicateFlag(final boolean setDuplicateFlag) { + this.setDuplicateFlag = setDuplicateFlag; + } +} diff --git a/src/main/java/htsjdk/samtools/DuplicateSetIterator.java b/src/main/java/htsjdk/samtools/DuplicateSetIterator.java index 29ac78fdfd..02b34394fb 100644 --- a/src/main/java/htsjdk/samtools/DuplicateSetIterator.java +++ b/src/main/java/htsjdk/samtools/DuplicateSetIterator.java @@ -27,9 +27,7 @@ import htsjdk.samtools.util.Log; import htsjdk.samtools.util.ProgressLogger; import htsjdk.samtools.util.SortingCollection; - import java.io.File; -import java.util.Collections; /** * An iterator of sets of duplicates. Duplicates are defined currently by the ordering in @@ -52,16 +50,17 @@ public class DuplicateSetIterator implements CloseableIterator { public DuplicateSetIterator(final CloseableIterator iterator, final SAMFileHeader header) { this(iterator, header, false); } - public DuplicateSetIterator(final CloseableIterator iterator, - final SAMFileHeader header, - final boolean preSorted) { + + public DuplicateSetIterator( + final CloseableIterator iterator, final SAMFileHeader header, final boolean preSorted) { this(iterator, header, preSorted, null); } - public DuplicateSetIterator(final CloseableIterator iterator, - final SAMFileHeader header, - final boolean preSorted, - final SAMRecordDuplicateComparator comparator) { + public DuplicateSetIterator( + final CloseableIterator iterator, + final SAMFileHeader header, + final boolean preSorted, + final SAMRecordDuplicateComparator comparator) { this(iterator, header, preSorted, comparator, null); } @@ -70,11 +69,12 @@ public DuplicateSetIterator(final CloseableIterator iterator, * sorted but not actually sorted in the correct order, an exception during iteration will be thrown. Progress information will * be printed for sorting of the input if `log` is provided. */ - public DuplicateSetIterator(final CloseableIterator iterator, - final SAMFileHeader header, - final boolean preSorted, - final SAMRecordDuplicateComparator comparator, - final Log log) { + public DuplicateSetIterator( + final CloseableIterator iterator, + final SAMFileHeader header, + final boolean preSorted, + final SAMRecordDuplicateComparator comparator, + final Log log) { this.comparator = (comparator == null) ? new SAMRecordDuplicateComparator(header) : comparator; if (preSorted) { @@ -89,9 +89,8 @@ public DuplicateSetIterator(final CloseableIterator iterator, // Sort it! final int maxRecordsInRam = SAMFileWriterImpl.getDefaultMaxRecordsInRam(); final File tmpDir = new File(System.getProperty("java.io.tmpdir")); - final SortingCollection alignmentSorter = SortingCollection.newInstance(SAMRecord.class, - new BAMRecordCodec(header), this.comparator, - maxRecordsInRam, tmpDir); + final SortingCollection alignmentSorter = SortingCollection.newInstance( + SAMRecord.class, new BAMRecordCodec(header), this.comparator, maxRecordsInRam, tmpDir); while (iterator.hasNext()) { final SAMRecord record = iterator.next(); @@ -109,12 +108,11 @@ public DuplicateSetIterator(final CloseableIterator iterator, if (hasNext()) { this.duplicateSet.add(this.wrappedIterator.next()); } - } @Deprecated /** @deprecated Do not use this method as the first duplicate set will not be compared with this scoring strategy. - * Instead, provide a comparator to the constructor that has the scoring strategy set. */ + * Instead, provide a comparator to the constructor that has the scoring strategy set. */ public void setScoringStrategy(final DuplicateScoringStrategy.ScoringStrategy scoringStrategy) { this.comparator.setScoringStrategy(scoringStrategy); } @@ -147,8 +145,8 @@ public DuplicateSet next() { cmp = this.duplicateSet.add(record); if (0 < cmp) { - throw new SAMException("The input records were not sorted in duplicate order:\n" + - representative.getSAMString() + "\n" + record.getSAMString()); + throw new SAMException("The input records were not sorted in duplicate order:\n" + + representative.getSAMString() + "\n" + record.getSAMString()); } else if (cmp < 0) { duplicateSet = this.duplicateSet; this.duplicateSet = new DuplicateSet(this.comparator); @@ -162,7 +160,9 @@ public DuplicateSet next() { } @Override - public void close() { wrappedIterator.close(); } + public void close() { + wrappedIterator.close(); + } @Override public boolean hasNext() { @@ -171,5 +171,5 @@ public boolean hasNext() { // Does nothing! @Override - public void remove() { } + public void remove() {} } diff --git a/src/main/java/htsjdk/samtools/FileTruncatedException.java b/src/main/java/htsjdk/samtools/FileTruncatedException.java index 0adf799c5e..0a7f66802c 100644 --- a/src/main/java/htsjdk/samtools/FileTruncatedException.java +++ b/src/main/java/htsjdk/samtools/FileTruncatedException.java @@ -29,8 +29,7 @@ * @author alecw@broadinstitute.org */ public class FileTruncatedException extends SAMException { - public FileTruncatedException() { - } + public FileTruncatedException() {} public FileTruncatedException(final String s) { super(s); diff --git a/src/main/java/htsjdk/samtools/GenomicIndexUtil.java b/src/main/java/htsjdk/samtools/GenomicIndexUtil.java index 275444e113..1bb9d9f4d2 100644 --- a/src/main/java/htsjdk/samtools/GenomicIndexUtil.java +++ b/src/main/java/htsjdk/samtools/GenomicIndexUtil.java @@ -24,7 +24,6 @@ package htsjdk.samtools; import htsjdk.utils.ValidationUtils; - import java.util.BitSet; /** @@ -34,20 +33,19 @@ public class GenomicIndexUtil { /** * Reports the total amount of genomic data that any bin can index. */ - public static final int BIN_GENOMIC_SPAN = 512*1024*1024; + public static final int BIN_GENOMIC_SPAN = 512 * 1024 * 1024; /** * What is the starting bin for each level? */ - public static final int[] LEVEL_STARTS = {0,1,9,73,585,4681}; + public static final int[] LEVEL_STARTS = {0, 1, 9, 73, 585, 4681}; /** * Reports the maximum number of bins that can appear in a binning index. */ - public static final int MAX_BINS = 37450; // =(8^6-1)/7+1 - - public static final int MAX_LINEAR_INDEX_SIZE = MAX_BINS+1-LEVEL_STARTS[LEVEL_STARTS.length-1]; + public static final int MAX_BINS = 37450; // =(8^6-1)/7+1 + public static final int MAX_LINEAR_INDEX_SIZE = MAX_BINS + 1 - LEVEL_STARTS[LEVEL_STARTS.length - 1]; /** * E.g. for a SAMRecord with no genomic coordinate. @@ -60,10 +58,10 @@ public class GenomicIndexUtil { * @return the binning index level for the given bin */ public static int binTolevel(int bin) { - ValidationUtils.validateArg(bin >=0 && bin <= MAX_BINS, "Bin number must be >=0 and <= 37450"); + ValidationUtils.validateArg(bin >= 0 && bin <= MAX_BINS, "Bin number must be >=0 and <= 37450"); // As described in Tabix: fast retrieval of sequence features from generic TAB-delimited files. // doi: 10.1093/bioinformatics/btq671 - return (int) Math.floor(((Math.log((7*bin) + 1) / Math.log(2)) / 3)); + return (int) Math.floor(((Math.log((7 * bin) + 1) / Math.log(2)) / 3)); } /** @@ -73,10 +71,10 @@ public static int binTolevel(int bin) { * @return the size for a bin at the given level */ public static int levelToSize(int level) { - ValidationUtils.validateArg(level >=0 && level <= 5, "Level number must be >=0 and <= 5"); + ValidationUtils.validateArg(level >= 0 && level <= 5, "Level number must be >=0 and <= 5"); // As described in Tabix: fast retrieval of sequence features from generic TAB-delimited files. // doi: 10.1093/bioinformatics/btq671 - return (int) Math.pow(2, 29-(3*level)); + return (int) Math.pow(2, 29 - (3 * level)); } /** @@ -91,14 +89,10 @@ public static String getBinSummaryString(int bin) { final int level = binTolevel(bin); final int levelStart = LEVEL_STARTS[level]; final int binSize = levelToSize(level); - final int binStart = (bin-levelStart) * binSize; - return String.format("bin=%d, level=%d, first bin=%d, bin size=%,d bin range=(%,d-%,d)", - bin, - level, - levelStart, - binSize, - binStart, - binStart + binSize); + final int binStart = (bin - levelStart) * binSize; + return String.format( + "bin=%d, level=%d, first bin=%d, bin size=%,d bin range=(%,d-%,d)", + bin, level, levelStart, binSize, binStart, binStart + binSize); } /** @@ -107,15 +101,14 @@ public static String getBinSummaryString(int bin) { * @param beg 0-based start of read (inclusive) * @param end 0-based end of read (exclusive) */ - public static int regionToBin(final int beg, int end) - { + public static int regionToBin(final int beg, int end) { --end; - if (beg>>14 == end>>14) return ((1<<15)-1)/7 + (beg>>14); - if (beg>>17 == end>>17) return ((1<<12)-1)/7 + (beg>>17); - if (beg>>20 == end>>20) return ((1<<9)-1)/7 + (beg>>20); - if (beg>>23 == end>>23) return ((1<<6)-1)/7 + (beg>>23); - if (beg>>26 == end>>26) return ((1<<3)-1)/7 + (beg>>26); + if (beg >> 14 == end >> 14) return ((1 << 15) - 1) / 7 + (beg >> 14); + if (beg >> 17 == end >> 17) return ((1 << 12) - 1) / 7 + (beg >> 17); + if (beg >> 20 == end >> 20) return ((1 << 9) - 1) / 7 + (beg >> 20); + if (beg >> 23 == end >> 23) return ((1 << 6) - 1) / 7 + (beg >> 23); + if (beg >> 26 == end >> 26) return ((1 << 3) - 1) / 7 + (beg >> 26); return 0; } @@ -127,18 +120,17 @@ public static int regionToBin(final int beg, int end) * @param minShift minimum bin width (2^minShift) * @param binDepth number of levels in the binning scheme (including bin 0) */ - public static int regionToBin(final int beg, int end, final int minShift, final int binDepth) - { - final int maxShift = minShift + 3*(binDepth-1); + public static int regionToBin(final int beg, int end, final int minShift, final int binDepth) { + final int maxShift = minShift + 3 * (binDepth - 1); int binWidth = minShift; --end; while (binWidth < maxShift) { - if (beg>>binWidth == end>>binWidth) { - return ((1<< (maxShift - binWidth)) - 1)/7 + (beg>>binWidth); + if (beg >> binWidth == end >> binWidth) { + return ((1 << (maxShift - binWidth)) - 1) / 7 + (beg >> binWidth); } - binWidth+=3; + binWidth += 3; } return 0; @@ -155,19 +147,19 @@ public static int regionToBin(final int beg, int end, final int minShift, final */ public static BitSet regionToBins(final int startPos, final int endPos) { final int maxPos = 0x1FFFFFFF; - final int start = (startPos <= 0) ? 0 : (startPos-1) & maxPos; - final int end = (endPos <= 0) ? maxPos : (endPos-1) & maxPos; + final int start = (startPos <= 0) ? 0 : (startPos - 1) & maxPos; + final int end = (endPos <= 0) ? maxPos : (endPos - 1) & maxPos; if (start > end) { return null; } int k; final BitSet bins = new BitSet(GenomicIndexUtil.MAX_BINS); bins.set(0); - for (k = 1 + (start>>26); k <= 1 + (end>>26); ++k) bins.set(k); - for (k = 9 + (start>>23); k <= 9 + (end>>23); ++k) bins.set(k); - for (k = 73 + (start>>20); k <= 73 + (end>>20); ++k) bins.set(k); - for (k = 585 + (start>>17); k <= 585 + (end>>17); ++k) bins.set(k); - for (k = 4681 + (start>>14); k <= 4681 + (end>>14); ++k) bins.set(k); + for (k = 1 + (start >> 26); k <= 1 + (end >> 26); ++k) bins.set(k); + for (k = 9 + (start >> 23); k <= 9 + (end >> 23); ++k) bins.set(k); + for (k = 73 + (start >> 20); k <= 73 + (end >> 20); ++k) bins.set(k); + for (k = 585 + (start >> 17); k <= 585 + (end >> 17); ++k) bins.set(k); + for (k = 4681 + (start >> 14); k <= 4681 + (end >> 14); ++k) bins.set(k); return bins; } @@ -205,5 +197,4 @@ public static BitSet regionToBins(final int startPos, final int endPos, final in } return bins; } - } diff --git a/src/main/java/htsjdk/samtools/HighAccuracyDownsamplingIterator.java b/src/main/java/htsjdk/samtools/HighAccuracyDownsamplingIterator.java index 2dd3b6c5ee..447694733f 100644 --- a/src/main/java/htsjdk/samtools/HighAccuracyDownsamplingIterator.java +++ b/src/main/java/htsjdk/samtools/HighAccuracyDownsamplingIterator.java @@ -52,7 +52,8 @@ class HighAccuracyDownsamplingIterator extends DownsamplingIterator { private Set bufferedRecordsToKeep; /** Override method to make it clear that this iterator attempts to provide a higher accuracy of downsampling. */ - @Override public boolean isHigherAccuracy() { + @Override + public boolean isHigherAccuracy() { return true; } @@ -70,22 +71,24 @@ class HighAccuracyDownsamplingIterator extends DownsamplingIterator { * for 1/accuracy templates, so setting this to extremely small numbers is not advisable. */ public DownsamplingIterator setTargetAccuracy(final double accuracy) { - if (accuracy >= 1 || accuracy <= 1d/Integer.MAX_VALUE) throw new IllegalArgumentException("Illegal value. Must be 1/MAX_INT < accuracy < 1"); + if (accuracy >= 1 || accuracy <= 1d / Integer.MAX_VALUE) + throw new IllegalArgumentException("Illegal value. Must be 1/MAX_INT < accuracy < 1"); this.targetAccuracy = accuracy; return this; } /** Returns true if there is another record available post-downsampling, false otherwise. */ - @Override public boolean hasNext() { + @Override + public boolean hasNext() { return this.nextRecord != null || advance(); } /** Returns the next record from the iterator, or throws an exception if there is no next record. */ - @Override public SAMRecord next() { + @Override + public SAMRecord next() { if (this.nextRecord == null) { throw new NoSuchElementException("Call to next() when hasNext() == false"); - } - else { + } else { final SAMRecord retval = this.nextRecord; advance(); return retval; @@ -107,7 +110,9 @@ protected Iterator getUnderlyingIterator() { protected boolean advance() { this.nextRecord = null; - while (this.nextRecord == null && (this.bufferedRecords.hasNext() || bufferNextChunkOfRecords(getTargetProportion(), this.targetAccuracy))) { + while (this.nextRecord == null + && (this.bufferedRecords.hasNext() + || bufferNextChunkOfRecords(getTargetProportion(), this.targetAccuracy))) { final SAMRecord rec = this.bufferedRecords.next(); final String key = rec.getReadName(); final Boolean previous = decisions.get(key); @@ -116,16 +121,14 @@ protected boolean advance() { if (previous == null) { keepThisRecord = this.bufferedRecordsToKeep.contains(rec.getReadName()); decisions.put(key, keepThisRecord); - } - else { + } else { keepThisRecord = previous; } if (keepThisRecord) { this.nextRecord = rec; recordAcceptedRecord(); - } - else { + } else { recordDiscardedRecord(); } } @@ -154,7 +157,7 @@ protected boolean bufferNextChunkOfRecords(final double proportion, final double // Randomly shuffle a list of all the template names, and then remove some from the set final int templatesToDiscard = templatesRead - templatesToKeep; - final List tmp = new ArrayList(names); + final List tmp = new ArrayList(names); Collections.shuffle(tmp, this.random); for (int i = 0; i < templatesToDiscard; ++i) names.remove(tmp.get(i)); @@ -162,7 +165,7 @@ protected boolean bufferNextChunkOfRecords(final double proportion, final double this.bufferedRecordsToKeep = names; this.bufferedRecords = recs.iterator(); this.totalTemplates += templatesRead; - this.keptTemplates += names.size(); + this.keptTemplates += names.size(); return !recs.isEmpty(); } @@ -176,7 +179,8 @@ protected boolean bufferNextChunkOfRecords(final double proportion, final double protected int calculateTemplatesToKeep(final int templatesRead, final double proportion) { final double rawTemplatesToKeep = templatesRead * proportion; return (keptTemplates / (double) totalTemplates < proportion) - ? (int) Math.ceil(rawTemplatesToKeep) : (int) Math.floor(rawTemplatesToKeep); + ? (int) Math.ceil(rawTemplatesToKeep) + : (int) Math.floor(rawTemplatesToKeep); } /** @@ -184,7 +188,8 @@ protected int calculateTemplatesToKeep(final int templatesRead, final double pro * observed, so that templatesToRead new keep/reject decisions can be made. The records that are read are placed into recs * and _novel_ template names are placed into names. */ - protected void readFromUnderlyingIterator(final List recs, final Set names, final int templatesToRead) { + protected void readFromUnderlyingIterator( + final List recs, final Set names, final int templatesToRead) { while (this.underlyingIterator.hasNext() && names.size() < templatesToRead) { final SAMRecord rec = this.underlyingIterator.next(); recs.add(rec); diff --git a/src/main/java/htsjdk/samtools/HtsgetBAMFileReader.java b/src/main/java/htsjdk/samtools/HtsgetBAMFileReader.java index a161e00bc0..6aa5ee10c4 100644 --- a/src/main/java/htsjdk/samtools/HtsgetBAMFileReader.java +++ b/src/main/java/htsjdk/samtools/HtsgetBAMFileReader.java @@ -5,7 +5,6 @@ import htsjdk.samtools.util.*; import htsjdk.samtools.util.htsget.*; import htsjdk.samtools.util.zip.InflaterFactory; - import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; @@ -60,34 +59,24 @@ public class HtsgetBAMFileReader extends SamReader.ReaderImplementation { * @param useAsynchronousIO if true, use asynchronous I/O and prefetching * @param inflaterFactory InflaterFactory used by BlockCompressedInputStream */ - public static HtsgetBAMFileReader fromHtsgetURI(final HtsgetInputResource source, - final boolean eagerDecode, - final ValidationStringency validationStringency, - final SAMRecordFactory samRecordFactory, - final boolean useAsynchronousIO, - final InflaterFactory inflaterFactory) throws IOException, URISyntaxException { + public static HtsgetBAMFileReader fromHtsgetURI( + final HtsgetInputResource source, + final boolean eagerDecode, + final ValidationStringency validationStringency, + final SAMRecordFactory samRecordFactory, + final boolean useAsynchronousIO, + final InflaterFactory inflaterFactory) + throws IOException, URISyntaxException { HtsgetBAMFileReader reader; try { final URI htsgetUri = HtsgetBAMFileReader.convertHtsgetUriToHttps(source.uri); reader = new HtsgetBAMFileReader( - htsgetUri, - eagerDecode, - validationStringency, - samRecordFactory, - useAsynchronousIO, - inflaterFactory - ); + htsgetUri, eagerDecode, validationStringency, samRecordFactory, useAsynchronousIO, inflaterFactory); } catch (final RuntimeIOException e) { // Fall back to http if htsget server does not support https final URI htsgetUri = HtsgetBAMFileReader.convertHtsgetUriToHttp(source.uri); reader = new HtsgetBAMFileReader( - htsgetUri, - eagerDecode, - validationStringency, - samRecordFactory, - useAsynchronousIO, - inflaterFactory - ); + htsgetUri, eagerDecode, validationStringency, samRecordFactory, useAsynchronousIO, inflaterFactory); } return reader; } @@ -101,12 +90,20 @@ public static HtsgetBAMFileReader fromHtsgetURI(final HtsgetInputResource source * @param samRecordFactory SAM record factory * @param useAsynchronousIO if true, use asynchronous I/O and prefetching */ - public HtsgetBAMFileReader(final URI source, - final boolean eagerDecode, - final ValidationStringency validationStringency, - final SAMRecordFactory samRecordFactory, - final boolean useAsynchronousIO) throws IOException { - this(source, eagerDecode, validationStringency, samRecordFactory, useAsynchronousIO, BlockGunzipper.getDefaultInflaterFactory()); + public HtsgetBAMFileReader( + final URI source, + final boolean eagerDecode, + final ValidationStringency validationStringency, + final SAMRecordFactory samRecordFactory, + final boolean useAsynchronousIO) + throws IOException { + this( + source, + eagerDecode, + validationStringency, + samRecordFactory, + useAsynchronousIO, + BlockGunzipper.getDefaultInflaterFactory()); } /** @@ -119,12 +116,14 @@ public HtsgetBAMFileReader(final URI source, * @param useAsynchronousIO if true, use asynchronous I/O and prefetching * @param inflaterFactory InflaterFactory used by BlockCompressedInputStream */ - public HtsgetBAMFileReader(final URI source, - final boolean eagerDecode, - final ValidationStringency validationStringency, - final SAMRecordFactory samRecordFactory, - final boolean useAsynchronousIO, - final InflaterFactory inflaterFactory) throws IOException { + public HtsgetBAMFileReader( + final URI source, + final boolean eagerDecode, + final ValidationStringency validationStringency, + final SAMRecordFactory samRecordFactory, + final boolean useAsynchronousIO, + final InflaterFactory inflaterFactory) + throws IOException { this.mSource = source; this.mEagerDecode = eagerDecode; this.mValidationStringency = validationStringency; @@ -135,10 +134,10 @@ public HtsgetBAMFileReader(final URI source, final HtsgetRequest req = new HtsgetRequest(this.mSource).withDataClass(HtsgetClass.header); // Request only the header and use it to construct a SAMFileHeader for this reader try (final InputStream headerStream = req.getResponse().getDataStream()) { - final BinaryCodec headerCodec = new BinaryCodec( - new DataInputStream(this.mUseAsynchronousIO - ? new AsyncBlockCompressedInputStream(headerStream, this.mInflaterFactory) - : new BlockCompressedInputStream(headerStream, this.mInflaterFactory))); + final BinaryCodec headerCodec = new BinaryCodec(new DataInputStream( + this.mUseAsynchronousIO + ? new AsyncBlockCompressedInputStream(headerStream, this.mInflaterFactory) + : new BlockCompressedInputStream(headerStream, this.mInflaterFactory))); this.mFileHeader = BAMFileReader.readHeader(headerCodec, this.mValidationStringency, null); } @@ -310,15 +309,17 @@ public SAMFileSpan getFilePointerSpanningReads() { public CloseableIterator query(final QueryInterval[] intervals, final boolean contained) { QueryInterval.assertIntervalsOptimized(intervals); final List namedIntervals = Arrays.stream(intervals) - .map(i -> new Interval(this.mFileHeader.getSequence(i.referenceIndex).getSequenceName(), i.start, i.end)) - .collect(Collectors.toList()); + .map(i -> new Interval( + this.mFileHeader.getSequence(i.referenceIndex).getSequenceName(), i.start, i.end)) + .collect(Collectors.toList()); return this.query(namedIntervals, contained); } - public CloseableIterator query(final String sequence, final int start, final int end, final boolean contained) { + public CloseableIterator query( + final String sequence, final int start, final int end, final boolean contained) { return this.query( - Collections.singletonList(new Interval(sequence, start, end == -1 ? Integer.MAX_VALUE : end)), - contained); + Collections.singletonList(new Interval(sequence, start, end == -1 ? Integer.MAX_VALUE : end)), + contained); } /** @@ -337,19 +338,17 @@ public CloseableIterator query(final List intervals, final // POST request does not guarantee that all returned records are overlapped/contained // by requested intervals, so we still need to filter, but don't need to filter duplicates chainingIterator = new FilteringSamIterator( - new HtsgetBAMFileIterator( - new HtsgetPOSTRequest(this.mSource) - .withIntervals(intervals) - .withFormat(HtsgetFormat.BAM) - ), - new BAMQueryMultipleIntervalsIteratorFilter(intervals, contained)); + new HtsgetBAMFileIterator(new HtsgetPOSTRequest(this.mSource) + .withIntervals(intervals) + .withFormat(HtsgetFormat.BAM)), + new BAMQueryMultipleIntervalsIteratorFilter(intervals, contained)); } else { chainingIterator = new BAMQueryChainingIterator(intervals, contained); } final CloseableIterator queryIterator = this.mUseAsynchronousIO - ? new SAMRecordPrefetchingIterator(chainingIterator, READAHEAD_LIMIT) - : chainingIterator; + ? new SAMRecordPrefetchingIterator(chainingIterator, READAHEAD_LIMIT) + : chainingIterator; this.iterators.add(queryIterator); return queryIterator; } @@ -373,14 +372,14 @@ public CloseableIterator queryAlignmentStart(final String sequence, f return new EmptyBamIterator(); } else { final HtsgetRequest req = new HtsgetRequest(this.mSource) - .withFormat(HtsgetFormat.BAM) - .withInterval(new Interval(sequence, start, start + 1)); + .withFormat(HtsgetFormat.BAM) + .withInterval(new Interval(sequence, start, start + 1)); final CloseableIterator iterator = new HtsgetBAMFileIterator(req); final BAMStartingAtIteratorFilter filter = new BAMStartingAtIteratorFilter(referenceIndex, start); final CloseableIterator filteringIterator = new BAMQueryFilteringIterator(iterator, filter); final CloseableIterator queryIterator = this.mUseAsynchronousIO - ? new SAMRecordPrefetchingIterator(filteringIterator, READAHEAD_LIMIT) - : filteringIterator; + ? new SAMRecordPrefetchingIterator(filteringIterator, READAHEAD_LIMIT) + : filteringIterator; this.iterators.add(queryIterator); return queryIterator; } @@ -396,12 +395,12 @@ public CloseableIterator queryAlignmentStart(final String sequence, f @Override public CloseableIterator queryUnmapped() { final HtsgetRequest req = new HtsgetRequest(this.mSource) - .withFormat(HtsgetFormat.BAM) - .withInterval(HtsgetRequest.UNMAPPED_UNPLACED_INTERVAL); + .withFormat(HtsgetFormat.BAM) + .withInterval(HtsgetRequest.UNMAPPED_UNPLACED_INTERVAL); final CloseableIterator unmappedIterator = new HtsgetBAMFileIterator(req); final CloseableIterator queryIterator = this.mUseAsynchronousIO - ? new SAMRecordPrefetchingIterator(unmappedIterator, READAHEAD_LIMIT) - : unmappedIterator; + ? new SAMRecordPrefetchingIterator(unmappedIterator, READAHEAD_LIMIT) + : unmappedIterator; this.iterators.add(queryIterator); return queryIterator; } @@ -433,8 +432,8 @@ private BlockCompressedInputStream getRequestStream(final HtsgetRequest req) { final InputStream stream = resp.getDataStream(); final BlockCompressedInputStream compressedInputStream = this.mUseAsynchronousIO - ? new AsyncBlockCompressedInputStream(stream, this.mInflaterFactory) - : new BlockCompressedInputStream(stream, this.mInflaterFactory); + ? new AsyncBlockCompressedInputStream(stream, this.mInflaterFactory) + : new BlockCompressedInputStream(stream, this.mInflaterFactory); if (this.mCheckCRC) { compressedInputStream.setCheckCrcs(true); } @@ -449,11 +448,25 @@ private BlockCompressedInputStream getRequestStream(final HtsgetRequest req) { } public static URI convertHtsgetUriToHttps(final URI uri) throws URISyntaxException { - return new URI("https", uri.getUserInfo(), uri.getHost(), uri.getPort(), uri.getPath(), uri.getQuery(), uri.getFragment()); + return new URI( + "https", + uri.getUserInfo(), + uri.getHost(), + uri.getPort(), + uri.getPath(), + uri.getQuery(), + uri.getFragment()); } public static URI convertHtsgetUriToHttp(final URI uri) throws URISyntaxException { - return new URI("http", uri.getUserInfo(), uri.getHost(), uri.getPort(), uri.getPath(), uri.getQuery(), uri.getFragment()); + return new URI( + "http", + uri.getUserInfo(), + uri.getHost(), + uri.getPort(), + uri.getPath(), + uri.getQuery(), + uri.getFragment()); } private class HtsgetBAMFileIterator implements CloseableIterator { @@ -465,8 +478,7 @@ private class HtsgetBAMFileIterator implements CloseableIterator { public HtsgetBAMFileIterator(final HtsgetRequest req) { this.stream = HtsgetBAMFileReader.this.getRequestStream(req); this.bamRecordCodec = new BAMRecordCodec( - HtsgetBAMFileReader.this.mFileHeader, - HtsgetBAMFileReader.this.mSamRecordFactory); + HtsgetBAMFileReader.this.mFileHeader, HtsgetBAMFileReader.this.mSamRecordFactory); this.bamRecordCodec.setInputStream(new DataInputStream(this.stream)); this.advance(); } @@ -496,9 +508,7 @@ private SAMRecord getNextRecord() { final SAMRecord next = this.bamRecordCodec.decode(); if (HtsgetBAMFileReader.this.mReader != null && next != null) { - next.setFileSource(new SAMFileSource( - HtsgetBAMFileReader.this.mReader, - null)); + next.setFileSource(new SAMFileSource(HtsgetBAMFileReader.this.mReader, null)); } return next; } @@ -512,11 +522,12 @@ private void advance() { this.currentRecord.setValidationStringency(HtsgetBAMFileReader.this.mValidationStringency); if (HtsgetBAMFileReader.this.mValidationStringency != ValidationStringency.SILENT) { - final boolean firstErrorOnly = HtsgetBAMFileReader.this.mValidationStringency == ValidationStringency.STRICT; + final boolean firstErrorOnly = + HtsgetBAMFileReader.this.mValidationStringency == ValidationStringency.STRICT; SAMUtils.processValidationErrors( - this.currentRecord.isValid(firstErrorOnly), - this.samRecordIndex, - HtsgetBAMFileReader.this.mValidationStringency); + this.currentRecord.isValid(firstErrorOnly), + this.samRecordIndex, + HtsgetBAMFileReader.this.mValidationStringency); } } if (HtsgetBAMFileReader.this.mEagerDecode && this.currentRecord != null) { @@ -543,13 +554,13 @@ public BAMQueryChainingIterator(final List intervals, final boolean c this.intervals = intervals; this.contained = contained; this.iterators = intervals.stream() - .map(i -> new Lazy<>(() -> { - final HtsgetRequest req = new HtsgetRequest(HtsgetBAMFileReader.this.mSource) - .withFormat(HtsgetFormat.BAM) - .withInterval(i); - return new HtsgetBAMFileIterator(req); - })) - .iterator(); + .map(i -> new Lazy<>(() -> { + final HtsgetRequest req = new HtsgetRequest(HtsgetBAMFileReader.this.mSource) + .withFormat(HtsgetFormat.BAM) + .withInterval(i); + return new HtsgetBAMFileIterator(req); + })) + .iterator(); this.advanceIterator(); this.advance(); } @@ -591,10 +602,11 @@ private void advanceIterator() { return; } final Locatable currInterval = this.intervals.get(this.currentIntervalIndex); - final Locatable prevInterval = this.currentIntervalIndex == 0 ? null : this.intervals.get(this.currentIntervalIndex - 1); + final Locatable prevInterval = + this.currentIntervalIndex == 0 ? null : this.intervals.get(this.currentIntervalIndex - 1); this.currentIterator = new FilteringSamIterator( - this.iterators.next().get(), - new ConsecutiveDuplicateRecordFilter(currInterval, prevInterval, contained)); + this.iterators.next().get(), + new ConsecutiveDuplicateRecordFilter(currInterval, prevInterval, contained)); this.currentIntervalIndex++; } } @@ -611,7 +623,8 @@ private static class ConsecutiveDuplicateRecordFilter implements SamRecordFilter private final Locatable currInterval; private final boolean contained; - public ConsecutiveDuplicateRecordFilter(final Locatable currInterval, final Locatable prevInterval, final boolean contained) { + public ConsecutiveDuplicateRecordFilter( + final Locatable currInterval, final Locatable prevInterval, final boolean contained) { this.currInterval = currInterval; this.prevInterval = prevInterval; this.contained = contained; @@ -620,8 +633,8 @@ public ConsecutiveDuplicateRecordFilter(final Locatable currInterval, final Loca @Override public boolean filterOut(final SAMRecord record) { return record.getReadUnmappedFlag() && record.getAlignmentStart() != SAMRecord.NO_ALIGNMENT_START - ? !this.acceptUnmappedRecord(record) - : !this.acceptRecord(record); + ? !this.acceptUnmappedRecord(record) + : !this.acceptRecord(record); } @Override @@ -631,19 +644,17 @@ public boolean filterOut(final SAMRecord first, final SAMRecord second) { private boolean acceptRecord(final SAMRecord rec) { return this.contained - ? currInterval.contains(rec) && (prevInterval == null || !prevInterval.contains(rec)) - : currInterval.overlaps(rec) && (prevInterval == null || !prevInterval.overlaps(rec)); + ? currInterval.contains(rec) && (prevInterval == null || !prevInterval.contains(rec)) + : currInterval.overlaps(rec) && (prevInterval == null || !prevInterval.overlaps(rec)); } private boolean acceptUnmappedRecord(final SAMRecord rec) { final int start = rec.getStart(); - final boolean matchesCurrInterval = - rec.contigsMatch(currInterval) && - CoordMath.encloses(currInterval.getStart(), currInterval.getEnd(), start, start); - final boolean matchesPrevInterval = - prevInterval != null && - rec.contigsMatch(prevInterval) && - CoordMath.encloses(prevInterval.getStart(), prevInterval.getEnd(), start, start); + final boolean matchesCurrInterval = rec.contigsMatch(currInterval) + && CoordMath.encloses(currInterval.getStart(), currInterval.getEnd(), start, start); + final boolean matchesPrevInterval = prevInterval != null + && rec.contigsMatch(prevInterval) + && CoordMath.encloses(prevInterval.getStart(), prevInterval.getEnd(), start, start); return matchesCurrInterval && !matchesPrevInterval; } } @@ -656,8 +667,7 @@ public static class BAMQueryMultipleIntervalsIteratorFilter implements SamRecord ConsecutiveDuplicateRecordFilter filter; final boolean contained; - public BAMQueryMultipleIntervalsIteratorFilter(final List intervals, - final boolean contained) { + public BAMQueryMultipleIntervalsIteratorFilter(final List intervals, final boolean contained) { this.contained = contained; this.intervals = intervals.iterator(); this.filter = null; @@ -694,9 +704,11 @@ private static class BAMQueryFilteringIterator implements CloseableIterator iterator, final BAMIteratorFilter iteratorFilter) { + public BAMQueryFilteringIterator( + final CloseableIterator iterator, final BAMIteratorFilter iteratorFilter) { this.wrappedIterator = iterator; this.iteratorFilter = iteratorFilter; this.nextRecord = this.advance(); @@ -764,7 +776,6 @@ public SAMRecord next() { } @Override - public void close() { - } + public void close() {} } } diff --git a/src/main/java/htsjdk/samtools/IndexFileBuffer.java b/src/main/java/htsjdk/samtools/IndexFileBuffer.java index e8e421b759..f6b5dd29c9 100644 --- a/src/main/java/htsjdk/samtools/IndexFileBuffer.java +++ b/src/main/java/htsjdk/samtools/IndexFileBuffer.java @@ -8,10 +8,16 @@ */ interface IndexFileBuffer extends Closeable { void readBytes(final byte[] bytes); + int readInteger(); + long readLong(); + void skipBytes(final int count); + void seek(final long position); + long position(); + void close(); -} \ No newline at end of file +} diff --git a/src/main/java/htsjdk/samtools/IndexFileBufferFactory.java b/src/main/java/htsjdk/samtools/IndexFileBufferFactory.java index 4592ce060f..5dcfe086fb 100644 --- a/src/main/java/htsjdk/samtools/IndexFileBufferFactory.java +++ b/src/main/java/htsjdk/samtools/IndexFileBufferFactory.java @@ -3,7 +3,6 @@ import htsjdk.samtools.seekablestream.SeekableStream; import htsjdk.samtools.util.IOUtil; import htsjdk.samtools.util.RuntimeIOException; - import java.io.File; import java.io.IOException; @@ -17,15 +16,15 @@ static IndexFileBuffer getBuffer(File file, boolean enableMemoryMapping) { throw (new RuntimeIOException(ioe)); } - return isCompressed ? new CompressedIndexFileBuffer(file) : (enableMemoryMapping ? new MemoryMappedFileBuffer(file) : new RandomAccessFileBuffer(file)); + return isCompressed + ? new CompressedIndexFileBuffer(file) + : (enableMemoryMapping ? new MemoryMappedFileBuffer(file) : new RandomAccessFileBuffer(file)); } static IndexFileBuffer getBuffer(SeekableStream seekableStream) { boolean isCompressed; isCompressed = IOUtil.isGZIPInputStream(seekableStream); - return isCompressed ? - new CompressedIndexFileBuffer(seekableStream) : - new IndexStreamBuffer(seekableStream); + return isCompressed ? new CompressedIndexFileBuffer(seekableStream) : new IndexStreamBuffer(seekableStream); } } diff --git a/src/main/java/htsjdk/samtools/IndexStreamBuffer.java b/src/main/java/htsjdk/samtools/IndexStreamBuffer.java index 5486dbe9c0..cd403c2250 100644 --- a/src/main/java/htsjdk/samtools/IndexStreamBuffer.java +++ b/src/main/java/htsjdk/samtools/IndexStreamBuffer.java @@ -2,7 +2,6 @@ import htsjdk.samtools.seekablestream.SeekableStream; import htsjdk.samtools.util.RuntimeIOException; - import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -25,7 +24,9 @@ private static void readFully(final SeekableStream in, final byte[] buffer, fina if (readThisLoop == -1) break; read += readThisLoop; } - if (read != length) throw new RuntimeIOException("Expected to read " + length + " bytes, but expired stream after " + read + "."); + if (read != length) + throw new RuntimeIOException( + "Expected to read " + length + " bytes, but expired stream after " + read + "."); } public IndexStreamBuffer(final SeekableStream s) { @@ -36,8 +37,11 @@ public IndexStreamBuffer(final SeekableStream s) { @Override public void close() { - try { in.close(); } - catch (final IOException e) { throw new RuntimeIOException(e); } + try { + in.close(); + } catch (final IOException e) { + throw new RuntimeIOException(e); + } } @Override @@ -47,8 +51,11 @@ public void readBytes(final byte[] bytes) { @Override public void seek(final long position) { - try { in.seek(position); } - catch (final IOException e) { throw new RuntimeIOException(e); } + try { + in.seek(position); + } catch (final IOException e) { + throw new RuntimeIOException(e); + } } @Override @@ -66,20 +73,24 @@ public long readLong() { @Override public void skipBytes(final int count) { try { - for (int s = count; s > 0;) { - final int skipped = (int)in.skip(s); + for (int s = count; s > 0; ) { + final int skipped = (int) in.skip(s); if (skipped <= 0) { throw new RuntimeIOException("Failed to skip " + s); } s -= skipped; } - } catch (final IOException e) { throw new RuntimeIOException(e); } + } catch (final IOException e) { + throw new RuntimeIOException(e); + } } @Override public long position() { try { return (int) in.position(); - } catch (final IOException e) { throw new RuntimeIOException(e); } + } catch (final IOException e) { + throw new RuntimeIOException(e); + } } } diff --git a/src/main/java/htsjdk/samtools/LinearIndex.java b/src/main/java/htsjdk/samtools/LinearIndex.java index 7ebd6bee57..0b72e7ff32 100644 --- a/src/main/java/htsjdk/samtools/LinearIndex.java +++ b/src/main/java/htsjdk/samtools/LinearIndex.java @@ -68,26 +68,26 @@ public int size() { } public long get(final int index) { - return mIndexEntries[index-mIndexStart]; + return mIndexEntries[index - mIndexStart]; } public static int convertToLinearIndexOffset(final int contigPos) { - final int indexPos = (contigPos <= 0) ? 0 : contigPos-1; + final int indexPos = (contigPos <= 0) ? 0 : contigPos - 1; return indexPos >> BAM_LIDX_SHIFT; } /** - * Gets the minimum offset of any alignment start appearing in this index, according to the linear index. + * Gets the minimum offset of any alignment start appearing in this index, according to the linear index. * @param startPos Starting position for this query. * @return The minimum offset, in chunk format, of any read appearing in this position. */ public long getMinimumOffset(final int startPos) { - final int start = (startPos <= 0) ? 0 : startPos-1; + final int start = (startPos <= 0) ? 0 : startPos - 1; final int regionLinearBin = start >> BAM_LIDX_SHIFT; // System.out.println("# regionLinearBin: " + regionLinearBin); long minimumOffset = 0; - if (regionLinearBin-mIndexStart < mIndexEntries.length) - minimumOffset = mIndexEntries[regionLinearBin-mIndexStart]; + if (regionLinearBin - mIndexStart < mIndexEntries.length) + minimumOffset = mIndexEntries[regionLinearBin - mIndexStart]; return minimumOffset; } @@ -108,9 +108,9 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; LinearIndex that = (LinearIndex) o; - return mReferenceSequence == that.mReferenceSequence && - mIndexStart == that.mIndexStart && - Arrays.equals(mIndexEntries, that.mIndexEntries); + return mReferenceSequence == that.mReferenceSequence + && mIndexStart == that.mIndexStart + && Arrays.equals(mIndexEntries, that.mIndexEntries); } @Override diff --git a/src/main/java/htsjdk/samtools/MemoryMappedFileBuffer.java b/src/main/java/htsjdk/samtools/MemoryMappedFileBuffer.java index b26747df69..d53aec0555 100644 --- a/src/main/java/htsjdk/samtools/MemoryMappedFileBuffer.java +++ b/src/main/java/htsjdk/samtools/MemoryMappedFileBuffer.java @@ -1,9 +1,7 @@ package htsjdk.samtools; import htsjdk.samtools.util.RuntimeIOException; - import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.nio.ByteOrder; import java.nio.MappedByteBuffer; @@ -17,7 +15,7 @@ class MemoryMappedFileBuffer implements IndexFileBuffer { private MappedByteBuffer mFileBuffer; MemoryMappedFileBuffer(final File file) { - try(final FileChannel fileChannel = FileChannel.open(file.toPath(), StandardOpenOption.READ);) { + try (final FileChannel fileChannel = FileChannel.open(file.toPath(), StandardOpenOption.READ); ) { mFileBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0L, fileChannel.size()); mFileBuffer.order(ByteOrder.LITTLE_ENDIAN); } catch (final IOException exc) { diff --git a/src/main/java/htsjdk/samtools/MergingSamRecordIterator.java b/src/main/java/htsjdk/samtools/MergingSamRecordIterator.java index ece5735f78..24058b3e9e 100644 --- a/src/main/java/htsjdk/samtools/MergingSamRecordIterator.java +++ b/src/main/java/htsjdk/samtools/MergingSamRecordIterator.java @@ -24,7 +24,6 @@ package htsjdk.samtools; import htsjdk.samtools.util.CloseableIterator; - import java.util.Collection; import java.util.Map; import java.util.PriorityQueue; @@ -63,7 +62,8 @@ public MergingSamRecordIterator(final SamFileHeaderMerger headerMerger, final bo * @param headerMerger The merged header and contents of readers. * @param assumeSorted false ensures that the iterator checks the headers of the readers for appropriate sort order. */ - public MergingSamRecordIterator(final SamFileHeaderMerger headerMerger, Collection readers, final boolean assumeSorted) { + public MergingSamRecordIterator( + final SamFileHeaderMerger headerMerger, Collection readers, final boolean assumeSorted) { this.samHeaderMerger = headerMerger; this.sortOrder = headerMerger.getMergedHeader().getSortOrder(); this.comparator = getComparator(); @@ -74,8 +74,9 @@ public MergingSamRecordIterator(final SamFileHeaderMerger headerMerger, Collecti for (final SamReader reader : readers) { if (!samHeaderMerger.getHeaders().contains(reader.getFileHeader())) throw new SAMException("All iterators to be merged must be accounted for in the SAM header merger"); - if (!assumeSorted && this.sortOrder != SAMFileHeader.SortOrder.unsorted && - reader.getFileHeader().getSortOrder() != this.sortOrder) { + if (!assumeSorted + && this.sortOrder != SAMFileHeader.SortOrder.unsorted + && reader.getFileHeader().getSortOrder() != this.sortOrder) { throw new SAMException("Files are not compatible with sort order"); } } @@ -88,7 +89,10 @@ public MergingSamRecordIterator(final SamFileHeaderMerger headerMerger, Collecti * @param headerMerger The merged header and contents of readers. * @param iterators Iterator traversing over reader contents. */ - public MergingSamRecordIterator(final SamFileHeaderMerger headerMerger, final Map> iterators, final boolean assumeSorted) { + public MergingSamRecordIterator( + final SamFileHeaderMerger headerMerger, + final Map> iterators, + final boolean assumeSorted) { this(headerMerger, iterators.keySet(), assumeSorted); for (final Map.Entry> mapping : iterators.entrySet()) addIfNotEmpty(new ComparableSamRecordIterator(mapping.getKey(), mapping.getValue(), comparator)); @@ -96,8 +100,7 @@ public MergingSamRecordIterator(final SamFileHeaderMerger headerMerger, final Ma } private void startIterationIfRequired() { - if (initialized) - return; + if (initialized) return; for (final SamReader reader : readers) addIfNotEmpty(new ComparableSamRecordIterator(reader, reader.iterator(), comparator)); initialized = true; @@ -108,9 +111,9 @@ private void startIterationIfRequired() { */ @Override public void close() { - // Iterators not in the priority queue have already been closed; only close down the iterators that are still in the priority queue. - for (CloseableIterator iterator : pq) - iterator.close(); + // Iterators not in the priority queue have already been closed; only close down the iterators that are still in + // the priority queue. + for (CloseableIterator iterator : pq) iterator.close(); } /** Returns true if any of the underlying iterators has more records, otherwise false. */ @@ -135,7 +138,8 @@ public SAMRecord next() { if (this.samHeaderMerger.hasReadGroupCollisions()) { final String oldGroupId = (String) record.getAttribute(ReservedTagConstants.READ_GROUP_ID); if (oldGroupId != null) { - final String newGroupId = this.samHeaderMerger.getReadGroupId(iterator.getReader().getFileHeader(), oldGroupId); + final String newGroupId = + this.samHeaderMerger.getReadGroupId(iterator.getReader().getFileHeader(), oldGroupId); record.setAttribute(ReservedTagConstants.READ_GROUP_ID, newGroupId); } } @@ -144,7 +148,8 @@ public SAMRecord next() { if (this.samHeaderMerger.hasProgramGroupCollisions()) { final String oldGroupId = (String) record.getAttribute(ReservedTagConstants.PROGRAM_GROUP_ID); if (oldGroupId != null) { - final String newGroupId = this.samHeaderMerger.getProgramGroupId(iterator.getReader().getFileHeader(), oldGroupId); + final String newGroupId = this.samHeaderMerger.getProgramGroupId( + iterator.getReader().getFileHeader(), oldGroupId); record.setAttribute(ReservedTagConstants.PROGRAM_GROUP_ID, newGroupId); } } diff --git a/src/main/java/htsjdk/samtools/QueryInterval.java b/src/main/java/htsjdk/samtools/QueryInterval.java index a41819cbc0..386c62d6d9 100644 --- a/src/main/java/htsjdk/samtools/QueryInterval.java +++ b/src/main/java/htsjdk/samtools/QueryInterval.java @@ -1,7 +1,6 @@ package htsjdk.samtools; import htsjdk.samtools.util.CoordMath; - import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -18,7 +17,6 @@ public class QueryInterval implements Comparable { /** 1-based, inclusive. If <= 0, implies that the interval goes to the end of the reference sequence */ public final int end; - public QueryInterval(final int referenceIndex, final int start, final int end) { if (referenceIndex < 0) { throw new IllegalArgumentException("Invalid reference index " + referenceIndex); @@ -28,7 +26,6 @@ public QueryInterval(final int referenceIndex, final int start, final int end) { this.end = end; } - @Override public int compareTo(final QueryInterval other) { int comp = this.referenceIndex - other.referenceIndex; @@ -78,7 +75,6 @@ public static QueryInterval[] optimizeIntervals(final QueryInterval[] inputInter final List unique = new ArrayList(); QueryInterval previous = inputIntervals[0]; - for (int i = 1; i < inputIntervals.length; ++i) { final QueryInterval next = inputIntervals[i]; if (previous.endsAtStartOf(next) || previous.overlaps(next)) { @@ -102,16 +98,19 @@ public static QueryInterval[] optimizeIntervals(final QueryInterval[] inputInter public static void assertIntervalsOptimized(final QueryInterval[] intervals) { if (intervals.length == 0) return; for (int i = 1; i < intervals.length; ++i) { - final QueryInterval prev = intervals[i-1]; + final QueryInterval prev = intervals[i - 1]; final QueryInterval thisInterval = intervals[i]; if (prev.compareTo(thisInterval) >= 0) { - throw new IllegalArgumentException(String.format("List of intervals is not sorted: %s >= %s", prev, thisInterval)); + throw new IllegalArgumentException( + String.format("List of intervals is not sorted: %s >= %s", prev, thisInterval)); } if (prev.overlaps(thisInterval)) { - throw new IllegalArgumentException(String.format("List of intervals is not optimized: %s intersects %s", prev, thisInterval)); + throw new IllegalArgumentException( + String.format("List of intervals is not optimized: %s intersects %s", prev, thisInterval)); } if (prev.endsAtStartOf(thisInterval)) { - throw new IllegalArgumentException(String.format("List of intervals is not optimized: %s abuts %s", prev, thisInterval)); + throw new IllegalArgumentException( + String.format("List of intervals is not optimized: %s abuts %s", prev, thisInterval)); } } } diff --git a/src/main/java/htsjdk/samtools/RandomAccessFileBuffer.java b/src/main/java/htsjdk/samtools/RandomAccessFileBuffer.java index 3eb271a0ff..1d5be658f1 100644 --- a/src/main/java/htsjdk/samtools/RandomAccessFileBuffer.java +++ b/src/main/java/htsjdk/samtools/RandomAccessFileBuffer.java @@ -1,7 +1,6 @@ package htsjdk.samtools; import htsjdk.samtools.util.RuntimeIOException; - import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; @@ -20,7 +19,7 @@ */ class RandomAccessFileBuffer implements IndexFileBuffer { private static final int PAGE_SIZE = 4 * 1024; - private static final int PAGE_OFFSET_MASK = PAGE_SIZE-1; + private static final int PAGE_OFFSET_MASK = PAGE_SIZE - 1; private static final int PAGE_MASK = ~PAGE_OFFSET_MASK; private static final int INVALID_PAGE = 1; private final File mFile; @@ -53,7 +52,7 @@ public void readBytes(final byte[] bytes) { } while (resultLength > 0) { loadPage(mFilePointer); - final int pageOffset = (int)mFilePointer & PAGE_OFFSET_MASK; + final int pageOffset = (int) mFilePointer & PAGE_OFFSET_MASK; final int copyLength = Math.min(resultLength, PAGE_SIZE - pageOffset); System.arraycopy(mBuffer, pageOffset, bytes, resultOffset, copyLength); mFilePointer += copyLength; @@ -66,12 +65,12 @@ public void readBytes(final byte[] bytes) { public int readInteger() { // This takes advantage of the fact that integers in BAM index files are always 4-byte aligned. loadPage(mFilePointer); - final int pageOffset = (int)mFilePointer & PAGE_OFFSET_MASK; + final int pageOffset = (int) mFilePointer & PAGE_OFFSET_MASK; mFilePointer += 4; - return((mBuffer[pageOffset + 0] & 0xFF) | - ((mBuffer[pageOffset + 1] & 0xFF) << 8) | - ((mBuffer[pageOffset + 2] & 0xFF) << 16) | - ((mBuffer[pageOffset + 3] & 0xFF) << 24)); + return ((mBuffer[pageOffset + 0] & 0xFF) + | ((mBuffer[pageOffset + 1] & 0xFF) << 8) + | ((mBuffer[pageOffset + 2] & 0xFF) << 16) + | ((mBuffer[pageOffset + 3] & 0xFF) << 24)); } @Override @@ -113,7 +112,7 @@ public void close() { } private void loadPage(final long filePosition) { - final int page = (int)filePosition & PAGE_MASK; + final int page = (int) filePosition & PAGE_MASK; if (page == mCurrentPage) { return; } diff --git a/src/main/java/htsjdk/samtools/ReservedTagConstants.java b/src/main/java/htsjdk/samtools/ReservedTagConstants.java index c0d03b8c99..ba60ee5140 100644 --- a/src/main/java/htsjdk/samtools/ReservedTagConstants.java +++ b/src/main/java/htsjdk/samtools/ReservedTagConstants.java @@ -1,70 +1,69 @@ -/* - * The MIT License - * - * Copyright (c) 2009 The Broad Institute - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package htsjdk.samtools; - -/** - * Constants for tags used in our SAM/BAM files - */ -public class ReservedTagConstants { - public static final String READ_GROUP_ID = SAMTag.RG.name(); // Specified in the SAM spec doc - public static final String PROGRAM_GROUP_ID = SAMTag.PG.name(); // Specified in the SAM spec doc - - /** Present and set to 1 if a read is a noise read. */ - public static final String XN = "XN"; - - /** Number of nucleotide differences (Specified in the SAM spec doc) */ - public static final String NM = SAMTag.NM.name(); - - /** The sum of the mismatched qualities. */ - public static final String XQ = "XQ"; - - /** - * The name of an attribute which stores the 1-based index of the start of - * sequence within a read (in original orientation) that should be clipped - * or trimmed before alignment and downstream use. - * The region to be clipped extends from this position to the end of the read. - */ - public static final String XT = "XT"; - - /** The original sequence before 454 cafie and homopolymer correction */ - public static final String XS = "XS"; - - /** The Four54 edit string of 454 cafie and homopolymer corrections - *

-     *   editString ::= {base operator position [- position]}* ;  // Cafie needs 2 positions
-     *   base ::= A | T | G | C | N ;   // N only for undercall
-     *   operator ::= o | u | c ;       // o = Overcall, u = Undercall, c = Cafie.
-     *   position is 0 based position of the correction (assuming forward strand) .  Cafie positions are to-from.
-     *   For example: XF :Z:Gc4-6Nu11Co15 means a cafie correction moved a G from position 6 to 4,
-     *   an N was inserted for an undercall at position 11, and a C was removed as an overcall at position 15
-     */
-    public static final String XF = "XF";
-
-    /** The original pred quality scores before modifications such as 454 cafie and homopolymer correction */
-    public static final String OQ = SAMTag.OQ.name();
-
-    /** The original cigar before indel cleaning, or 454 cafie and homopolymer correction */
-    public static final String OC = "OC";
-
-}
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2009 The Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package htsjdk.samtools;
+
+/**
+ * Constants for tags used in our SAM/BAM files
+ */
+public class ReservedTagConstants {
+    public static final String READ_GROUP_ID = SAMTag.RG.name(); // Specified in the SAM spec doc
+    public static final String PROGRAM_GROUP_ID = SAMTag.PG.name(); // Specified in the SAM spec doc
+
+    /** Present and set to 1 if a read is a noise read. */
+    public static final String XN = "XN";
+
+    /** Number of nucleotide differences (Specified in the SAM spec doc) */
+    public static final String NM = SAMTag.NM.name();
+
+    /** The sum of the mismatched qualities. */
+    public static final String XQ = "XQ";
+
+    /**
+     * The name of an attribute which stores the 1-based index of the start of
+     * sequence within a read (in original orientation) that should be clipped
+     * or trimmed before alignment and downstream use.
+     * The region to be clipped extends from this position to the end of the read.
+     */
+    public static final String XT = "XT";
+
+    /** The original sequence before 454 cafie and homopolymer correction */
+    public static final String XS = "XS";
+
+    /** The Four54 edit string of 454 cafie and homopolymer corrections
+     * 
+     *   editString ::= {base operator position [- position]}* ;  // Cafie needs 2 positions
+     *   base ::= A | T | G | C | N ;   // N only for undercall
+     *   operator ::= o | u | c ;       // o = Overcall, u = Undercall, c = Cafie.
+     *   position is 0 based position of the correction (assuming forward strand) .  Cafie positions are to-from.
+     *   For example: XF :Z:Gc4-6Nu11Co15 means a cafie correction moved a G from position 6 to 4,
+     *   an N was inserted for an undercall at position 11, and a C was removed as an overcall at position 15
+     */
+    public static final String XF = "XF";
+
+    /** The original pred quality scores before modifications such as 454 cafie and homopolymer correction */
+    public static final String OQ = SAMTag.OQ.name();
+
+    /** The original cigar before indel cleaning, or 454 cafie and homopolymer correction */
+    public static final String OC = "OC";
+}
diff --git a/src/main/java/htsjdk/samtools/SAMBinaryTagAndUnsignedArrayValue.java b/src/main/java/htsjdk/samtools/SAMBinaryTagAndUnsignedArrayValue.java
index 36a8e40ac0..b293256193 100644
--- a/src/main/java/htsjdk/samtools/SAMBinaryTagAndUnsignedArrayValue.java
+++ b/src/main/java/htsjdk/samtools/SAMBinaryTagAndUnsignedArrayValue.java
@@ -33,9 +33,8 @@ public class SAMBinaryTagAndUnsignedArrayValue extends SAMBinaryTagAndValue {
     public SAMBinaryTagAndUnsignedArrayValue(final short tag, final Object value) {
         super(tag, value);
         if (!value.getClass().isArray() || value instanceof float[]) {
-            throw new IllegalArgumentException("Attribute type " + value.getClass() +
-                    " cannot be encoded as an unsigned array. Tag: " +
-                    SAMTag.makeStringTag(tag));
+            throw new IllegalArgumentException("Attribute type " + value.getClass()
+                    + " cannot be encoded as an unsigned array. Tag: " + SAMTag.makeStringTag(tag));
         }
     }
 
@@ -62,7 +61,6 @@ public SAMBinaryTagAndValue deepCopy() {
         return retval;
     }
 
-
     @Override
     public boolean isUnsignedArray() {
         return true;
diff --git a/src/main/java/htsjdk/samtools/SAMBinaryTagAndValue.java b/src/main/java/htsjdk/samtools/SAMBinaryTagAndValue.java
index 8389200401..c84bdc4752 100644
--- a/src/main/java/htsjdk/samtools/SAMBinaryTagAndValue.java
+++ b/src/main/java/htsjdk/samtools/SAMBinaryTagAndValue.java
@@ -58,8 +58,8 @@ public SAMBinaryTagAndValue(final short tag, final Object value) {
             throw new IllegalArgumentException("SAMBinaryTagAndValue value may not be null");
         }
         if (!isAllowedAttributeValue(value)) {
-            throw new IllegalArgumentException("Attribute type " + value.getClass() + " not supported. Tag: " +
-                    SAMTag.makeStringTag(tag));
+            throw new IllegalArgumentException(
+                    "Attribute type " + value.getClass() + " not supported. Tag: " + SAMTag.makeStringTag(tag));
         }
         this.tag = tag;
         this.value = value;
@@ -77,16 +77,16 @@ public SAMBinaryTagAndValue(final short tag, final Object value) {
     // Inspect the proposed value to determine if it is an allowed value type,
     // and if the value is in range.
     protected static boolean isAllowedAttributeValue(final Object value) {
-            if (value instanceof Byte ||
-                value instanceof Short ||
-                value instanceof Integer ||
-                value instanceof String ||
-                value instanceof Character ||
-                value instanceof Float ||
-                value instanceof byte[] ||
-                value instanceof short[] ||
-                value instanceof int[] ||
-                value instanceof float[]) {
+        if (value instanceof Byte
+                || value instanceof Short
+                || value instanceof Integer
+                || value instanceof String
+                || value instanceof Character
+                || value instanceof Float
+                || value instanceof byte[]
+                || value instanceof short[]
+                || value instanceof int[]
+                || value instanceof float[]) {
             return true;
         }
 
@@ -99,7 +99,8 @@ protected static boolean isAllowedAttributeValue(final Object value) {
         return false;
     }
 
-    @Override public boolean equals(final Object o) {
+    @Override
+    public boolean equals(final Object o) {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
         return typeSafeEquals((SAMBinaryTagAndValue) o);
@@ -111,30 +112,21 @@ private boolean typeSafeEquals(final SAMBinaryTagAndValue that) {
         if (this.valueEquals(that)) {
             if (this.next == null) return that.next == null;
             else return this.next.equals(that.next);
-        }
-        else {
+        } else {
             return false;
         }
     }
 
     private boolean valueEquals(SAMBinaryTagAndValue that) {
         if (this.value instanceof byte[]) {
-            return that.value instanceof byte[] ?
-                Arrays.equals((byte[])this.value, (byte[])that.value) : false;
-        }
-        else if (this.value instanceof short[]) {
-            return that.value instanceof short[] ?
-                    Arrays.equals((short[])this.value, (short[])that.value) : false;
-        }
-        else if (this.value instanceof int[]) {
-            return that.value instanceof int[] ?
-                    Arrays.equals((int[])this.value, (int[])that.value) : false;
-        }
-        else if (this.value instanceof float[]) {
-            return that.value instanceof float[] ?
-                    Arrays.equals((float[])this.value, (float[])that.value) : false;
-        }
-        else {
+            return that.value instanceof byte[] ? Arrays.equals((byte[]) this.value, (byte[]) that.value) : false;
+        } else if (this.value instanceof short[]) {
+            return that.value instanceof short[] ? Arrays.equals((short[]) this.value, (short[]) that.value) : false;
+        } else if (this.value instanceof int[]) {
+            return that.value instanceof int[] ? Arrays.equals((int[]) this.value, (int[]) that.value) : false;
+        } else if (this.value instanceof float[]) {
+            return that.value instanceof float[] ? Arrays.equals((float[]) this.value, (float[]) that.value) : false;
+        } else {
             // otherwise, the api limits the remaining possible value types to
             // immutable (String or boxed primitive) types
             return this.value.equals(that.value);
@@ -145,18 +137,14 @@ else if (this.value instanceof float[]) {
     public int hashCode() {
         int valueHash;
         if (this.value instanceof byte[]) {
-            valueHash = Arrays.hashCode((byte[])this.value);
-        }
-        else if (this.value instanceof short[]) {
-            valueHash = Arrays.hashCode((short[])this.value);
-        }
-        else if (this.value instanceof int[]) {
-            valueHash = Arrays.hashCode((int[])this.value);
-        }
-        else if (this.value instanceof float[]) {
-            valueHash = Arrays.hashCode((float[])this.value);
-        }
-        else {
+            valueHash = Arrays.hashCode((byte[]) this.value);
+        } else if (this.value instanceof short[]) {
+            valueHash = Arrays.hashCode((short[]) this.value);
+        } else if (this.value instanceof int[]) {
+            valueHash = Arrays.hashCode((int[]) this.value);
+        } else if (this.value instanceof float[]) {
+            valueHash = Arrays.hashCode((float[]) this.value);
+        } else {
             // otherwise, the api limits the remaining possible value types to
             // immutable (String or boxed primitive) types
             valueHash = value.hashCode();
@@ -189,17 +177,13 @@ protected Object cloneValue() {
 
         if (value instanceof byte[]) {
             valueClone = ((byte[]) value).clone();
-        }
-        else if (value instanceof short[]) {
+        } else if (value instanceof short[]) {
             valueClone = ((short[]) value).clone();
-        }
-        else if (value instanceof int[]) {
+        } else if (value instanceof int[]) {
             valueClone = ((int[]) value).clone();
-        }
-        else if (value instanceof float[]) {
+        } else if (value instanceof float[]) {
             valueClone = ((float[]) value).clone();
-        }
-        else {
+        } else {
             // otherwise, the api limits the remaining possible value types to
             // immutable (String or boxed primitive) types
             valueClone = value;
@@ -209,7 +193,9 @@ else if (value instanceof float[]) {
 
     // The methods below are for implementing a light-weight, single-direction linked list
 
-    public SAMBinaryTagAndValue getNext() { return this.next; }
+    public SAMBinaryTagAndValue getNext() {
+        return this.next;
+    }
 
     /** Inserts an item into the ordered list of attributes and returns the head of the list/sub-list */
     public SAMBinaryTagAndValue insert(final SAMBinaryTagAndValue attr) {
@@ -220,18 +206,15 @@ public SAMBinaryTagAndValue insert(final SAMBinaryTagAndValue attr) {
             // attr joins the list ahead of this element
             attr.next = this;
             return attr;
-        }
-        else if (this.tag == attr.tag) {
+        } else if (this.tag == attr.tag) {
             // attr replaces this in the list
             attr.next = this.next;
             return attr;
-        }
-        else if (this.next == null) {
+        } else if (this.next == null) {
             // attr gets stuck on the end
             this.next = attr;
             return this;
-        }
-        else {
+        } else {
             // attr gets inserted somewhere in the tail
             this.next = this.next.insert(attr);
             return this;
@@ -251,7 +234,7 @@ public SAMBinaryTagAndValue remove(final short tag) {
     public SAMBinaryTagAndValue find(final short tag) {
         if (this.tag == tag) return this;
         else if (this.tag > tag || this.next == null) return null;
-        else return this.next.find(tag); 
+        else return this.next.find(tag);
     }
 
     public boolean isUnsignedArray() {
diff --git a/src/main/java/htsjdk/samtools/SAMException.java b/src/main/java/htsjdk/samtools/SAMException.java
index add07456de..00d7d8b975 100644
--- a/src/main/java/htsjdk/samtools/SAMException.java
+++ b/src/main/java/htsjdk/samtools/SAMException.java
@@ -27,8 +27,7 @@
  * @author alecw@broadinstitute.org
  */
 public class SAMException extends RuntimeException {
-    public SAMException() {
-    }
+    public SAMException() {}
 
     public SAMException(final String s) {
         super(s);
diff --git a/src/main/java/htsjdk/samtools/SAMFileHeader.java b/src/main/java/htsjdk/samtools/SAMFileHeader.java
index 4796683ab2..b09077c226 100644
--- a/src/main/java/htsjdk/samtools/SAMFileHeader.java
+++ b/src/main/java/htsjdk/samtools/SAMFileHeader.java
@@ -23,12 +23,10 @@
  */
 package htsjdk.samtools;
 
-
 import htsjdk.beta.plugin.HtsHeader;
 import htsjdk.samtools.util.BufferedLineReader;
 import htsjdk.samtools.util.CollectionUtil;
 import htsjdk.samtools.util.Log;
-
 import java.io.StringWriter;
 import java.util.*;
 import java.util.function.Supplier;
@@ -36,13 +34,13 @@
 /**
  * Header information from a SAM or BAM file.
  */
-public class SAMFileHeader extends AbstractSAMHeaderRecord implements HtsHeader
-{
+public class SAMFileHeader extends AbstractSAMHeaderRecord implements HtsHeader {
     public static final String VERSION_TAG = "VN";
     public static final String SORT_ORDER_TAG = "SO";
     public static final String GROUP_ORDER_TAG = "GO";
     public static final String CURRENT_VERSION = "1.6";
-    public static final Set ACCEPTABLE_VERSIONS = CollectionUtil.makeSet("1.0", "1.3", "1.4", "1.5", CURRENT_VERSION );
+    public static final Set ACCEPTABLE_VERSIONS =
+            CollectionUtil.makeSet("1.0", "1.3", "1.4", "1.5", CURRENT_VERSION);
 
     private SortOrder sortOrder = null;
     private GroupOrder groupOrder = null;
@@ -93,7 +91,9 @@ public SAMRecordComparator getComparatorInstance() {
     }
 
     public enum GroupOrder {
-        none, query, reference
+        none,
+        query,
+        reference
     }
 
     private List mReadGroups = new ArrayList<>();
@@ -101,7 +101,7 @@ public enum GroupOrder {
     private final Map mReadGroupMap = new HashMap<>();
     private final Map mProgramRecordMap = new HashMap<>();
     private SAMSequenceDictionary mSequenceDictionary = new SAMSequenceDictionary();
-    final private List mComments = new ArrayList<>();
+    private final List mComments = new ArrayList<>();
     private final List mValidationErrors = new ArrayList<>();
 
     public SAMFileHeader() {
@@ -186,8 +186,8 @@ public void setReadGroups(final List readGroups) {
 
     public void addReadGroup(final SAMReadGroupRecord readGroup) {
         if (mReadGroupMap.containsKey(readGroup.getReadGroupId())) {
-            throw new IllegalArgumentException("Read group with group id " +
-                readGroup.getReadGroupId() + " already exists in SAMFileHeader!");
+            throw new IllegalArgumentException(
+                    "Read group with group id " + readGroup.getReadGroupId() + " already exists in SAMFileHeader!");
         }
         mReadGroups.add(readGroup);
         mReadGroupMap.put(readGroup.getReadGroupId(), readGroup);
@@ -199,8 +199,8 @@ public List getProgramRecords() {
 
     public void addProgramRecord(final SAMProgramRecord programRecord) {
         if (mProgramRecordMap.containsKey(programRecord.getProgramGroupId())) {
-            throw new IllegalArgumentException("Program record with group id " +
-                programRecord.getProgramGroupId() + " already exists in SAMFileHeader!");
+            throw new IllegalArgumentException("Program record with group id " + programRecord.getProgramGroupId()
+                    + " already exists in SAMFileHeader!");
         }
         this.mProgramRecords.add(programRecord);
         this.mProgramRecordMap.put(programRecord.getProgramGroupId(), programRecord);
@@ -281,7 +281,6 @@ public void setGroupOrder(final GroupOrder go) {
         super.setAttribute(GROUP_ORDER_TAG, go.name());
     }
 
-
     /**
      * Set the given value for the attribute named 'key'.  Replaces an existing value, if any.
      * If value is null, the attribute is removed.
@@ -323,10 +322,14 @@ public void setAttribute(final String key, final String value) {
     }
 
     /** @deprecated since May 1st 2019 - text version of header is no longer stored. */
-    @Deprecated public String getTextHeader() {  return null; }
+    @Deprecated
+    public String getTextHeader() {
+        return null;
+    }
 
     /** @deprecated since May 1st 2019 - text version of header is no longer stored. */
-    @Deprecated public void setTextHeader(final String textHeader) { }
+    @Deprecated
+    public void setTextHeader(final String textHeader) {}
 
     public List getComments() {
         return Collections.unmodifiableList(mComments);
@@ -339,7 +342,6 @@ public void addComment(String comment) {
         mComments.add(comment);
     }
 
-
     /**
      * Replace existing comments with the contents of the given collection.
      */
@@ -377,8 +379,9 @@ public boolean equals(final Object o) {
         if (mProgramRecords != null ? !mProgramRecords.equals(that.mProgramRecords) : that.mProgramRecords != null)
             return false;
         if (mReadGroups != null ? !mReadGroups.equals(that.mReadGroups) : that.mReadGroups != null) return false;
-        if (mSequenceDictionary != null ? !mSequenceDictionary.equals(that.mSequenceDictionary) : that.mSequenceDictionary != null)
-            return false;
+        if (mSequenceDictionary != null
+                ? !mSequenceDictionary.equals(that.mSequenceDictionary)
+                : that.mSequenceDictionary != null) return false;
 
         return true;
     }
@@ -432,7 +435,8 @@ public String getNonCollidingId(final String recordId) {
                 // our old process of just counting from 0 upward and adding that to the previous id led to 1000s of
                 // calls idsThatAreAlreadyTaken.contains() just to resolve 1 collision when merging 1000s of similarly
                 // processed bams.
-                while (idsThatAreAlreadyTaken.contains(newId = recordId + "." + SamFileHeaderMerger.positiveFourDigitBase36Str(recordCounter++)))
+                while (idsThatAreAlreadyTaken.contains(
+                        newId = recordId + "." + SamFileHeaderMerger.positiveFourDigitBase36Str(recordCounter++)))
                     ;
 
                 idsThatAreAlreadyTaken.add(newId);
diff --git a/src/main/java/htsjdk/samtools/SAMFileWriter.java b/src/main/java/htsjdk/samtools/SAMFileWriter.java
index 68c9cc1abc..d312ab1ced 100644
--- a/src/main/java/htsjdk/samtools/SAMFileWriter.java
+++ b/src/main/java/htsjdk/samtools/SAMFileWriter.java
@@ -23,9 +23,8 @@
  */
 package htsjdk.samtools;
 
-import java.io.Closeable;
-
 import htsjdk.samtools.util.ProgressLoggerInterface;
+import java.io.Closeable;
 
 /**
  * Interface for SAMText and BAM file writers.  Clients need not care which they write to,
@@ -33,23 +32,24 @@
  */
 public interface SAMFileWriter extends Closeable {
 
-	void addAlignment(SAMRecord alignment);
+    void addAlignment(SAMRecord alignment);
 
     SAMFileHeader getFileHeader();
 
-	/**
-	 * Sets a ProgressLogger on this writer. This is useful when pulling, for instance, from a
-	 * SortingCollection.
-	 */
-	void setProgressLogger(final ProgressLoggerInterface progress);
+    /**
+     * Sets a ProgressLogger on this writer. This is useful when pulling, for instance, from a
+     * SortingCollection.
+     */
+    void setProgressLogger(final ProgressLoggerInterface progress);
 
-	/** If true writers that are writing pre-sorted records should check the order during writing. */
-	default void setSortOrderChecking(final boolean check) {
-		throw new UnsupportedOperationException("Operation not supported on " + getClass().getName());
-	}
+    /** If true writers that are writing pre-sorted records should check the order during writing. */
+    default void setSortOrderChecking(final boolean check) {
+        throw new UnsupportedOperationException(
+                "Operation not supported on " + getClass().getName());
+    }
 
     /**
-     * Must be called to flush or file will likely be defective. 
+     * Must be called to flush or file will likely be defective.
      */
     @Override
     void close();
diff --git a/src/main/java/htsjdk/samtools/SAMFileWriterFactory.java b/src/main/java/htsjdk/samtools/SAMFileWriterFactory.java
index 0a8b4a0cbd..54d2f5690c 100644
--- a/src/main/java/htsjdk/samtools/SAMFileWriterFactory.java
+++ b/src/main/java/htsjdk/samtools/SAMFileWriterFactory.java
@@ -23,6 +23,8 @@
  */
 package htsjdk.samtools;
 
+import static htsjdk.samtools.SamReader.Type.*;
+
 import htsjdk.samtools.cram.ref.CRAMReferenceSource;
 import htsjdk.samtools.cram.ref.ReferenceSource;
 import htsjdk.samtools.cram.structure.CRAMEncodingStrategy;
@@ -33,20 +35,18 @@
 import htsjdk.samtools.util.Md5CalculatingOutputStream;
 import htsjdk.samtools.util.RuntimeIOException;
 import htsjdk.samtools.util.zip.DeflaterFactory;
-
 import java.io.File;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.zip.Deflater;
-import static htsjdk.samtools.SamReader.Type.*;
 
 /**
  * Create a writer for writing SAM, BAM, or CRAM files.
  */
 public class SAMFileWriterFactory implements Cloneable {
-    private final static Log log = Log.getInstance(SAMFileWriterFactory.class);
+    private static final Log log = Log.getInstance(SAMFileWriterFactory.class);
     private static boolean defaultCreateIndexWhileWriting = Defaults.CREATE_INDEX;
     private boolean createIndex = defaultCreateIndexWhileWriting;
     private static boolean defaultCreateMd5File = Defaults.CREATE_MD5;
@@ -57,18 +57,18 @@ public class SAMFileWriterFactory implements Cloneable {
     private File tmpDir;
     /** compression level 0: min 9:max */
     private int compressionLevel = BlockCompressedOutputStream.getDefaultCompressionLevel();
+
     private SamFlagField samFlagFieldOutput = SamFlagField.NONE;
     private Integer maxRecordsInRam = null;
     private DeflaterFactory deflaterFactory = BlockCompressedOutputStream.getDefaultDeflaterFactory();
     private CRAMEncodingStrategy cramEncodingStrategy = new CRAMEncodingStrategy();
 
     /** simple constructor */
-    public SAMFileWriterFactory() {
-    }
-    
+    public SAMFileWriterFactory() {}
+
     /** copy constructor */
-    public SAMFileWriterFactory( final SAMFileWriterFactory other) {
-        if( other == null ) throw new IllegalArgumentException("SAMFileWriterFactory(null)");
+    public SAMFileWriterFactory(final SAMFileWriterFactory other) {
+        if (other == null) throw new IllegalArgumentException("SAMFileWriterFactory(null)");
         this.createIndex = other.createIndex;
         this.createMd5File = other.createMd5File;
         this.useAsyncIo = other.useAsyncIo;
@@ -79,7 +79,7 @@ public SAMFileWriterFactory( final SAMFileWriterFactory other) {
         this.maxRecordsInRam = other.maxRecordsInRam;
         this.cramEncodingStrategy = other.cramEncodingStrategy;
     }
-    
+
     @Override
     public SAMFileWriterFactory clone() {
         return new SAMFileWriterFactory(this);
@@ -112,8 +112,8 @@ public SAMFileWriterFactory setCreateMd5File(final boolean createMd5File) {
      * Set the deflater factory used by BAM writers created by this writer factory. Must not be null.
      * If this method is not called, the default  {@link DeflaterFactory} is used which creates the default JDK {@link Deflater}.
      * This method returns the SAMFileWriterFactory itself. */
-    public SAMFileWriterFactory setDeflaterFactory(final DeflaterFactory deflaterFactory){
-        if (deflaterFactory == null){
+    public SAMFileWriterFactory setDeflaterFactory(final DeflaterFactory deflaterFactory) {
+        if (deflaterFactory == null) {
             throw new IllegalArgumentException("null deflater factory");
         }
         this.deflaterFactory = deflaterFactory;
@@ -125,11 +125,11 @@ public SAMFileWriterFactory setCompressionLevel(final int compressionLevel) {
         this.compressionLevel = Math.min(9, Math.max(0, compressionLevel));
         return this;
     }
-    
+
     public int getCompressionLevel() {
         return compressionLevel;
     }
-    
+
     /**
      * Sets the default for subsequent SAMFileWriterFactories
      * that do not specify whether to create an index.
@@ -297,8 +297,8 @@ public SAMFileWriter makeBAMWriter(final SAMFileHeader header, final boolean pre
      * @param outputFile       where to write the output.
      * @param compressionLevel Override default compression level with the given value, between 0 (fastest) and 9 (smallest).
      */
-    public SAMFileWriter makeBAMWriter(final SAMFileHeader header, final boolean presorted, final File outputFile,
-                                       final int compressionLevel) {
+    public SAMFileWriter makeBAMWriter(
+            final SAMFileHeader header, final boolean presorted, final File outputFile, final int compressionLevel) {
         return makeBAMWriter(header, presorted, outputFile.toPath(), compressionLevel);
     }
 
@@ -310,19 +310,22 @@ public SAMFileWriter makeBAMWriter(final SAMFileHeader header, final boolean pre
      * @param outputPath       where to write the output.
      * @param compressionLevel Override default compression level with the given value, between 0 (fastest) and 9 (smallest).
      */
-    public SAMFileWriter makeBAMWriter(final SAMFileHeader header, final boolean presorted, final Path outputPath,
-        final int compressionLevel) {
+    public SAMFileWriter makeBAMWriter(
+            final SAMFileHeader header, final boolean presorted, final Path outputPath, final int compressionLevel) {
         try {
             final boolean createMd5File = this.createMd5File && IOUtil.isRegularPath(outputPath);
             if (this.createMd5File && !createMd5File) {
-                log.warn("Cannot create MD5 file for BAM because output file is not a regular file: " + outputPath.toUri());
+                log.warn("Cannot create MD5 file for BAM because output file is not a regular file: "
+                        + outputPath.toUri());
             }
             OutputStream os = IOUtil.maybeBufferOutputStream(Files.newOutputStream(outputPath), bufferSize);
-            if (createMd5File) os = new Md5CalculatingOutputStream(os, IOUtil.addExtension(outputPath,".md5"));
-            final BAMFileWriter ret = new BAMFileWriter(os, outputPath.toUri().toString(), compressionLevel, deflaterFactory);
+            if (createMd5File) os = new Md5CalculatingOutputStream(os, IOUtil.addExtension(outputPath, ".md5"));
+            final BAMFileWriter ret =
+                    new BAMFileWriter(os, outputPath.toUri().toString(), compressionLevel, deflaterFactory);
             final boolean createIndex = this.createIndex && IOUtil.isRegularPath(outputPath);
             if (this.createIndex && !createIndex) {
-                log.warn("Cannot create index for BAM because output file is not a regular file: " + outputPath.toUri());
+                log.warn(
+                        "Cannot create index for BAM because output file is not a regular file: " + outputPath.toUri());
             }
             initializeBAMWriter(ret, header, presorted, createIndex);
 
@@ -333,7 +336,11 @@ public SAMFileWriter makeBAMWriter(final SAMFileHeader header, final boolean pre
         }
     }
 
-    private void initializeBAMWriter(final BAMFileWriter writer, final SAMFileHeader header, final boolean presorted, final boolean createIndex) {
+    private void initializeBAMWriter(
+            final BAMFileWriter writer,
+            final SAMFileHeader header,
+            final boolean presorted,
+            final boolean createIndex) {
         writer.setSortOrder(header.getSortOrder(), presorted);
         if (maxRecordsInRam != null) {
             writer.setMaxRecordsInRam(maxRecordsInRam);
@@ -373,12 +380,12 @@ public SAMFileWriter makeSAMWriter(final SAMFileHeader header, final boolean pre
         }
         try {
             final SAMTextWriter ret = this.createMd5File
-                    ? new SAMTextWriter(new Md5CalculatingOutputStream(Files.newOutputStream(outputPath),
-                          IOUtil.addExtension(outputPath, ".md5")), samFlagFieldOutput)
-                    : new SAMTextWriter(null == outputPath
-                                        ? null
-                                        : Files.newOutputStream(outputPath),
-                                        samFlagFieldOutput);
+                    ? new SAMTextWriter(
+                            new Md5CalculatingOutputStream(
+                                    Files.newOutputStream(outputPath), IOUtil.addExtension(outputPath, ".md5")),
+                            samFlagFieldOutput)
+                    : new SAMTextWriter(
+                            null == outputPath ? null : Files.newOutputStream(outputPath), samFlagFieldOutput);
             return initWriter(header, presorted, ret);
         } catch (final IOException ioe) {
             throw new RuntimeIOException("Error opening file: " + outputPath.toUri(), ioe);
@@ -414,9 +421,11 @@ public SAMFileWriter makeSAMWriter(final SAMFileHeader header, final boolean pre
      * @param stream    the stream to write records to.  Note that this method does not buffer the stream, so the
      *                  caller must buffer if desired.  Note that PrintStream is buffered.
      */
-
     public SAMFileWriter makeBAMWriter(final SAMFileHeader header, final boolean presorted, final OutputStream stream) {
-        return initWriter(header, presorted, new BAMFileWriter(stream, (File)null, this.getCompressionLevel(), this.deflaterFactory));
+        return initWriter(
+                header,
+                presorted,
+                new BAMFileWriter(stream, (File) null, this.getCompressionLevel(), this.deflaterFactory));
     }
 
     /**
@@ -425,9 +434,8 @@ public SAMFileWriter makeBAMWriter(final SAMFileHeader header, final boolean pre
      * @param presorted if true, SAMRecords must be added to the SAMFileWriter in order that agrees with header.sortOrder.
      * @param writer    SAM or BAM writer to initialize and maybe wrap.
      */
-
-    private SAMFileWriter initWriter(final SAMFileHeader header, final boolean presorted,
-                                     final SAMFileWriterImpl writer) {
+    private SAMFileWriter initWriter(
+            final SAMFileHeader header, final boolean presorted, final SAMFileWriterImpl writer) {
         writer.setSortOrder(header.getSortOrder(), presorted);
         if (maxRecordsInRam != null) {
             writer.setMaxRecordsInRam(maxRecordsInRam);
@@ -447,8 +455,9 @@ private SAMFileWriter initWriter(final SAMFileHeader header, final boolean preso
      * @param outputFile where to write the output.  Must end with .sam or .bam.
      * @return SAM or BAM writer based on file extension of outputFile.
      */
-    public SAMFileWriter makeSAMOrBAMWriter(final SAMFileHeader header, final boolean presorted, final File outputFile) {
-       return makeSAMOrBAMWriter(header, presorted, outputFile.toPath());
+    public SAMFileWriter makeSAMOrBAMWriter(
+            final SAMFileHeader header, final boolean presorted, final File outputFile) {
+        return makeSAMOrBAMWriter(header, presorted, outputFile.toPath());
     }
 
     /**
@@ -459,13 +468,15 @@ public SAMFileWriter makeSAMOrBAMWriter(final SAMFileHeader header, final boolea
      * @param outputPath where to write the output.  Must end with .sam or .bam.
      * @return SAM or BAM writer based on file extension of outputPath.
      */
-    public SAMFileWriter makeSAMOrBAMWriter(final SAMFileHeader header, final boolean presorted, final Path outputPath) {
+    public SAMFileWriter makeSAMOrBAMWriter(
+            final SAMFileHeader header, final boolean presorted, final Path outputPath) {
         final String filename = outputPath.getFileName().toString();
         if (SAM_TYPE.hasValidFileExtension(filename)) {
             return makeSAMWriter(header, presorted, outputPath);
         } else {
             if (!BAM_TYPE.hasValidFileExtension(filename)) {
-                log.info("Unknown file extension, assuming BAM format when writing file: " + outputPath.toUri().toString());
+                log.info("Unknown file extension, assuming BAM format when writing file: "
+                        + outputPath.toUri().toString());
             }
             return makeBAMWriter(header, presorted, outputPath);
         }
@@ -483,8 +494,9 @@ public SAMFileWriter makeSAMOrBAMWriter(final SAMFileHeader header, final boolea
      * @return SAMFileWriter appropriate for SAM and CRAM file types specified in outputFile, or a BAM writer for all other types
      *
      */
-    public SAMFileWriter makeWriter(final SAMFileHeader header, final boolean presorted, final File outputFile, final File referenceFasta) {
-        return makeWriter(header, presorted, IOUtil.toPath( outputFile ), IOUtil.toPath(referenceFasta));
+    public SAMFileWriter makeWriter(
+            final SAMFileHeader header, final boolean presorted, final File outputFile, final File referenceFasta) {
+        return makeWriter(header, presorted, IOUtil.toPath(outputFile), IOUtil.toPath(referenceFasta));
     }
 
     /**
@@ -499,8 +511,9 @@ public SAMFileWriter makeWriter(final SAMFileHeader header, final boolean presor
      * @deprecated since 6/18, use {@link #makeWriter(SAMFileHeader, boolean, Path, Path)} instead
      */
     @Deprecated
-    public SAMFileWriter makeWriter(final SAMFileHeader header, final boolean presorted, final Path outputPath, final File referenceFasta) {
-        return makeWriter(header, presorted, outputPath, IOUtil.toPath( referenceFasta ));
+    public SAMFileWriter makeWriter(
+            final SAMFileHeader header, final boolean presorted, final Path outputPath, final File referenceFasta) {
+        return makeWriter(header, presorted, outputPath, IOUtil.toPath(referenceFasta));
     }
 
     /**
@@ -514,12 +527,13 @@ public SAMFileWriter makeWriter(final SAMFileHeader header, final boolean presor
      * @return SAMFileWriter appropriate for the file type specified in outputPath
      *
      */
-    public SAMFileWriter makeWriter(final SAMFileHeader header, final boolean presorted, final Path outputPath, final Path referenceFasta) {
+    public SAMFileWriter makeWriter(
+            final SAMFileHeader header, final boolean presorted, final Path outputPath, final Path referenceFasta) {
         final String filename = outputPath.getFileName().toString();
         if (CRAM_TYPE.hasValidFileExtension(filename)) {
             return makeCRAMWriter(header, presorted, outputPath, referenceFasta);
         } else {
-            return makeSAMOrBAMWriter (header, presorted, outputPath);
+            return makeSAMOrBAMWriter(header, presorted, outputPath);
         }
     }
 
@@ -534,8 +548,9 @@ public SAMFileWriter makeWriter(final SAMFileHeader header, final boolean presor
      * @param referenceFasta reference sequence file
      * @return CRAMFileWriter
      */
-    public CRAMFileWriter makeCRAMWriter(final SAMFileHeader header, final OutputStream stream, final File referenceFasta) {
-        return makeCRAMWriter(header, stream, IOUtil.toPath( referenceFasta ));
+    public CRAMFileWriter makeCRAMWriter(
+            final SAMFileHeader header, final OutputStream stream, final File referenceFasta) {
+        return makeCRAMWriter(header, stream, IOUtil.toPath(referenceFasta));
     }
 
     /**
@@ -549,7 +564,8 @@ public CRAMFileWriter makeCRAMWriter(final SAMFileHeader header, final OutputStr
      * @param referenceFasta reference sequence file
      * @return CRAMFileWriter
      */
-    public CRAMFileWriter makeCRAMWriter(final SAMFileHeader header, final OutputStream stream, final Path referenceFasta) {
+    public CRAMFileWriter makeCRAMWriter(
+            final SAMFileHeader header, final OutputStream stream, final Path referenceFasta) {
         return new CRAMFileWriter(
                 cramEncodingStrategy,
                 stream,
@@ -573,7 +589,7 @@ public CRAMFileWriter makeCRAMWriter(final SAMFileHeader header, final OutputStr
      *
      */
     public CRAMFileWriter makeCRAMWriter(final SAMFileHeader header, final File outputFile, final File referenceFasta) {
-        return createCRAMWriterWithSettings(header, true, outputFile.toPath(), IOUtil.toPath( referenceFasta ));
+        return createCRAMWriterWithSettings(header, true, outputFile.toPath(), IOUtil.toPath(referenceFasta));
     }
 
     /**
@@ -592,7 +608,7 @@ public CRAMFileWriter makeCRAMWriter(final SAMFileHeader header, final File outp
      */
     @Deprecated
     public CRAMFileWriter makeCRAMWriter(final SAMFileHeader header, final Path outputPath, final File referenceFasta) {
-        return makeCRAMWriter(header, true, outputPath, IOUtil.toPath( referenceFasta ));
+        return makeCRAMWriter(header, true, outputPath, IOUtil.toPath(referenceFasta));
     }
 
     /**
@@ -607,11 +623,11 @@ public CRAMFileWriter makeCRAMWriter(final SAMFileHeader header, final Path outp
      * @return CRAMFileWriter
      *
      */
-    public CRAMFileWriter makeCRAMWriter(final SAMFileHeader header, final boolean presorted, final File outputFile, final File referenceFasta) {
-        return makeCRAMWriter(header, presorted, outputFile.toPath(),  IOUtil.toPath(referenceFasta));
+    public CRAMFileWriter makeCRAMWriter(
+            final SAMFileHeader header, final boolean presorted, final File outputFile, final File referenceFasta) {
+        return makeCRAMWriter(header, presorted, outputFile.toPath(), IOUtil.toPath(referenceFasta));
     }
 
-
     /**
      * Create a CRAMFileWriter on an output file.
      *
@@ -628,8 +644,9 @@ public CRAMFileWriter makeCRAMWriter(final SAMFileHeader header, final boolean p
      *
      */
     @Deprecated
-    public CRAMFileWriter makeCRAMWriter(final SAMFileHeader header, final boolean presorted, final Path output, final File referenceFasta) {
-        return makeCRAMWriter(header, presorted, output, IOUtil.toPath( referenceFasta ));
+    public CRAMFileWriter makeCRAMWriter(
+            final SAMFileHeader header, final boolean presorted, final Path output, final File referenceFasta) {
+        return makeCRAMWriter(header, presorted, output, IOUtil.toPath(referenceFasta));
     }
 
     /**
@@ -644,7 +661,8 @@ public CRAMFileWriter makeCRAMWriter(final SAMFileHeader header, final boolean p
      * @return CRAMFileWriter
      *
      */
-    public CRAMFileWriter makeCRAMWriter(final SAMFileHeader header, final boolean presorted, final Path output, final Path referenceFasta) {
+    public CRAMFileWriter makeCRAMWriter(
+            final SAMFileHeader header, final boolean presorted, final Path output, final Path referenceFasta) {
         return createCRAMWriterWithSettings(header, presorted, output, referenceFasta);
     }
 
@@ -660,17 +678,16 @@ public CRAMFileWriter makeCRAMWriter(final SAMFileHeader header, final boolean p
      * @return CRAMFileWriter
      */
     private CRAMFileWriter createCRAMWriterWithSettings(
-            final SAMFileHeader header,
-            final boolean presorted,
-            final Path outputFile,
-            final Path referenceFasta) {
+            final SAMFileHeader header, final boolean presorted, final Path outputFile, final Path referenceFasta) {
 
         final CRAMReferenceSource referenceSource;
         if (referenceFasta == null) {
-            log.info("Reference fasta is not provided when writing CRAM file " + outputFile.toUri().toString());
+            log.info("Reference fasta is not provided when writing CRAM file "
+                    + outputFile.toUri().toString());
             log.info("Will attempt to use a default reference or download as set by defaults:");
             log.info("Default REFERENCE_FASTA (-Dsamjdk.reference_fasta): " + Defaults.REFERENCE_FASTA);
-            log.info("Default USE_CRAM_REF_DOWNLOAD (-Dsamjdk.use_cram_ref_download): " + Defaults.USE_CRAM_REF_DOWNLOAD);
+            log.info("Default USE_CRAM_REF_DOWNLOAD (-Dsamjdk.use_cram_ref_download): "
+                    + Defaults.USE_CRAM_REF_DOWNLOAD);
 
             referenceSource = ReferenceSource.getDefaultCRAMReferenceSource();
         } else {
@@ -681,14 +698,14 @@ private CRAMFileWriter createCRAMWriterWithSettings(
 
         if (createIndex) {
             if (!IOUtil.isRegularPath(outputFile)) {
-                log.warn("Cannot create index for CRAM because output file is not a regular file: " + outputFile.toUri());
+                log.warn("Cannot create index for CRAM because output file is not a regular file: "
+                        + outputFile.toUri());
             } else {
                 final Path indexPath = IOUtil.addExtension(outputFile, FileExtensions.BAI_INDEX);
                 try {
 
-                    indexOS = Files.newOutputStream(indexPath) ;
-                }
-                catch (final IOException ioe) {
+                    indexOS = Files.newOutputStream(indexPath);
+                } catch (final IOException ioe) {
                     throw new RuntimeIOException("Error creating index file for: " + indexPath.toUri(), ioe);
                 }
             }
@@ -720,5 +737,4 @@ public String toString() {
                 + ", tmpDir=" + tmpDir + ", compressionLevel=" + compressionLevel + ", maxRecordsInRam="
                 + maxRecordsInRam + "]";
     }
-
 }
diff --git a/src/main/java/htsjdk/samtools/SAMFileWriterImpl.java b/src/main/java/htsjdk/samtools/SAMFileWriterImpl.java
index 3b89e09ae9..674307d8d6 100644
--- a/src/main/java/htsjdk/samtools/SAMFileWriterImpl.java
+++ b/src/main/java/htsjdk/samtools/SAMFileWriterImpl.java
@@ -23,12 +23,12 @@
  */
 package htsjdk.samtools;
 
+import static htsjdk.samtools.SAMFileHeader.SortOrder;
+
 import htsjdk.samtools.util.ProgressLoggerInterface;
 import htsjdk.samtools.util.SortingCollection;
-
 import java.io.File;
 import java.io.StringWriter;
-import static htsjdk.samtools.SAMFileHeader.SortOrder;
 
 /**
  * Base class for implementing SAM writer with any underlying format.
@@ -36,9 +36,8 @@
  * and produces the text version of the header, since that seems to be a popular item
  * in both text and binary file formats.
  */
-public abstract class SAMFileWriterImpl implements SAMFileWriter
-{
-    private static int DEAFULT_MAX_RECORDS_IN_RAM = 500000;      
+public abstract class SAMFileWriterImpl implements SAMFileWriter {
+    private static int DEAFULT_MAX_RECORDS_IN_RAM = 500000;
     private int maxRecordsInRam = DEAFULT_MAX_RECORDS_IN_RAM;
     private SAMFileHeader.SortOrder sortOrder;
     private SAMFileHeader header;
@@ -60,16 +59,16 @@ public abstract class SAMFileWriterImpl implements SAMFileWriter
      * @param maxRecordsInRam
      */
     public static void setDefaultMaxRecordsInRam(final int maxRecordsInRam) {
-        DEAFULT_MAX_RECORDS_IN_RAM = maxRecordsInRam;    
+        DEAFULT_MAX_RECORDS_IN_RAM = maxRecordsInRam;
     }
-    
+
     /**
-     * When writing records that are not presorted, this number determines the 
+     * When writing records that are not presorted, this number determines the
      * number of records stored in RAM before spilling to disk.
-     * @return DEAFULT_MAX_RECORDS_IN_RAM 
+     * @return DEAFULT_MAX_RECORDS_IN_RAM
      */
     public static int getDefaultMaxRecordsInRam() {
-        return DEAFULT_MAX_RECORDS_IN_RAM;    
+        return DEAFULT_MAX_RECORDS_IN_RAM;
     }
 
     /**
@@ -87,8 +86,8 @@ public void setProgressLogger(final ProgressLoggerInterface progress) {
      */
     public void setSortOrder(final SAMFileHeader.SortOrder sortOrder, final boolean presorted) {
         if (header != null) {
-            throw new IllegalStateException("Cannot call SAMFileWriterImpl.setSortOrder after setHeader for " +
-                    getFilename());
+            throw new IllegalStateException(
+                    "Cannot call SAMFileWriterImpl.setSortOrder after setHeader for " + getFilename());
         }
         this.sortOrder = sortOrder;
         this.presorted = presorted;
@@ -97,15 +96,14 @@ public void setSortOrder(final SAMFileHeader.SortOrder sortOrder, final boolean
 
     @Override
     public void setSortOrderChecking(boolean check) {
-        final boolean doCheck = check &&
-                this.presorted &&
-                this.sortOrder != SAMFileHeader.SortOrder.unsorted &&
-                this.sortOrder != SortOrder.unknown;
+        final boolean doCheck = check
+                && this.presorted
+                && this.sortOrder != SAMFileHeader.SortOrder.unsorted
+                && this.sortOrder != SortOrder.unknown;
 
         if (doCheck) {
             this.sortOrderChecker = new SAMSortOrderChecker(this.sortOrder);
-        }
-        else {
+        } else {
             this.sortOrderChecker = null;
         }
     }
@@ -134,12 +132,12 @@ protected int getMaxRecordsInRam() {
     }
 
     /**
-     * When writing records that are not presorted, specify the path of the temporary directory 
+     * When writing records that are not presorted, specify the path of the temporary directory
      * for spilling to disk.  Must be called before setHeader().
      * @param tmpDir path to the temporary directory
      */
     protected void setTempDirectory(final File tmpDir) {
-        if (tmpDir!=null) {
+        if (tmpDir != null) {
             this.tmpDir = tmpDir;
         }
     }
@@ -151,14 +149,13 @@ protected File getTempDirectory() {
     /**
      * Must be called before addAlignment. Header cannot be null.
      */
-    public void setHeader(final SAMFileHeader header)
-    {
+    public void setHeader(final SAMFileHeader header) {
         if (null == header) {
             throw new IllegalArgumentException("A non-null SAMFileHeader is required for a writer");
         }
         this.header = header;
         if (this.sortOrder == null) {
-             this.sortOrder = SAMFileHeader.SortOrder.unsorted;
+            this.sortOrder = SAMFileHeader.SortOrder.unsorted;
         }
         header.setSortOrder(this.sortOrder);
 
@@ -170,8 +167,12 @@ public void setHeader(final SAMFileHeader header)
             }
             setSortOrderChecking(true);
         } else if (!sortOrder.equals(SAMFileHeader.SortOrder.unsorted)) {
-            alignmentSorter = SortingCollection.newInstance(SAMRecord.class,
-                    new BAMRecordCodec(header), sortOrder.getComparatorInstance(), maxRecordsInRam, tmpDir);
+            alignmentSorter = SortingCollection.newInstance(
+                    SAMRecord.class,
+                    new BAMRecordCodec(header),
+                    sortOrder.getComparatorInstance(),
+                    maxRecordsInRam,
+                    tmpDir);
         }
     }
 
@@ -190,8 +191,7 @@ public SAMFileHeader getFileHeader() {
      * resolved against the writer's header using the current reference and mate reference names
      */
     @Override
-    public void addAlignment(final SAMRecord alignment)
-    {
+    public void addAlignment(final SAMRecord alignment) {
         alignment.setHeaderStrict(header); // re-establish the record header and resolve reference indices
         if (sortOrder.equals(SAMFileHeader.SortOrder.unsorted)) {
             writeAlignment(alignment);
@@ -206,10 +206,11 @@ public void addAlignment(final SAMRecord alignment)
     private void assertPresorted(final SAMRecord alignment) {
         if (this.sortOrderChecker != null && !sortOrderChecker.isSorted(alignment)) {
             final SAMRecord prev = sortOrderChecker.getPreviousRecord();
-            throw new IllegalArgumentException("Alignments added out of order in SAMFileWriterImpl.addAlignment for " +
-                    getFilename() + ". Sort order is " + this.sortOrder + ". Offending records are at ["
-                    + sortOrderChecker.getSortKey(prev) + "] and ["
-                    + sortOrderChecker.getSortKey(alignment) + "]");
+            throw new IllegalArgumentException(
+                    "Alignments added out of order in SAMFileWriterImpl.addAlignment for " + getFilename()
+                            + ". Sort order is " + this.sortOrder + ". Offending records are at ["
+                            + sortOrderChecker.getSortKey(prev) + "] and ["
+                            + sortOrderChecker.getSortKey(alignment) + "]");
         }
     }
 
@@ -217,16 +218,14 @@ private void assertPresorted(final SAMRecord alignment) {
      * Must be called or else file will likely be defective.
      */
     @Override
-    public final void close()
-    {
+    public final void close() {
         try {
             if (!isClosed) {
                 if (alignmentSorter != null) {
                     try {
                         for (final SAMRecord alignment : alignmentSorter) {
                             writeAlignment(alignment);
-                            if (progressLogger != null)
-                                progressLogger.record(alignment);
+                            if (progressLogger != null) progressLogger.record(alignment);
                         }
                     } finally {
                         alignmentSorter.cleanup();
@@ -244,7 +243,7 @@ public final void close()
      * this method is called. The record must hava a non-null SAMFileHeader.
      * @param alignment
      */
-    abstract protected void writeAlignment(SAMRecord alignment);
+    protected abstract void writeAlignment(SAMRecord alignment);
 
     /**
      * Write the header to disk.  Header object is available via getHeader().
@@ -252,7 +251,7 @@ public final void close()
      * @deprecated since 06/2018. {@link #writeHeader(SAMFileHeader)} is preferred for avoid String construction if not need it.
      */
     @Deprecated
-    abstract protected void writeHeader(String textHeader);
+    protected abstract void writeHeader(String textHeader);
 
     /**
      * Write the header to disk. Header object is available via getHeader().
@@ -273,11 +272,11 @@ protected void writeHeader(final SAMFileHeader header) {
     /**
      * Do any required flushing here.
      */
-    abstract protected void finish();
+    protected abstract void finish();
 
     /**
      * For producing error messages.
      * @return Output filename, or null if there isn't one.
      */
-    abstract protected String getFilename();
+    protected abstract String getFilename();
 }
diff --git a/src/main/java/htsjdk/samtools/SAMFlag.java b/src/main/java/htsjdk/samtools/SAMFlag.java
index 8451b898aa..c5bf7d2737 100644
--- a/src/main/java/htsjdk/samtools/SAMFlag.java
+++ b/src/main/java/htsjdk/samtools/SAMFlag.java
@@ -31,22 +31,21 @@
  * SAM flags as enum, to be used in GUI, menu, etc...
  */
 public enum SAMFlag {
-    READ_PAIRED(                    0x1,    "Template having multiple segments in sequencing"),
-    PROPER_PAIR(                    0x2,    "Each segment properly aligned according to the aligner"),
-    READ_UNMAPPED(                  0x4,    "Segment unmapped"),
-    MATE_UNMAPPED(                  0x8,    "Next segment in the template unmapped"),
-    READ_REVERSE_STRAND(            0x10,   "SEQ being reverse complemented"),
-    MATE_REVERSE_STRAND(            0x20,   "SEQ of the next segment in the template being reverse complemented"),
-    FIRST_OF_PAIR(                  0x40,   "The first segment in the template"),
-    SECOND_OF_PAIR(                 0x80,   "The last segment in the template"),
-    SECONDARY_ALIGNMENT(            0x100,  "Secondary alignment"),
+    READ_PAIRED(0x1, "Template having multiple segments in sequencing"),
+    PROPER_PAIR(0x2, "Each segment properly aligned according to the aligner"),
+    READ_UNMAPPED(0x4, "Segment unmapped"),
+    MATE_UNMAPPED(0x8, "Next segment in the template unmapped"),
+    READ_REVERSE_STRAND(0x10, "SEQ being reverse complemented"),
+    MATE_REVERSE_STRAND(0x20, "SEQ of the next segment in the template being reverse complemented"),
+    FIRST_OF_PAIR(0x40, "The first segment in the template"),
+    SECOND_OF_PAIR(0x80, "The last segment in the template"),
+    SECONDARY_ALIGNMENT(0x100, "Secondary alignment"),
     /** @deprecated use {@link #SECONDARY_ALIGNMENT} instead. */
     @Deprecated
-    NOT_PRIMARY_ALIGNMENT(          0x100,  "Secondary alignment"),
-    READ_FAILS_VENDOR_QUALITY_CHECK(0x200,  "Not passing quality controls"),
-    DUPLICATE_READ(                 0x400,  "PCR or optical duplicate"), 
-    SUPPLEMENTARY_ALIGNMENT(        0x800,  "Supplementary alignment")
-    ;
+    NOT_PRIMARY_ALIGNMENT(0x100, "Secondary alignment"),
+    READ_FAILS_VENDOR_QUALITY_CHECK(0x200, "Not passing quality controls"),
+    DUPLICATE_READ(0x400, "PCR or optical duplicate"),
+    SUPPLEMENTARY_ALIGNMENT(0x800, "Supplementary alignment");
 
     /* visible for the package, to be used by SAMRecord */
     final int flag;
@@ -75,18 +74,15 @@ public String getDescription() {
     /** @return the SAMFlag for the value 'flag' or null if it was not found */
     public static SAMFlag valueOf(int flag) {
         for (SAMFlag f : values()) {
-            if (flag == f.flag)
-                return f;
+            if (flag == f.flag) return f;
         }
         return null;
     }
 
     /** @return find SAMFlag the flag by name, or null if it was not found */
-    public static SAMFlag findByName(String flag)
-        {   
+    public static SAMFlag findByName(String flag) {
         for (SAMFlag f : values()) {
-            if (f.name().equals(flag))
-                return f;
+            if (f.name().equals(flag)) return f;
         }
         return null;
     }
@@ -105,8 +101,7 @@ public boolean isUnset(int flag) {
     public static Set getFlags(int flag) {
         Set set = new HashSet();
         for (SAMFlag f : values()) {
-            if (f.isSet(flag))
-                set.add(f);
+            if (f.isSet(flag)) set.add(f);
         }
         return set;
     }
diff --git a/src/main/java/htsjdk/samtools/SAMFormatException.java b/src/main/java/htsjdk/samtools/SAMFormatException.java
index bce82bc1de..62a51f3f4c 100644
--- a/src/main/java/htsjdk/samtools/SAMFormatException.java
+++ b/src/main/java/htsjdk/samtools/SAMFormatException.java
@@ -27,8 +27,7 @@
  * Thrown when a SAM file being read or decoded (text or binary) looks bad.
  */
 public class SAMFormatException extends SAMException {
-    public SAMFormatException() {
-    }
+    public SAMFormatException() {}
 
     public SAMFormatException(final String s) {
         super(s);
diff --git a/src/main/java/htsjdk/samtools/SAMHeaderRecordComparator.java b/src/main/java/htsjdk/samtools/SAMHeaderRecordComparator.java
index f48df4d338..a9eb3e9c59 100644
--- a/src/main/java/htsjdk/samtools/SAMHeaderRecordComparator.java
+++ b/src/main/java/htsjdk/samtools/SAMHeaderRecordComparator.java
@@ -23,7 +23,6 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-
 import java.io.Serializable;
 import java.util.Comparator;
 
@@ -33,36 +32,36 @@
  * record) sort behind those that have values.
  */
 public class SAMHeaderRecordComparator implements Comparator, Serializable {
-	private static final long serialVersionUID = 1L;
+    private static final long serialVersionUID = 1L;
 
-	private final String[] attributes;
+    private final String[] attributes;
 
-	public SAMHeaderRecordComparator(final String... attributes) {
-		this.attributes = attributes;
-	}
+    public SAMHeaderRecordComparator(final String... attributes) {
+        this.attributes = attributes;
+    }
 
-	@Override
-	public int compare(final T left, final T right) {
-		for (final String attribute : attributes) {
-			final String leftValue = left.getAttribute(attribute);
-			final String rightValue = right.getAttribute(attribute);
+    @Override
+    public int compare(final T left, final T right) {
+        for (final String attribute : attributes) {
+            final String leftValue = left.getAttribute(attribute);
+            final String rightValue = right.getAttribute(attribute);
 
-			if (leftValue == null) {
-				// Fastest comparison possible; two empty values are
-				// equivalent, so move along to the next attribute
-				if (rightValue == null) continue;
+            if (leftValue == null) {
+                // Fastest comparison possible; two empty values are
+                // equivalent, so move along to the next attribute
+                if (rightValue == null) continue;
 
-					// Otherwise left < right, since right has a value
-				else return -1;
-			}
+                // Otherwise left < right, since right has a value
+                else return -1;
+            }
 
-			// left is not null; if right is, left > right
-			if (rightValue == null) return 1;
+            // left is not null; if right is, left > right
+            if (rightValue == null) return 1;
 
-			final int compare = leftValue.compareTo(rightValue);
-			if (compare != 0) return compare;
-		}
+            final int compare = leftValue.compareTo(rightValue);
+            if (compare != 0) return compare;
+        }
 
-		return 0;
-	}
+        return 0;
+    }
 }
diff --git a/src/main/java/htsjdk/samtools/SAMLineParser.java b/src/main/java/htsjdk/samtools/SAMLineParser.java
index c015aa0a5a..89fc31cd90 100644
--- a/src/main/java/htsjdk/samtools/SAMLineParser.java
+++ b/src/main/java/htsjdk/samtools/SAMLineParser.java
@@ -24,7 +24,6 @@
 package htsjdk.samtools;
 
 import htsjdk.samtools.util.StringUtil;
-
 import java.io.File;
 import java.util.List;
 import java.util.Map;
@@ -62,6 +61,7 @@ public class SAMLineParser {
      * Add information about the origin (reader and position) to SAM records.
      */
     private final SamReader mParentReader;
+
     private final SAMRecordFactory samRecordFactory;
     private final ValidationStringency validationStringency;
     private final SAMFileHeader mFileHeader;
@@ -84,9 +84,7 @@ public class SAMLineParser {
      */
     public SAMLineParser(final SAMFileHeader samFileHeader) {
 
-        this(new DefaultSAMRecordFactory(),
-                ValidationStringency.DEFAULT_STRINGENCY, samFileHeader,
-                null, null);
+        this(new DefaultSAMRecordFactory(), ValidationStringency.DEFAULT_STRINGENCY, samFileHeader, null, null);
     }
 
     /**
@@ -96,12 +94,14 @@ public SAMLineParser(final SAMFileHeader samFileHeader) {
      * @param samFileReader SAM file reader For passing to SAMRecord.setFileSource, may be null.
      * @param samFile       SAM file being read (for error message only, may be null)
      */
-    public SAMLineParser(final SAMFileHeader samFileHeader,
-                         final SamReader samFileReader, final File samFile) {
-
-        this(new DefaultSAMRecordFactory(),
-                ValidationStringency.DEFAULT_STRINGENCY, samFileHeader,
-                samFileReader, samFile);
+    public SAMLineParser(final SAMFileHeader samFileHeader, final SamReader samFileReader, final File samFile) {
+
+        this(
+                new DefaultSAMRecordFactory(),
+                ValidationStringency.DEFAULT_STRINGENCY,
+                samFileHeader,
+                samFileReader,
+                samFile);
     }
 
     /**
@@ -113,19 +113,18 @@ public SAMLineParser(final SAMFileHeader samFileHeader,
      * @param samFileReader        SAM file reader For passing to SAMRecord.setFileSource, may be null.
      * @param samFile              SAM file being read (for error message only, may be null)
      */
-    public SAMLineParser(final SAMRecordFactory samRecordFactory,
-                         final ValidationStringency validationStringency,
-                         final SAMFileHeader samFileHeader, final SamReader samFileReader,
-                         final File samFile) {
+    public SAMLineParser(
+            final SAMRecordFactory samRecordFactory,
+            final ValidationStringency validationStringency,
+            final SAMFileHeader samFileHeader,
+            final SamReader samFileReader,
+            final File samFile) {
 
-        if (samRecordFactory == null)
-            throw new NullPointerException("The SamRecordFactory must be set");
+        if (samRecordFactory == null) throw new NullPointerException("The SamRecordFactory must be set");
 
-        if (validationStringency == null)
-            throw new NullPointerException("The validationStringency must be set");
+        if (validationStringency == null) throw new NullPointerException("The validationStringency must be set");
 
-        if (samFileHeader == null)
-            throw new NullPointerException("The mFileHeader must be set");
+        if (samFileHeader == null) throw new NullPointerException("The mFileHeader must be set");
 
         this.samRecordFactory = samRecordFactory;
         this.validationStringency = validationStringency;
@@ -175,7 +174,7 @@ private int parseInt(final String s, final String fieldName) {
         }
         return ret;
     }
-    
+
     private int parseFlag(final String s, final String fieldName) {
         try {
             return samFlagField.isPresent() ? samFlagField.get().parse(s) : SamFlagField.parseDefault(s);
@@ -191,13 +190,11 @@ private void validateReferenceName(final String rname, final String fieldName) {
             if (fieldName.equals("MRNM")) {
                 return;
             }
-            reportErrorParsingLine("= is not a valid value for "
-                    + fieldName + " field.");
+            reportErrorParsingLine("= is not a valid value for " + fieldName + " field.");
         }
         if (!this.mFileHeader.getSequenceDictionary().isEmpty()) {
             if (this.mFileHeader.getSequence(rname) == null) {
-                reportErrorParsingLine(fieldName
-                        + " '" + rname + "' not found in any SQ record");
+                reportErrorParsingLine(fieldName + " '" + rname + "' not found in any SQ record");
             }
         }
     }
@@ -238,11 +235,9 @@ public SAMRecord parseLine(final String line, final int lineNumber) {
                 reportErrorParsingLine("Empty field at position " + i + " (zero-based)");
             }
         }
-        final SAMRecord samRecord =
-                samRecordFactory.createSAMRecord(this.mFileHeader);
+        final SAMRecord samRecord = samRecordFactory.createSAMRecord(this.mFileHeader);
         samRecord.setValidationStringency(this.validationStringency);
-        if (mParentReader != null)
-            samRecord.setFileSource(new SAMFileSource(mParentReader, null));
+        if (mParentReader != null) samRecord.setFileSource(new SAMFileSource(mParentReader, null));
         samRecord.setHeader(this.mFileHeader);
         samRecord.setReadName(mFields[QNAME_COL]);
 
@@ -261,8 +256,7 @@ public SAMRecord parseLine(final String line, final int lineNumber) {
         final int pos = parseInt(mFields[POS_COL], "POS");
         final int mapq = parseInt(mFields[MAPQ_COL], "MAPQ");
         final String cigar = mFields[CIGAR_COL];
-        if (!SAMRecord.NO_ALIGNMENT_REFERENCE_NAME.equals(samRecord
-                .getReferenceName())) {
+        if (!SAMRecord.NO_ALIGNMENT_REFERENCE_NAME.equals(samRecord.getReferenceName())) {
             if (pos == 0) {
                 reportErrorParsingLine("POS must be non-zero if RNAME is specified");
             }
@@ -309,8 +303,7 @@ public SAMRecord parseLine(final String line, final int lineNumber) {
 
         final int matePos = parseInt(mFields[MPOS_COL], "MPOS");
         final int isize = parseInt(mFields[ISIZE_COL], "ISIZE");
-        if (!samRecord.getMateReferenceName().equals(
-                SAMRecord.NO_ALIGNMENT_REFERENCE_NAME)) {
+        if (!samRecord.getMateReferenceName().equals(SAMRecord.NO_ALIGNMENT_REFERENCE_NAME)) {
             if (matePos == 0) {
                 reportErrorParsingLine("MPOS must be non-zero if MRNM is specified");
             }
@@ -362,11 +355,11 @@ public SAMRecord parseLine(final String line, final int lineNumber) {
 
     private void validateReadBases(final String bases) {
         /*
-        * Using regex is slow, so check for invalid characters via
-        * isValidReadBase(), which hopefully the JIT will optimize. if
-        * (!VALID_BASES.matcher(bases).matches()) {
-        * reportErrorParsingLine("Invalid character in read bases"); }
-        */
+         * Using regex is slow, so check for invalid characters via
+         * isValidReadBase(), which hopefully the JIT will optimize. if
+         * (!VALID_BASES.matcher(bases).matches()) {
+         * reportErrorParsingLine("Invalid character in read bases"); }
+         */
         for (int i = 0; i < bases.length(); ++i) {
             if (!isValidReadBase(bases.charAt(i))) {
                 reportErrorParsingLine("Invalid character in read bases");
@@ -424,11 +417,9 @@ private void parseTag(final SAMRecord samRecord, final String tag) {
         }
         if (entry != null) {
             if (entry.getValue() instanceof TagValueAndUnsignedArrayFlag) {
-                final TagValueAndUnsignedArrayFlag valueAndFlag =
-                        (TagValueAndUnsignedArrayFlag) entry.getValue();
+                final TagValueAndUnsignedArrayFlag valueAndFlag = (TagValueAndUnsignedArrayFlag) entry.getValue();
                 if (valueAndFlag.isUnsignedArray) {
-                    samRecord.setUnsignedArrayAttribute(entry.getKey(),
-                            valueAndFlag.value);
+                    samRecord.setUnsignedArrayAttribute(entry.getKey(), valueAndFlag.value);
                 } else {
                     samRecord.setAttribute(entry.getKey(), valueAndFlag.value);
                 }
@@ -456,8 +447,7 @@ private void reportErrorParsingLine(final String reason) {
         if (validationStringency == ValidationStringency.STRICT) {
             throw new SAMFormatException(errorMessage);
         } else if (validationStringency == ValidationStringency.LENIENT) {
-            System.err
-                    .println("Ignoring SAM validation error due to lenient parsing:");
+            System.err.println("Ignoring SAM validation error due to lenient parsing:");
             System.err.println(errorMessage);
         }
     }
@@ -482,5 +472,4 @@ private String makeErrorString(final String reason) {
                 + (this.currentLineNumber <= 0 ? "unknown" : this.currentLineNumber)
                 + "\nLine: " + this.currentLine;
     }
-
 }
diff --git a/src/main/java/htsjdk/samtools/SAMProgramRecord.java b/src/main/java/htsjdk/samtools/SAMProgramRecord.java
index f5ddd964a6..86cabf661c 100644
--- a/src/main/java/htsjdk/samtools/SAMProgramRecord.java
+++ b/src/main/java/htsjdk/samtools/SAMProgramRecord.java
@@ -39,12 +39,12 @@ public class SAMProgramRecord extends AbstractSAMHeaderRecord {
     public static final String COMMAND_LINE_TAG = "CL";
     public static final String PREVIOUS_PROGRAM_GROUP_ID_TAG = "PP";
     private String mProgramGroupId;
-    public static final Set STANDARD_TAGS = Collections.unmodifiableSet(
-            new HashSet(Arrays.asList(PROGRAM_GROUP_ID_TAG,
-                    PROGRAM_NAME_TAG,
-                    PROGRAM_VERSION_TAG,
-                    COMMAND_LINE_TAG,
-                    PREVIOUS_PROGRAM_GROUP_ID_TAG)) );
+    public static final Set STANDARD_TAGS = Collections.unmodifiableSet(new HashSet(Arrays.asList(
+            PROGRAM_GROUP_ID_TAG,
+            PROGRAM_NAME_TAG,
+            PROGRAM_VERSION_TAG,
+            COMMAND_LINE_TAG,
+            PREVIOUS_PROGRAM_GROUP_ID_TAG)));
 
     public SAMProgramRecord(final String programGroupId) {
         this.mProgramGroupId = programGroupId;
@@ -67,7 +67,7 @@ public String getProgramGroupId() {
     }
 
     public String getProgramName() {
-        return (String)getAttribute(PROGRAM_NAME_TAG);
+        return (String) getAttribute(PROGRAM_NAME_TAG);
     }
 
     public void setProgramName(final String name) {
@@ -75,7 +75,7 @@ public void setProgramName(final String name) {
     }
 
     public String getProgramVersion() {
-        return (String)getAttribute(PROGRAM_VERSION_TAG);
+        return (String) getAttribute(PROGRAM_VERSION_TAG);
     }
 
     public void setProgramVersion(final String version) {
@@ -83,7 +83,7 @@ public void setProgramVersion(final String version) {
     }
 
     public String getCommandLine() {
-        return (String)getAttribute(COMMAND_LINE_TAG);
+        return (String) getAttribute(COMMAND_LINE_TAG);
     }
 
     public void setCommandLine(final String commandLine) {
@@ -91,15 +91,13 @@ public void setCommandLine(final String commandLine) {
     }
 
     public String getPreviousProgramGroupId() {
-        return (String)getAttribute(PREVIOUS_PROGRAM_GROUP_ID_TAG);
+        return (String) getAttribute(PREVIOUS_PROGRAM_GROUP_ID_TAG);
     }
 
     public void setPreviousProgramGroupId(final String id) {
         setAttribute(PREVIOUS_PROGRAM_GROUP_ID_TAG, id);
     }
 
-
-
     /**
      * @return true if this == that except for the program group ID, which is arbitrary
      */
@@ -115,7 +113,8 @@ public boolean equals(final Object o) {
         final SAMProgramRecord that = (SAMProgramRecord) o;
 
         if (!attributesEqual(that)) return false;
-        if (mProgramGroupId != null ? !mProgramGroupId.equals(that.mProgramGroupId) : that.mProgramGroupId != null) return false;
+        if (mProgramGroupId != null ? !mProgramGroupId.equals(that.mProgramGroupId) : that.mProgramGroupId != null)
+            return false;
 
         return true;
     }
@@ -132,7 +131,6 @@ Set getStandardTags() {
         return STANDARD_TAGS;
     }
 
-
     @Override
     public String getSAMString() {
         return new SAMTextHeaderCodec().getPGLine(this);
diff --git a/src/main/java/htsjdk/samtools/SAMReadGroupRecord.java b/src/main/java/htsjdk/samtools/SAMReadGroupRecord.java
index 7a7c14e24e..4eb8b36687 100644
--- a/src/main/java/htsjdk/samtools/SAMReadGroupRecord.java
+++ b/src/main/java/htsjdk/samtools/SAMReadGroupRecord.java
@@ -23,10 +23,8 @@
  */
 package htsjdk.samtools;
 
-
 import htsjdk.samtools.util.Iso8601Date;
 import htsjdk.samtools.util.SamConstants;
-
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Date;
@@ -38,8 +36,7 @@
 /**
  * Header information about a read group.
  */
-public class SAMReadGroupRecord extends AbstractSAMHeaderRecord
-{
+public class SAMReadGroupRecord extends AbstractSAMHeaderRecord {
     private String mReadGroupId = null;
     public static final String READ_GROUP_ID_TAG = "ID";
     public static final String SEQUENCING_CENTER_TAG = "CN";
@@ -56,15 +53,15 @@ public class SAMReadGroupRecord extends AbstractSAMHeaderRecord
     public static final String READ_GROUP_SAMPLE_TAG = "SM";
     public static final String BARCODE_TAG = "BC";
 
-
     /* Platform values for the @RG-PL tag */
     public enum PlatformValue {
         /** @deprecated Use {@linkplain PlatformValue#DNBSEQ} instead. */
-        @Deprecated BGI,
+        @Deprecated
+        BGI,
 
         /** Capillary */
         CAPILLARY,
-        
+
         /** MGI/BGI */
         DNBSEQ,
 
@@ -87,11 +84,12 @@ public enum PlatformValue {
         ONT,
 
         /** @deprecated OTHER is not an official value.  It is recommended to omit PL if it is not in this list or is unknown. */
-        @Deprecated OTHER,
+        @Deprecated
+        OTHER,
 
         /** Pacific Biotechnology */
         PACBIO,
-        
+
         /** Singular Genomics */
         SINGULAR,
 
@@ -102,13 +100,25 @@ public enum PlatformValue {
         ULTIMA
     }
 
-    public static final Set STANDARD_TAGS =
-            new HashSet<>(Arrays.asList(READ_GROUP_ID_TAG, SEQUENCING_CENTER_TAG, DESCRIPTION_TAG,
-                    DATE_RUN_PRODUCED_TAG, FLOW_ORDER_TAG, KEY_SEQUENCE_TAG, LIBRARY_TAG,
-                    PROGRAM_GROUP_TAG, PREDICTED_MEDIAN_INSERT_SIZE_TAG, PLATFORM_TAG, PLATFORM_MODEL_TAG,
-                    PLATFORM_UNIT_TAG, READ_GROUP_SAMPLE_TAG, BARCODE_TAG));
-
-    public SAMReadGroupRecord(final String id) { mReadGroupId = id; }
+    public static final Set STANDARD_TAGS = new HashSet<>(Arrays.asList(
+            READ_GROUP_ID_TAG,
+            SEQUENCING_CENTER_TAG,
+            DESCRIPTION_TAG,
+            DATE_RUN_PRODUCED_TAG,
+            FLOW_ORDER_TAG,
+            KEY_SEQUENCE_TAG,
+            LIBRARY_TAG,
+            PROGRAM_GROUP_TAG,
+            PREDICTED_MEDIAN_INSERT_SIZE_TAG,
+            PLATFORM_TAG,
+            PLATFORM_MODEL_TAG,
+            PLATFORM_UNIT_TAG,
+            READ_GROUP_SAMPLE_TAG,
+            BARCODE_TAG));
+
+    public SAMReadGroupRecord(final String id) {
+        mReadGroupId = id;
+    }
 
     public SAMReadGroupRecord(final String id, final SAMReadGroupRecord srcProgramRecord) {
         mReadGroupId = id;
@@ -118,20 +128,45 @@ public SAMReadGroupRecord(final String id, final SAMReadGroupRecord srcProgramRe
     }
 
     @Override
-    public String getId() { return getReadGroupId();  }
-    public String getReadGroupId() { return mReadGroupId; }
+    public String getId() {
+        return getReadGroupId();
+    }
+
+    public String getReadGroupId() {
+        return mReadGroupId;
+    }
 
-    public String getSample() { return getAttribute(READ_GROUP_SAMPLE_TAG); }
-    public void setSample(final String value) { setAttribute(READ_GROUP_SAMPLE_TAG, value); }
+    public String getSample() {
+        return getAttribute(READ_GROUP_SAMPLE_TAG);
+    }
+
+    public void setSample(final String value) {
+        setAttribute(READ_GROUP_SAMPLE_TAG, value);
+    }
 
-    public String getLibrary() { return getAttribute(LIBRARY_TAG); }
-    public void setLibrary(final String value) { setAttribute(LIBRARY_TAG, value); }
+    public String getLibrary() {
+        return getAttribute(LIBRARY_TAG);
+    }
+
+    public void setLibrary(final String value) {
+        setAttribute(LIBRARY_TAG, value);
+    }
 
-    public String getPlatformUnit() { return getAttribute(PLATFORM_UNIT_TAG); }
-    public void setPlatformUnit(final String pu) { setAttribute(PLATFORM_UNIT_TAG, pu); }
+    public String getPlatformUnit() {
+        return getAttribute(PLATFORM_UNIT_TAG);
+    }
+
+    public void setPlatformUnit(final String pu) {
+        setAttribute(PLATFORM_UNIT_TAG, pu);
+    }
+
+    public String getPlatform() {
+        return getAttribute(PLATFORM_TAG);
+    }
 
-    public String getPlatform() { return getAttribute(PLATFORM_TAG); }
-    public void setPlatform(final String platform) { setAttribute(PLATFORM_TAG, platform); }
+    public void setPlatform(final String platform) {
+        setAttribute(PLATFORM_TAG, platform);
+    }
 
     /**
      * @return the List of barcodes associated with this read group or null
@@ -159,7 +194,7 @@ public void setBarcodes(final List barcodes) {
             if (barcodes.stream().anyMatch(String::isEmpty)) {
                 throw new IllegalArgumentException("A barcode must not be an empty String");
             }
-           setAttribute(BARCODE_TAG, String.join(SamConstants.BARCODE_SEQUENCE_DELIMITER, barcodes));
+            setAttribute(BARCODE_TAG, String.join(SamConstants.BARCODE_SEQUENCE_DELIMITER, barcodes));
         }
     }
 
@@ -172,11 +207,21 @@ public Date getRunDate() {
         }
     }
 
-    public String getFlowOrder() { return getAttribute(FLOW_ORDER_TAG); }
-    public void setFlowOrder(final String flowOrder) { setAttribute(FLOW_ORDER_TAG, flowOrder); }
+    public String getFlowOrder() {
+        return getAttribute(FLOW_ORDER_TAG);
+    }
+
+    public void setFlowOrder(final String flowOrder) {
+        setAttribute(FLOW_ORDER_TAG, flowOrder);
+    }
 
-    public String getKeySequence() { return getAttribute(KEY_SEQUENCE_TAG); }
-    public void setKeySequence(final String keySequence) { setAttribute(KEY_SEQUENCE_TAG, keySequence); }
+    public String getKeySequence() {
+        return getAttribute(KEY_SEQUENCE_TAG);
+    }
+
+    public void setKeySequence(final String keySequence) {
+        setAttribute(KEY_SEQUENCE_TAG, keySequence);
+    }
 
     /**
      * Converts to Iso8601Date if not already in that form.
@@ -188,30 +233,53 @@ public void setRunDate(Date runDate) {
         setAttribute(DATE_RUN_PRODUCED_TAG, runDate != null ? runDate.toString() : null);
     }
 
-    public String getSequencingCenter() { return getAttribute(SEQUENCING_CENTER_TAG); }
-    public void setSequencingCenter(final String center) { setAttribute(SEQUENCING_CENTER_TAG, center); }
+    public String getSequencingCenter() {
+        return getAttribute(SEQUENCING_CENTER_TAG);
+    }
+
+    public void setSequencingCenter(final String center) {
+        setAttribute(SEQUENCING_CENTER_TAG, center);
+    }
+
+    public String getDescription() {
+        return getAttribute(DESCRIPTION_TAG);
+    }
 
-    public String getDescription() { return getAttribute(DESCRIPTION_TAG); }
-    public void setDescription(final String description) { setAttribute(DESCRIPTION_TAG, description); }
+    public void setDescription(final String description) {
+        setAttribute(DESCRIPTION_TAG, description);
+    }
 
     public Integer getPredictedMedianInsertSize() {
         final String stringRep = getAttribute(PREDICTED_MEDIAN_INSERT_SIZE_TAG);
         if (stringRep == null) {
             return null;
         }
-        return Integer.parseInt(stringRep); 
+        return Integer.parseInt(stringRep);
     }
+
     public void setPredictedMedianInsertSize(final Integer predictedMedianInsertSize) {
 
-        setAttribute(PREDICTED_MEDIAN_INSERT_SIZE_TAG, (predictedMedianInsertSize == null? null: predictedMedianInsertSize.toString())); 
+        setAttribute(
+                PREDICTED_MEDIAN_INSERT_SIZE_TAG,
+                (predictedMedianInsertSize == null ? null : predictedMedianInsertSize.toString()));
     }
 
-    public String getProgramGroup() { return getAttribute(PROGRAM_GROUP_TAG); }
-    public void setProgramGroup(final String programGroup) { setAttribute(PROGRAM_GROUP_TAG, programGroup); }
+    public String getProgramGroup() {
+        return getAttribute(PROGRAM_GROUP_TAG);
+    }
+
+    public void setProgramGroup(final String programGroup) {
+        setAttribute(PROGRAM_GROUP_TAG, programGroup);
+    }
+
+    public String getPlatformModel() {
+        return getAttribute(PLATFORM_MODEL_TAG);
+    }
+
+    public void setPlatformModel(final String platformModel) {
+        setAttribute(PLATFORM_MODEL_TAG, platformModel);
+    }
 
-    public String getPlatformModel() { return getAttribute(PLATFORM_MODEL_TAG); }
-    public void setPlatformModel(final String platformModel) { setAttribute(PLATFORM_MODEL_TAG, platformModel); }
-    
     /**
      * @return true if this == that except for the read group ID, which is arbitrary
      */
@@ -250,7 +318,6 @@ Set getStandardTags() {
 
     @Override
     public String getSAMString() {
-      return new SAMTextHeaderCodec().getRGLine(this);
+        return new SAMTextHeaderCodec().getRGLine(this);
     }
 }
-
diff --git a/src/main/java/htsjdk/samtools/SAMRecord.java b/src/main/java/htsjdk/samtools/SAMRecord.java
index 6b37378f1a..aea310677f 100644
--- a/src/main/java/htsjdk/samtools/SAMRecord.java
+++ b/src/main/java/htsjdk/samtools/SAMRecord.java
@@ -30,9 +30,7 @@
 import htsjdk.samtools.util.Log;
 import htsjdk.samtools.util.SequenceUtil;
 import htsjdk.samtools.util.StringUtil;
-
 import java.io.Serializable;
-import java.lang.reflect.Array;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -42,7 +40,6 @@
 import java.util.Map;
 import java.util.Set;
 
-
 /**
  * Java binding for a SAM file record.  c.f. http://samtools.sourceforge.net/SAM1.pdf
  * 

@@ -113,12 +110,12 @@ * @author mishali.naik@intel.com */ public class SAMRecord implements HtsRecord, Cloneable, Locatable, Serializable { - private final static Log LOG = Log.getInstance(SAMRecord.class); + private static final Log LOG = Log.getInstance(SAMRecord.class); public static final long serialVersionUID = 1L; /** - * Alignment score for a good alignment, but where computing a Phred-score is not feasible. + * Alignment score for a good alignment, but where computing a Phred-score is not feasible. */ public static final int UNKNOWN_MAPPING_QUALITY = 255; @@ -160,6 +157,7 @@ public class SAMRecord implements HtsRecord, Cloneable, Locatable, Serializable * This should rarely be used, since all reads should have quality scores. */ public static final byte[] NULL_QUALS = new byte[0]; + public static final String NULL_QUALS_STRING = "*"; /** @@ -207,10 +205,11 @@ public class SAMRecord implements HtsRecord, Cloneable, Locatable, Serializable * file source to be lost (if it had one). */ private transient SAMFileSource mFileSource; + private SAMFileHeader mHeader = null; /** Transient Map of attributes for use by anyone. */ - private transient Map transientAttributes; + private transient Map transientAttributes; public SAMRecord(final SAMFileHeader header) { mHeader = header; @@ -317,8 +316,7 @@ public byte[] getOriginalBaseQualities() { final String oqString = (String) getAttribute("OQ"); if (oqString != null && !oqString.isEmpty()) { return SAMUtils.fastqToPhred(oqString); - } - else { + } else { return null; } } @@ -332,8 +330,8 @@ public void setOriginalBaseQualities(final byte[] oq) { } private static boolean hasReferenceName(final Integer referenceIndex, final String referenceName) { - return (referenceIndex != null && !referenceIndex.equals(NO_ALIGNMENT_REFERENCE_INDEX)) || - (!NO_ALIGNMENT_REFERENCE_NAME.equals(referenceName)); + return (referenceIndex != null && !referenceIndex.equals(NO_ALIGNMENT_REFERENCE_INDEX)) + || (!NO_ALIGNMENT_REFERENCE_NAME.equals(referenceName)); } /** @@ -353,7 +351,9 @@ private boolean hasMateReferenceName() { /** * @return Reference name, or NO_ALIGNMENT_REFERENCE_NAME (*) if the record has no reference name */ - public String getReferenceName() { return mReferenceName; } + public String getReferenceName() { + return mReferenceName; + } /** * Sets the reference name for this record. If the record has a valid SAMFileHeader and the reference @@ -373,15 +373,12 @@ public void setReferenceName(final String referenceName) { mReferenceIndex = resolveIndexFromName(referenceName, mHeader, false); // String.intern() is surprisingly expensive, so avoid it by calling resolveNameFromIndex // and using the interned value in the sequence dictionary if possible - mReferenceName = null == mReferenceIndex ? - referenceName.intern() : - resolveNameFromIndex(mReferenceIndex, mHeader); - } - else if (NO_ALIGNMENT_REFERENCE_NAME.equals(referenceName)) { + mReferenceName = + null == mReferenceIndex ? referenceName.intern() : resolveNameFromIndex(mReferenceIndex, mHeader); + } else if (NO_ALIGNMENT_REFERENCE_NAME.equals(referenceName)) { mReferenceName = NO_ALIGNMENT_REFERENCE_NAME; mReferenceIndex = NO_ALIGNMENT_REFERENCE_INDEX; - } - else { + } else { mReferenceName = referenceName.intern(); mReferenceIndex = null; } @@ -470,21 +467,20 @@ public String getMateReferenceName() { */ public void setMateReferenceName(final String mateReferenceName) { if (null == mateReferenceName) { - throw new IllegalArgumentException("Mate reference name must not be null. Use SAMRecord.NO_ALIGNMENT_REFERENCE_NAME to reset the mate reference name."); + throw new IllegalArgumentException( + "Mate reference name must not be null. Use SAMRecord.NO_ALIGNMENT_REFERENCE_NAME to reset the mate reference name."); } if (null != mHeader) { mMateReferenceIndex = resolveIndexFromName(mateReferenceName, mHeader, false); // String.intern() is surprisingly expensive, so avoid it by calling resolveNameFromIndex // and using the interned value in the sequence dictionary if possible - mMateReferenceName = null == mMateReferenceIndex ? - mateReferenceName.intern() : - resolveNameFromIndex(mMateReferenceIndex, mHeader); - } - else if (NO_ALIGNMENT_REFERENCE_NAME.equals(mateReferenceName)) { + mMateReferenceName = null == mMateReferenceIndex + ? mateReferenceName.intern() + : resolveNameFromIndex(mMateReferenceIndex, mHeader); + } else if (NO_ALIGNMENT_REFERENCE_NAME.equals(mateReferenceName)) { mMateReferenceName = NO_ALIGNMENT_REFERENCE_NAME; mMateReferenceIndex = NO_ALIGNMENT_REFERENCE_INDEX; - } - else { + } else { mMateReferenceName = mateReferenceName.intern(); mMateReferenceIndex = null; } @@ -552,19 +548,21 @@ public void setMateReferenceIndex(final int mateReferenceIndex) { * * Does not mutate the SAMRecord. */ - protected static Integer resolveIndexFromName(final String referenceName, final SAMFileHeader header, final boolean strict) { + protected static Integer resolveIndexFromName( + final String referenceName, final SAMFileHeader header, final boolean strict) { Integer referenceIndex = NO_ALIGNMENT_REFERENCE_INDEX; if (!NO_ALIGNMENT_REFERENCE_NAME.equals(referenceName)) { if (null == header) { - throw new IllegalStateException("A non-null SAMFileHeader is required to resolve the reference index or name"); + throw new IllegalStateException( + "A non-null SAMFileHeader is required to resolve the reference index or name"); } referenceIndex = header.getSequenceIndex(referenceName); if (NO_ALIGNMENT_REFERENCE_INDEX == referenceIndex) { if (strict) { - throw new IllegalArgumentException("Reference index for '" + referenceName + "' not found in sequence dictionary."); - } - else { - referenceIndex = null; // unresolved. + throw new IllegalArgumentException( + "Reference index for '" + referenceName + "' not found in sequence dictionary."); + } else { + referenceIndex = null; // unresolved. } } } @@ -590,11 +588,13 @@ protected static String resolveNameFromIndex(final int referenceIndex, final SAM String referenceName = NO_ALIGNMENT_REFERENCE_NAME; if (NO_ALIGNMENT_REFERENCE_INDEX != referenceIndex) { if (null == header) { - throw new IllegalStateException("A non-null SAMFileHeader is required to resolve the reference index or name"); + throw new IllegalStateException( + "A non-null SAMFileHeader is required to resolve the reference index or name"); } SAMSequenceRecord samSeq = header.getSequence(referenceIndex); if (null == samSeq) { - throw new IllegalArgumentException("Reference name for '" + referenceIndex + "' not found in sequence dictionary."); + throw new IllegalArgumentException( + "Reference name for '" + referenceIndex + "' not found in sequence dictionary."); } referenceName = samSeq.getSequenceName(); } @@ -603,7 +603,7 @@ protected static String resolveNameFromIndex(final int referenceIndex, final SAM } /** - * @return 1-based inclusive leftmost position of the sequence remaining after clipping, or 0 + * @return 1-based inclusive leftmost position of the sequence remaining after clipping, or 0 * if there is no position, e.g. for unmapped read. */ public int getAlignmentStart() { @@ -611,7 +611,7 @@ public int getAlignmentStart() { } /** - * @param value 1-based inclusive leftmost position of the sequence remaining after clipping or 0 + * @param value 1-based inclusive leftmost position of the sequence remaining after clipping or 0 * if there is no position, e.g. for unmapped read. */ public void setAlignmentStart(final int value) { @@ -622,14 +622,13 @@ public void setAlignmentStart(final int value) { } /** - * @return 1-based inclusive rightmost position of the sequence remaining after clipping or 0 + * @return 1-based inclusive rightmost position of the sequence remaining after clipping or 0 * if there is no position, e.g. for unmapped read. */ public int getAlignmentEnd() { if (getReadUnmappedFlag()) { return NO_ALIGNMENT_START; - } - else if (this.mAlignmentEnd == NO_ALIGNMENT_START) { + } else if (this.mAlignmentEnd == NO_ALIGNMENT_START) { this.mAlignmentEnd = mAlignmentStart + getCigar().getReferenceLength() - 1; } @@ -658,7 +657,6 @@ public int getUnclippedEnd() { return SAMUtils.getUnclippedEnd(getAlignmentEnd(), getCigar()); } - /** * Non static version of the static function with the same name. * @@ -703,7 +701,6 @@ public static int getReferencePositionAtReadPosition(final SAMRecord rec, final return 0; // offset not located in an alignment block } - /** * Returns the 1-based position in the read of the 1-based reference position provided. * @@ -757,7 +754,8 @@ public int getReadPositionAtReferencePosition(final int pos, final boolean retur * in the preceding block. * */ - public static int getReadPositionAtReferencePosition(final SAMRecord rec, final int pos, final boolean returnLastBaseIfDeleted) { + public static int getReadPositionAtReferencePosition( + final SAMRecord rec, final int pos, final boolean returnLastBaseIfDeleted) { if (pos <= 0) { return 0; @@ -767,14 +765,14 @@ public static int getReadPositionAtReferencePosition(final SAMRecord rec, final for (final AlignmentBlock alignmentBlock : rec.getAlignmentBlocks()) { if (CoordMath.getEnd(alignmentBlock.getReferenceStart(), alignmentBlock.getLength()) >= pos) { if (pos < alignmentBlock.getReferenceStart()) { - //There must have been a deletion block that skipped + // There must have been a deletion block that skipped return returnLastBaseIfDeleted ? lastAlignmentOffset : 0; } else { - return pos - alignmentBlock.getReferenceStart() + alignmentBlock.getReadStart() ; + return pos - alignmentBlock.getReferenceStart() + alignmentBlock.getReadStart(); } } else { // record the offset to the last base in the current block, in case the next block starts too late - lastAlignmentOffset = alignmentBlock.getReadStart() + alignmentBlock.getLength() - 1 ; + lastAlignmentOffset = alignmentBlock.getReadStart() + alignmentBlock.getLength() - 1; } } // if we are here, the reference position was not overlapping the read at all @@ -838,9 +836,9 @@ public void setCigarString(final String value) { public Cigar getCigar() { if (mCigar == null && mCigarString != null) { mCigar = TextCigarCodec.decode(mCigarString); - if (null != getHeader() && - getValidationStringency() != ValidationStringency.SILENT && - !this.getReadUnmappedFlag()) { + if (null != getHeader() + && getValidationStringency() != ValidationStringency.SILENT + && !this.getReadUnmappedFlag()) { // Don't know line number, and don't want to force read name to be decoded. SAMUtils.processValidationErrors(this.validateCigar(-1L), -1L, getValidationStringency()); } @@ -887,7 +885,7 @@ protected void initializeCigar(final Cigar cigar) { * @throws ClassCastException if RG tag does not have a String value. */ public SAMReadGroupRecord getReadGroup() { - final String rgId = (String)getAttribute(SAMTag.RG); + final String rgId = (String) getAttribute(SAMTag.RG); if (rgId == null || getHeader() == null) { return null; } else { @@ -1174,7 +1172,6 @@ public boolean hasAttribute(final SAMTag tag) { return getAttribute(tag) != null; } - /** * Get the value for a SAM tag. * WARNING: Some value types (e.g. byte[]) are mutable. It is dangerous to change one of these values in @@ -1211,7 +1208,7 @@ public Integer getIntegerAttribute(final SAMTag tag) { return getIntegerAttribute(tag.name()); } - /** + /** * Get the tag value and attempt to coerce it into the requested type. * @param tag The requested tag. * @return The value of a tag, converted into a signed Integer if possible. @@ -1221,16 +1218,16 @@ public Integer getIntegerAttribute(final String tag) { final Object val = getAttribute(tag); if (val == null) return null; if (val instanceof Integer) { - return (Integer)val; + return (Integer) val; } if (!(val instanceof Number)) { throw new RuntimeException("Value for tag " + tag + " is not Number: " + val.getClass()); } - final long longVal = ((Number)val).longValue(); + final long longVal = ((Number) val).longValue(); if (longVal < Integer.MIN_VALUE || longVal > Integer.MAX_VALUE) { throw new RuntimeException("Value for tag " + tag + " is not in Integer range: " + longVal); } - return (int)longVal; + return (int) longVal; } /** @@ -1272,16 +1269,16 @@ public Long getUnsignedIntegerAttribute(final short tag) throws SAMException { } if (value instanceof Number) { - final long lValue = ((Number)value).longValue(); + final long lValue = ((Number) value).longValue(); if (SAMUtils.isValidUnsignedIntegerAttribute(lValue)) { return lValue; } else { - throw new SAMException("Unsigned integer value of tag " + - SAMTag.makeStringTag(tag) + " is out of bounds for a 32-bit unsigned integer: " + lValue); + throw new SAMException("Unsigned integer value of tag " + SAMTag.makeStringTag(tag) + + " is out of bounds for a 32-bit unsigned integer: " + lValue); } } else { - throw new SAMException("Unexpected attribute value data type " + value.getClass() + " for tag " + - SAMTag.makeStringTag(tag)); + throw new SAMException("Unexpected attribute value data type " + value.getClass() + " for tag " + + SAMTag.makeStringTag(tag)); } } @@ -1304,16 +1301,16 @@ public Short getShortAttribute(final String tag) { final Object val = getAttribute(tag); if (val == null) return null; if (val instanceof Short) { - return (Short)val; + return (Short) val; } if (!(val instanceof Number)) { throw new RuntimeException("Value for tag " + tag + " is not Number: " + val.getClass()); } - final long longVal = ((Number)val).longValue(); + final long longVal = ((Number) val).longValue(); if (longVal < Short.MIN_VALUE || longVal > Short.MAX_VALUE) { throw new RuntimeException("Value for tag " + tag + " is not in Short range: " + longVal); } - return (short)longVal; + return (short) longVal; } /** @@ -1324,9 +1321,8 @@ public Short getShortAttribute(final String tag) { */ public Byte getByteAttribute(final SAMTag tag) { return getByteAttribute(tag.name()); - } - /** + /** * Get the tag value and attempt to coerce it into the requested type. * @param tag The requested tag. * @return The value of a tag, converted into a Byte if possible. @@ -1336,16 +1332,16 @@ public Byte getByteAttribute(final String tag) { final Object val = getAttribute(tag); if (val == null) return null; if (val instanceof Byte) { - return (Byte)val; + return (Byte) val; } if (!(val instanceof Number)) { throw new RuntimeException("Value for tag " + tag + " is not Number: " + val.getClass()); } - final long longVal = ((Number)val).longValue(); + final long longVal = ((Number) val).longValue(); if (longVal < Byte.MIN_VALUE || longVal > Byte.MAX_VALUE) { throw new RuntimeException("Value for tag " + tag + " is not in Short range: " + longVal); } - return (byte)longVal; + return (byte) longVal; } public String getStringAttribute(final SAMTag tag) { @@ -1356,7 +1352,7 @@ public String getStringAttribute(final String tag) { final Object val = getAttribute(tag); if (val == null) return null; if (val instanceof String) { - return (String)val; + return (String) val; } throw new SAMException("Value for tag " + tag + " is not a String: " + val.getClass()); } @@ -1369,12 +1365,11 @@ public Character getCharacterAttribute(final String tag) { final Object val = getAttribute(tag); if (val == null) return null; if (val instanceof Character) { - return (Character)val; + return (Character) val; } throw new SAMException("Value for tag " + tag + " is not a Character: " + val.getClass()); } - public Float getFloatAttribute(final SAMTag tag) { return getFloatAttribute(tag.name()); } @@ -1383,7 +1378,7 @@ public Float getFloatAttribute(final String tag) { final Object val = getAttribute(tag); if (val == null) return null; if (val instanceof Float) { - return (Float)val; + return (Float) val; } throw new SAMException("Value for tag " + tag + " is not a Float: " + val.getClass()); } @@ -1398,7 +1393,7 @@ public byte[] getByteArrayAttribute(final String tag) { final Object val = getAttribute(tag); if (val == null) return null; if (val instanceof byte[]) { - return (byte[])val; + return (byte[]) val; } throw new SAMException("Value for tag " + tag + " is not a byte[]: " + val.getClass()); } @@ -1432,6 +1427,7 @@ public byte[] getSignedByteArrayAttribute(final String tag) { public short[] getUnsignedShortArrayAttribute(final SAMTag tag) { return getUnsignedShortArrayAttribute(tag.name()); } + public short[] getUnsignedShortArrayAttribute(final String tag) { final Object val = getAttribute(tag); if (val == null) return null; @@ -1457,7 +1453,7 @@ public short[] getSignedShortArrayAttribute(final String tag) { } public int[] getUnsignedIntArrayAttribute(final SAMTag tag) { - return getUnsignedIntArrayAttribute(tag.name()); + return getUnsignedIntArrayAttribute(tag.name()); } public int[] getUnsignedIntArrayAttribute(final String tag) { @@ -1507,11 +1503,11 @@ public boolean isUnsignedArrayAttribute(final String tag) { } private void requireSigned(final String tag) { - if (isUnsignedArrayAttribute(tag)) throw new SAMException("Value for tag " + tag + " is not signed"); + if (isUnsignedArrayAttribute(tag)) throw new SAMException("Value for tag " + tag + " is not signed"); } private void requireUnsigned(final String tag) { - if (!isUnsignedArrayAttribute(tag)) throw new SAMException("Value for tag " + tag + " is not unsigned"); + if (!isUnsignedArrayAttribute(tag)) throw new SAMException("Value for tag " + tag + " is not unsigned"); } /** @@ -1574,7 +1570,7 @@ protected void setAttribute(final short tag, final Object value) { * @see htsjdk.samtools.SAMRecord#setAttribute(java.lang.String, java.lang.Object) * @param tag Binary representation of a 2-char String tag as created by SAMTagUtil. */ - public void setAttribute(final SAMTag tag, final Object value){ + public void setAttribute(final SAMTag tag, final Object value) { setAttribute(tag, value, false); } @@ -1583,7 +1579,7 @@ public void setAttribute(final SAMTag tag, final Object value){ * * @param value the value to be checked * @return true if the value is valid and false otherwise - + * * @deprecated * The attribute type and value checks have been moved directly into * {@link SAMBinaryTagAndValue}. @@ -1692,8 +1688,7 @@ public List getAttributes() { SAMBinaryTagAndValue binaryAttributes = getBinaryAttributes(); final List ret = new ArrayList<>(); while (binaryAttributes != null) { - ret.add(new SAMTagAndValue(SAMTag.makeStringTag(binaryAttributes.tag), - binaryAttributes.value)); + ret.add(new SAMTagAndValue(SAMTag.makeStringTag(binaryAttributes.tag), binaryAttributes.value)); binaryAttributes = binaryAttributes.getNext(); } return ret; @@ -1702,7 +1697,10 @@ public List getAttributes() { /** * @deprecated Use computeIndexingBin() if accessible or GenomicIndexUtil.regionToBin() otherwise. */ - @Deprecated() public int computeIndexingBinIfAbsent(final SAMRecord alignment) { return alignment.computeIndexingBin(); } + @Deprecated() + public int computeIndexingBinIfAbsent(final SAMRecord alignment) { + return alignment.computeIndexingBin(); + } /** * Computes the BAI indexing bin for the record. Invokes getAlignmentEnd() among other methods, which may @@ -1726,7 +1724,6 @@ int computeIndexingBin() { return GenomicIndexUtil.regionToBin(alignmentStart, alignmentEnd) & (int) BinaryCodec.MAX_USHORT; } - /** * @return the SAMFileHeader for this record. If the header is null, the following SAMRecord methods may throw * exceptions: @@ -1784,8 +1781,7 @@ public void setHeader(final SAMFileHeader header) { // mark the reference indices as unresolved mReferenceIndex = null; mMateReferenceIndex = null; - } - else { + } else { // attempt to resolve the existing reference names and indices against the new sequence dictionary, but // don't throw if the names don't appear in the dictionary setReferenceName(mReferenceName); @@ -1807,8 +1803,7 @@ public void setHeaderStrict(final SAMFileHeader header) { // mark the reference indices as unresolved mReferenceIndex = null; mMateReferenceIndex = null; - } - else { + } else { // Attempt to resolve the existing reference names against the new sequence dictionary // and throw if the names don't appear. Integer referenceIndex = resolveIndexFromName(mReferenceName, header, true); @@ -1870,13 +1865,17 @@ public List getAlignmentBlocks() { public List validateCigar(final long recordNumber) { List ret = null; - if (null != getHeader() && getValidationStringency() != ValidationStringency.SILENT && !this.getReadUnmappedFlag()) { + if (null != getHeader() + && getValidationStringency() != ValidationStringency.SILENT + && !this.getReadUnmappedFlag()) { try { - //make sure that the cashed version is good - //wrapped in a try to catch an un-parsable string - return SAMUtils.validateCigar(this, getCigar(), getReferenceIndex(), getAlignmentBlocks(), recordNumber, "Read CIGAR"); - } catch( final IllegalArgumentException e){ - return Collections.singletonList(new SAMValidationError(SAMValidationError.Type.INVALID_CIGAR,e.getMessage(),getReadName(),recordNumber)); + // make sure that the cashed version is good + // wrapped in a try to catch an un-parsable string + return SAMUtils.validateCigar( + this, getCigar(), getReferenceIndex(), getAlignmentBlocks(), recordNumber, "Read CIGAR"); + } catch (final IllegalArgumentException e) { + return Collections.singletonList(new SAMValidationError( + SAMValidationError.Type.INVALID_CIGAR, e.getMessage(), getReadName(), recordNumber)); } } return ret; @@ -1895,10 +1894,12 @@ public boolean equals(final Object o) { if (mInferredInsertSize != samRecord.mInferredInsertSize) return false; if (mMappingQuality != samRecord.mMappingQuality) return false; if (mMateAlignmentStart != samRecord.mMateAlignmentStart) return false; - if (mMateReferenceIndex != null ? !mMateReferenceIndex.equals(samRecord.mMateReferenceIndex) : samRecord.mMateReferenceIndex != null) - return false; - if (mReferenceIndex != null ? !mReferenceIndex.equals(samRecord.mReferenceIndex) : samRecord.mReferenceIndex != null) - return false; + if (mMateReferenceIndex != null + ? !mMateReferenceIndex.equals(samRecord.mMateReferenceIndex) + : samRecord.mMateReferenceIndex != null) return false; + if (mReferenceIndex != null + ? !mReferenceIndex.equals(samRecord.mReferenceIndex) + : samRecord.mReferenceIndex != null) return false; eagerDecode(); samRecord.eagerDecode(); @@ -1907,13 +1908,14 @@ public boolean equals(final Object o) { if (mAttributes != null ? !mAttributes.equals(samRecord.mAttributes) : samRecord.mAttributes != null) return false; if (!Arrays.equals(mBaseQualities, samRecord.mBaseQualities)) return false; - if (mCigar != null ? !mCigar.equals(samRecord.mCigar) : samRecord.mCigar != null) - return false; - if (mMateReferenceName != null ? !mMateReferenceName.equals(samRecord.mMateReferenceName) : samRecord.mMateReferenceName != null) - return false; + if (mCigar != null ? !mCigar.equals(samRecord.mCigar) : samRecord.mCigar != null) return false; + if (mMateReferenceName != null + ? !mMateReferenceName.equals(samRecord.mMateReferenceName) + : samRecord.mMateReferenceName != null) return false; if (!Arrays.equals(mReadBases, samRecord.mReadBases)) return false; - if (mReferenceName != null ? !mReferenceName.equals(samRecord.mReferenceName) : samRecord.mReferenceName != null) - return false; + if (mReferenceName != null + ? !mReferenceName.equals(samRecord.mReferenceName) + : samRecord.mReferenceName != null) return false; return true; } @@ -1971,42 +1973,64 @@ public List isValid(final boolean firstOnly) { if (!getReadPairedFlag()) { if (getProperPairFlagUnchecked()) { if (ret == null) ret = new ArrayList<>(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_FLAG_PROPER_PAIR, "Proper pair flag should not be set for unpaired read.", getReadName())); + ret.add(new SAMValidationError( + SAMValidationError.Type.INVALID_FLAG_PROPER_PAIR, + "Proper pair flag should not be set for unpaired read.", + getReadName())); if (firstOnly) return ret; } if (getMateUnmappedFlagUnchecked()) { if (ret == null) ret = new ArrayList<>(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_FLAG_MATE_UNMAPPED, "Mate unmapped flag should not be set for unpaired read.", getReadName())); + ret.add(new SAMValidationError( + SAMValidationError.Type.INVALID_FLAG_MATE_UNMAPPED, + "Mate unmapped flag should not be set for unpaired read.", + getReadName())); if (firstOnly) return ret; } if (getMateNegativeStrandFlagUnchecked()) { if (ret == null) ret = new ArrayList<>(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_FLAG_MATE_NEG_STRAND, "Mate negative strand flag should not be set for unpaired read.", getReadName())); + ret.add(new SAMValidationError( + SAMValidationError.Type.INVALID_FLAG_MATE_NEG_STRAND, + "Mate negative strand flag should not be set for unpaired read.", + getReadName())); if (firstOnly) return ret; } if (getFirstOfPairFlagUnchecked()) { if (ret == null) ret = new ArrayList<>(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_FLAG_FIRST_OF_PAIR, "First of pair flag should not be set for unpaired read.", getReadName())); + ret.add(new SAMValidationError( + SAMValidationError.Type.INVALID_FLAG_FIRST_OF_PAIR, + "First of pair flag should not be set for unpaired read.", + getReadName())); if (firstOnly) return ret; } if (getSecondOfPairFlagUnchecked()) { if (ret == null) ret = new ArrayList<>(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_FLAG_SECOND_OF_PAIR, "Second of pair flag should not be set for unpaired read.", getReadName())); + ret.add(new SAMValidationError( + SAMValidationError.Type.INVALID_FLAG_SECOND_OF_PAIR, + "Second of pair flag should not be set for unpaired read.", + getReadName())); if (firstOnly) return ret; } if (null != getHeader() && getMateReferenceIndex() != NO_ALIGNMENT_REFERENCE_INDEX) { if (ret == null) ret = new ArrayList<>(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_MATE_REF_INDEX, "MRNM should not be set for unpaired read.", getReadName())); + ret.add(new SAMValidationError( + SAMValidationError.Type.INVALID_MATE_REF_INDEX, + "MRNM should not be set for unpaired read.", + getReadName())); if (firstOnly) return ret; } if (!getMateReferenceName().equals(SAMRecord.NO_ALIGNMENT_REFERENCE_NAME)) { if (ret == null) ret = new ArrayList<>(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_UNPAIRED_MATE_REFERENCE, "Unpaired read mate reference is " + getMateReferenceName() + " not " + SAMRecord.NO_ALIGNMENT_REFERENCE_NAME + " for unpaired read", getReadName())); + ret.add(new SAMValidationError( + SAMValidationError.Type.INVALID_UNPAIRED_MATE_REFERENCE, + "Unpaired read mate reference is " + getMateReferenceName() + " not " + + SAMRecord.NO_ALIGNMENT_REFERENCE_NAME + " for unpaired read", + getReadName())); if (firstOnly) return ret; } } else { - final List errors = isValidReferenceIndexAndPosition(mMateReferenceIndex, mMateReferenceName, - getMateAlignmentStart(), true, firstOnly); + final List errors = isValidReferenceIndexAndPosition( + mMateReferenceIndex, mMateReferenceName, getMateAlignmentStart(), true, firstOnly); if (errors != null) { if (firstOnly) return errors; if (ret == null) ret = new ArrayList(); @@ -2014,101 +2038,129 @@ public List isValid(final boolean firstOnly) { } if (!hasMateReferenceName() && !getMateUnmappedFlag()) { if (ret == null) ret = new ArrayList(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_FLAG_MATE_UNMAPPED, "Mapped mate should have mate reference name", getReadName())); + ret.add(new SAMValidationError( + SAMValidationError.Type.INVALID_FLAG_MATE_UNMAPPED, + "Mapped mate should have mate reference name", + getReadName())); if (firstOnly) return ret; } if (!getFirstOfPairFlagUnchecked() && !getSecondOfPairFlagUnchecked()) { if (ret == null) ret = new ArrayList(); - ret.add(new SAMValidationError(SAMValidationError.Type.PAIRED_READ_NOT_MARKED_AS_FIRST_OR_SECOND, - "Paired read should be marked as first of pair or second of pair.", getReadName())); - if (firstOnly) return ret; - } -/* - TODO: PIC-97 This validation should be enabled, but probably at this point there are too many - BAM files that have the proper pair flag set when read or mate is unmapped. - if (getMateUnmappedFlag() && getProperPairFlagUnchecked()) { - if (ret == null) ret = new ArrayList(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_FLAG_PROPER_PAIR, "Proper pair flag should not be set for unpaired read.", getReadName())); + ret.add(new SAMValidationError( + SAMValidationError.Type.PAIRED_READ_NOT_MARKED_AS_FIRST_OR_SECOND, + "Paired read should be marked as first of pair or second of pair.", + getReadName())); if (firstOnly) return ret; } -*/ + /* + TODO: PIC-97 This validation should be enabled, but probably at this point there are too many + BAM files that have the proper pair flag set when read or mate is unmapped. + if (getMateUnmappedFlag() && getProperPairFlagUnchecked()) { + if (ret == null) ret = new ArrayList(); + ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_FLAG_PROPER_PAIR, "Proper pair flag should not be set for unpaired read.", getReadName())); + if (firstOnly) return ret; + } + */ } if (getInferredInsertSize() > MAX_INSERT_SIZE || getInferredInsertSize() < -MAX_INSERT_SIZE) { if (ret == null) ret = new ArrayList<>(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_INSERT_SIZE, "Insert size out of range", getReadName())); + ret.add(new SAMValidationError( + SAMValidationError.Type.INVALID_INSERT_SIZE, "Insert size out of range", getReadName())); if (firstOnly) return ret; } if (getReadUnmappedFlag()) { if (isSecondaryAlignment()) { if (ret == null) ret = new ArrayList<>(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_FLAG_NOT_PRIM_ALIGNMENT, "Secondary alignment flag should not be set for unmapped read.", getReadName())); + ret.add(new SAMValidationError( + SAMValidationError.Type.INVALID_FLAG_NOT_PRIM_ALIGNMENT, + "Secondary alignment flag should not be set for unmapped read.", + getReadName())); if (firstOnly) return ret; } if (getSupplementaryAlignmentFlag()) { if (ret == null) ret = new ArrayList<>(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_FLAG_SUPPLEMENTARY_ALIGNMENT, "Supplementary alignment flag should not be set for unmapped read.", getReadName())); + ret.add(new SAMValidationError( + SAMValidationError.Type.INVALID_FLAG_SUPPLEMENTARY_ALIGNMENT, + "Supplementary alignment flag should not be set for unmapped read.", + getReadName())); if (firstOnly) return ret; } if (getMappingQuality() != 0) { if (ret == null) ret = new ArrayList<>(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_MAPPING_QUALITY, "MAPQ should be 0 for unmapped read.", getReadName())); + ret.add(new SAMValidationError( + SAMValidationError.Type.INVALID_MAPPING_QUALITY, + "MAPQ should be 0 for unmapped read.", + getReadName())); if (firstOnly) return ret; } /* non-empty CIGAR on unmapped read is now allowed, because there are special reads when SAM is used to store assembly. */ -/* - TODO: PIC-97 This validation should be enabled, but probably at this point there are too many - BAM files that have the proper pair flag set when read or mate is unmapped. - if (getProperPairFlagUnchecked()) { - if (ret == null) ret = new ArrayList<>(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_FLAG_PROPER_PAIR, "Proper pair flag should not be set for unmapped read.", getReadName())); - } -*/ + /* + TODO: PIC-97 This validation should be enabled, but probably at this point there are too many + BAM files that have the proper pair flag set when read or mate is unmapped. + if (getProperPairFlagUnchecked()) { + if (ret == null) ret = new ArrayList<>(); + ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_FLAG_PROPER_PAIR, "Proper pair flag should not be set for unmapped read.", getReadName())); + } + */ } else { if (getMappingQuality() >= 256) { if (ret == null) ret = new ArrayList<>(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_MAPPING_QUALITY, "MAPQ should be < 256.", getReadName())); + ret.add(new SAMValidationError( + SAMValidationError.Type.INVALID_MAPPING_QUALITY, "MAPQ should be < 256.", getReadName())); if (firstOnly) return ret; } if (getCigarLength() == 0) { if (ret == null) ret = new ArrayList<>(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_CIGAR, "CIGAR should have > zero elements for mapped read.", getReadName())); - /* todo - will uncomment once unit tests are added - } else if (getCigar().getReadLength() != getReadLength()) { - if (ret == null) ret = new ArrayList<>(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_CIGAR, "CIGAR read length " + getCigar().getReadLength() + " doesn't match read length " + getReadLength(), getReadName())); - */ + ret.add(new SAMValidationError( + SAMValidationError.Type.INVALID_CIGAR, + "CIGAR should have > zero elements for mapped read.", + getReadName())); + /* todo - will uncomment once unit tests are added + } else if (getCigar().getReadLength() != getReadLength()) { + if (ret == null) ret = new ArrayList<>(); + ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_CIGAR, "CIGAR read length " + getCigar().getReadLength() + " doesn't match read length " + getReadLength(), getReadName())); + */ if (firstOnly) return ret; } if (getHeader() != null && getHeader().getSequenceDictionary().isEmpty()) { if (ret == null) ret = new ArrayList(); - ret.add(new SAMValidationError(SAMValidationError.Type.MISSING_SEQUENCE_DICTIONARY, "Empty sequence dictionary.", getReadName())); + ret.add(new SAMValidationError( + SAMValidationError.Type.MISSING_SEQUENCE_DICTIONARY, + "Empty sequence dictionary.", + getReadName())); if (firstOnly) return ret; } if (!hasReferenceName()) { if (ret == null) ret = new ArrayList<>(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_FLAG_READ_UNMAPPED, "Mapped read should have valid reference name", getReadName())); + ret.add(new SAMValidationError( + SAMValidationError.Type.INVALID_FLAG_READ_UNMAPPED, + "Mapped read should have valid reference name", + getReadName())); if (firstOnly) return ret; } -/* - Oops! We know this is broken in older BAM files, so this having this validation will cause all sorts of - problems! - if (getIndexingBin() != null && getIndexingBin() != computeIndexingBin()) { - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_INDEXING_BIN, - "Indexing bin (" + getIndexingBin() + ") does not agree with computed value (" + computeIndexingBin() + ")", - getReadName())); + /* + Oops! We know this is broken in older BAM files, so this having this validation will cause all sorts of + problems! + if (getIndexingBin() != null && getIndexingBin() != computeIndexingBin()) { + ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_INDEXING_BIN, + "Indexing bin (" + getIndexingBin() + ") does not agree with computed value (" + computeIndexingBin() + ")", + getReadName())); - } -*/ + } + */ } // Validate the RG ID is found in header - final String rgId = (String)getAttribute(SAMTag.RG); + final String rgId = (String) getAttribute(SAMTag.RG); if (rgId != null && getHeader() != null && getHeader().getReadGroup(rgId) == null) { - if (ret == null) ret = new ArrayList<>(); - ret.add(new SAMValidationError(SAMValidationError.Type.READ_GROUP_NOT_FOUND, - "RG ID on SAMRecord not found in header: " + rgId, getReadName())); - if (firstOnly) return ret; + if (ret == null) ret = new ArrayList<>(); + ret.add(new SAMValidationError( + SAMValidationError.Type.READ_GROUP_NOT_FOUND, + "RG ID on SAMRecord not found in header: " + rgId, + getReadName())); + if (firstOnly) return ret; } - final List errors = isValidReferenceIndexAndPosition(mReferenceIndex, mReferenceName, getAlignmentStart(), false); + final List errors = + isValidReferenceIndexAndPosition(mReferenceIndex, mReferenceName, getAlignmentStart(), false); if (errors != null) { if (ret == null) ret = new ArrayList<>(); ret.addAll(errors); @@ -2153,27 +2205,35 @@ public List isValid(final boolean firstOnly) { } } */ - - if (this.getReadLength() != getBaseQualities().length && !Arrays.equals(getBaseQualities(), NULL_QUALS)) { + + if (this.getReadLength() != getBaseQualities().length && !Arrays.equals(getBaseQualities(), NULL_QUALS)) { if (ret == null) ret = new ArrayList<>(); - ret.add(new SAMValidationError(SAMValidationError.Type.MISMATCH_READ_LENGTH_AND_QUALS_LENGTH, - "Read length does not match quals length", getReadName())); + ret.add(new SAMValidationError( + SAMValidationError.Type.MISMATCH_READ_LENGTH_AND_QUALS_LENGTH, + "Read length does not match quals length", + getReadName())); if (firstOnly) return ret; } - if (getMateReferenceName().equals(SAMRecord.NO_ALIGNMENT_REFERENCE_NAME) && - getMateAlignmentStart() != SAMRecord.NO_ALIGNMENT_START) { + if (getMateReferenceName().equals(SAMRecord.NO_ALIGNMENT_REFERENCE_NAME) + && getMateAlignmentStart() != SAMRecord.NO_ALIGNMENT_START) { if (ret == null) ret = new ArrayList<>(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_UNALIGNED_MATE_START, - "The unaligned mate start position is " + getAlignmentStart() + ", should be " + SAMRecord.NO_ALIGNMENT_START, + ret.add(new SAMValidationError( + SAMValidationError.Type.INVALID_UNALIGNED_MATE_START, + "The unaligned mate start position is " + getAlignmentStart() + ", should be " + + SAMRecord.NO_ALIGNMENT_START, getReadName())); if (firstOnly) return ret; } - if (getReadLength() != 0 && getCigar().getReadLength() != 0 && getCigar().getReadLength() != getReadLength()) { + if (getReadLength() != 0 + && getCigar().getReadLength() != 0 + && getCigar().getReadLength() != getReadLength()) { if (ret == null) ret = new ArrayList<>(); - ret.add(new SAMValidationError(SAMValidationError.Type.MISMATCH_CIGAR_SEQ_LENGTH, - "CIGAR covers " + getCigar().getReadLength() + " bases but the sequence is " + getReadLength() + " read bases ", + ret.add(new SAMValidationError( + SAMValidationError.Type.MISMATCH_CIGAR_SEQ_LENGTH, + "CIGAR covers " + getCigar().getReadLength() + " bases but the sequence is " + getReadLength() + + " read bases ", getReadName())); if (firstOnly) return ret; } @@ -2182,7 +2242,7 @@ public List isValid(final boolean firstOnly) { if (ret == null) ret = new ArrayList<>(); ret.add(new SAMValidationError( SAMValidationError.Type.MISMATCH_SEQ_QUAL_LENGTH, - "Read length is " + getReadLength() + " bases but have " + mBaseQualities.length + " qualities ", + "Read length is " + getReadLength() + " bases but have " + mBaseQualities.length + " qualities ", getReadName())); if (firstOnly) return ret; } @@ -2195,7 +2255,7 @@ public List isValid(final boolean firstOnly) { /** * Gets the source of this SAM record -- both the reader that retrieved the record and the position on disk from - * whence it came. + * whence it came. * @return The file source. Note that the reader will be null if the reader source has not be set. */ public SAMFileSource getFileSource() { @@ -2210,13 +2270,17 @@ public void setFileSource(final SAMFileSource fileSource) { mFileSource = fileSource; } - private List isValidReferenceIndexAndPosition(final Integer referenceIndex, final String referenceName, - final int alignmentStart, final boolean isMate) { + private List isValidReferenceIndexAndPosition( + final Integer referenceIndex, final String referenceName, final int alignmentStart, final boolean isMate) { return isValidReferenceIndexAndPosition(referenceIndex, referenceName, alignmentStart, isMate, false); } - private List isValidReferenceIndexAndPosition(final Integer referenceIndex, final String referenceName, - final int alignmentStart, final boolean isMate, final boolean firstOnly) { + private List isValidReferenceIndexAndPosition( + final Integer referenceIndex, + final String referenceName, + final int alignmentStart, + final boolean isMate, + final boolean firstOnly) { final boolean hasReference = hasReferenceName(referenceIndex, referenceName); // ret is only instantiate if there are errors to report, in order to reduce GC in the typical case @@ -2225,27 +2289,44 @@ private List isValidReferenceIndexAndPosition(final Integer if (!hasReference) { if (alignmentStart != 0) { if (ret == null) ret = new ArrayList<>(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_ALIGNMENT_START, buildMessage("Alignment start should be 0 because reference name = *.", isMate), getReadName())); + ret.add(new SAMValidationError( + SAMValidationError.Type.INVALID_ALIGNMENT_START, + buildMessage("Alignment start should be 0 because reference name = *.", isMate), + getReadName())); if (firstOnly) return ret; } } else { if (alignmentStart == 0) { if (ret == null) ret = new ArrayList<>(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_ALIGNMENT_START, buildMessage("Alignment start should != 0 because reference name != *.", isMate), getReadName())); + ret.add(new SAMValidationError( + SAMValidationError.Type.INVALID_ALIGNMENT_START, + buildMessage("Alignment start should != 0 because reference name != *.", isMate), + getReadName())); if (firstOnly) return ret; } if (getHeader() != null && !getHeader().getSequenceDictionary().isEmpty()) { - final SAMSequenceRecord sequence = - (referenceIndex != null? getHeader().getSequence(referenceIndex): getHeader().getSequence(referenceName)); + final SAMSequenceRecord sequence = (referenceIndex != null + ? getHeader().getSequence(referenceIndex) + : getHeader().getSequence(referenceName)); if (sequence == null) { if (ret == null) ret = new ArrayList<>(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_REFERENCE_INDEX, buildMessage("Reference sequence not found in sequence dictionary.", isMate), getReadName())); + ret.add(new SAMValidationError( + SAMValidationError.Type.INVALID_REFERENCE_INDEX, + buildMessage("Reference sequence not found in sequence dictionary.", isMate), + getReadName())); if (firstOnly) return ret; } else { if (alignmentStart > sequence.getSequenceLength()) { if (ret == null) ret = new ArrayList<>(); - ret.add(new SAMValidationError(SAMValidationError.Type.INVALID_ALIGNMENT_START, buildMessage("Alignment start (" + alignmentStart + ") must be <= reference sequence length (" + - sequence.getSequenceLength() + ") on reference " + sequence.getSequenceName(), isMate), getReadName())); + ret.add(new SAMValidationError( + SAMValidationError.Type.INVALID_ALIGNMENT_START, + buildMessage( + "Alignment start (" + alignmentStart + + ") must be <= reference sequence length (" + + sequence.getSequenceLength() + ") on reference " + + sequence.getSequenceName(), + isMate), + getReadName())); if (firstOnly) return ret; } } @@ -2266,7 +2347,7 @@ private String buildMessage(final String baseMessage, final boolean isMate) { */ @Override public Object clone() throws CloneNotSupportedException { - final SAMRecord newRecord = (SAMRecord)super.clone(); + final SAMRecord newRecord = (SAMRecord) super.clone(); if (mAttributes != null) { newRecord.mAttributes = this.mAttributes.copy(); } @@ -2317,8 +2398,8 @@ public String toString() { } /** - Returns the record in the SAM line-based text format. Fields are separated by - '\t' characters. The returned String is NOT terminated by a newline. + * Returns the record in the SAM line-based text format. Fields are separated by + * '\t' characters. The returned String is NOT terminated by a newline. */ public String getSAMString() { return SAMTextWriter.getSAMString(this); @@ -2336,8 +2417,8 @@ public String getPairedReadName() { } return builder.toString(); } - - /** + + /** * shortcut to

SAMFlag.getFlags( this.getFlags() );
* @returns a set of SAMFlag associated to this sam record */ public final Set getSAMFlags() { @@ -2363,7 +2444,7 @@ public final Object getTransientAttribute(final Object key) { * then stored as transient attributes to avoid frequent re-computation. */ public final Object setTransientAttribute(final Object key, final Object value) { - if (this.transientAttributes == null) this.transientAttributes = new HashMap(); + if (this.transientAttributes == null) this.transientAttributes = new HashMap(); return this.transientAttributes.put(key, value); } @@ -2405,24 +2486,27 @@ public void reverseComplement(boolean inplace) { * non-null attributes specified by tagsToRevcomp and reverse and non-null attributes * specified by tagsToReverse. */ - public void reverseComplement(final Collection tagsToRevcomp, final Collection tagsToReverse, boolean inplace) { + public void reverseComplement( + final Collection tagsToRevcomp, final Collection tagsToReverse, boolean inplace) { final byte[] readBases = inplace ? getReadBases() : getReadBases().clone(); SequenceUtil.reverseComplement(readBases); setReadBases(readBases); - final byte qualities[] = inplace ? getBaseQualities() : getBaseQualities().clone(); + final byte qualities[] = + inplace ? getBaseQualities() : getBaseQualities().clone(); reverseArray(qualities); setBaseQualities(qualities); // Deal with tags that need to be reverse complemented if (tagsToRevcomp != null) { - for (final String tag: tagsToRevcomp) { + for (final String tag : tagsToRevcomp) { Object value = getAttribute(tag); if (value != null) { if (value instanceof byte[]) { value = inplace ? value : ((byte[]) value).clone(); SequenceUtil.reverseComplement((byte[]) value); } else if (value instanceof String) { - //SequenceUtil.reverseComplement is in-place for bytes but copies Strings since they are immutable. + // SequenceUtil.reverseComplement is in-place for bytes but copies Strings since they are + // immutable. value = SequenceUtil.reverseComplement((String) value); } else { throw new UnsupportedOperationException("Don't know how to reverse complement: " + value); @@ -2453,7 +2537,8 @@ public void reverseComplement(final Collection tagsToRevcomp, final Coll value = inplace ? value : ((float[]) value).clone(); reverseArray((float[]) value); } else { - throw new UnsupportedOperationException("Reversing array attribute of type " + value.getClass().getComponentType() + " not supported."); + throw new UnsupportedOperationException("Reversing array attribute of type " + + value.getClass().getComponentType() + " not supported."); } } else { throw new UnsupportedOperationException("Don't know how to reverse: " + value); @@ -2466,7 +2551,7 @@ public void reverseComplement(final Collection tagsToRevcomp, final Coll } private static void reverseArray(final byte[] array) { - for (int i=0, j=array.length-1; i libraryIds = new ConcurrentHashMap<>(); // from library string to library id private short nextLibraryId = 1; - + private ScoringStrategy scoringStrategy = ScoringStrategy.TOTAL_MAPPED_REFERENCE_LENGTH; - + public SAMRecordDuplicateComparator() {} - @Deprecated // This results in sort order depending on the order in which the headers are listed. Will be removed in future version. + @Deprecated // This results in sort order depending on the order in which the headers are listed. Will be removed + // in future version. public SAMRecordDuplicateComparator(final List headers) { populateLibraryIds(headers); } @@ -99,11 +101,13 @@ public void setScoringStrategy(final ScoringStrategy scoringStrategy) { /** * Populates the set of transient attributes on SAMRecords if they are not already there. */ - synchronized private void populateTransientAttributes(final SAMRecord... recs) { + private synchronized void populateTransientAttributes(final SAMRecord... recs) { for (final SAMRecord rec : recs) { if (rec.getTransientAttribute(Attr.LibraryId) != null) continue; rec.setTransientAttribute(Attr.LibraryId, getLibraryId(rec)); - rec.setTransientAttribute(Attr.ReadCoordinate, rec.getReadNegativeStrandFlag() ? rec.getUnclippedEnd() : rec.getUnclippedStart()); + rec.setTransientAttribute( + Attr.ReadCoordinate, + rec.getReadNegativeStrandFlag() ? rec.getUnclippedEnd() : rec.getUnclippedStart()); rec.setTransientAttribute(Attr.MateCoordinate, getMateCoordinate(rec)); } } @@ -151,7 +155,7 @@ private int compareOrientationByteCollapseOrientation(final int orientation1, fi // R == RF, R == RR if (F == orientation1 || R == orientation1) { // first orientation is fragment /** - * We want + * We want * F == FR, F == FF * R == RF, R == RR */ @@ -159,20 +163,18 @@ private int compareOrientationByteCollapseOrientation(final int orientation1, fi if (F == orientation2 || FR == orientation2 || FF == orientation2) { return 0; } - } - else { // R == orientation1 + } else { // R == orientation1 if (R == orientation2 || RF == orientation2 || RR == orientation2) { return 0; } } - } - else if (F == orientation2 || R == orientation2) { // first orientation is paired, second is fragment + } else if (F == orientation2 || R == orientation2) { // first orientation is paired, second is fragment return -compareOrientationByteCollapseOrientation(orientation2, orientation1); } return orientation1 - orientation2; } - + /** * Returns a single byte that encodes the orientation of the two reads in a pair. */ @@ -185,9 +187,9 @@ private static byte getPairedOrientationByte(final boolean read1NegativeStrand, else return SAMRecordDuplicateComparator.FF; } } - + private int getFragmentOrientation(final SAMRecord record) { - return record.getReadNegativeStrandFlag() ? SAMRecordDuplicateComparator.R : SAMRecordDuplicateComparator.F; + return record.getReadNegativeStrandFlag() ? SAMRecordDuplicateComparator.R : SAMRecordDuplicateComparator.F; } private int getPairedOrientation(final SAMRecord record) { @@ -208,12 +210,14 @@ private int getMateReferenceIndex(final SAMRecord record) { private int getMateCoordinate(final SAMRecord record) { if (record.getReadPairedFlag() && !record.getReadUnmappedFlag() && !record.getMateUnmappedFlag()) { - return record.getMateNegativeStrandFlag() ? SAMUtils.getMateUnclippedEnd(record) : SAMUtils.getMateUnclippedStart(record); + return record.getMateNegativeStrandFlag() + ? SAMUtils.getMateUnclippedEnd(record) + : SAMUtils.getMateUnclippedStart(record); } else { return -1; } } - + /** Is one end of a pair, or the fragment, unmapped? */ private boolean hasUnmappedEnd(final SAMRecord record) { return (record.getReadUnmappedFlag() || (record.getReadPairedFlag() && record.getMateUnmappedFlag())); @@ -223,11 +227,10 @@ private boolean hasUnmappedEnd(final SAMRecord record) { private boolean hasMappedEnd(final SAMRecord record) { return (!record.getReadUnmappedFlag() || (record.getReadPairedFlag() && !record.getMateUnmappedFlag())); } - + /** Is this paired end and are both ends of a pair mapped */ private boolean pairedEndAndBothMapped(final SAMRecord record) { return (record.getReadPairedFlag() && !record.getReadUnmappedFlag() && !record.getMateUnmappedFlag()); - } /** @@ -236,12 +239,12 @@ private boolean pairedEndAndBothMapped(final SAMRecord record) { * Two records are compared based on if they are duplicates of each other, and then based * on if they should be prioritized for being the most "representative". Typically, the representative * is the record in the SAM file that is *not* marked as a duplicate within a set of duplicates. - * + * * Compare by file order, then duplicate scoring strategy, read name. - * + * * If both reads are paired and both ends mapped, always prefer the first end over the second end. This is needed to - * properly choose the first end for optical duplicate identification when both ends are mapped to the same position etc. - */ + * properly choose the first end for optical duplicate identification when both ends are mapped to the same position etc. + */ @Override public int compare(final SAMRecord samRecord1, final SAMRecord samRecord2) { populateTransientAttributes(samRecord1, samRecord2); @@ -274,13 +277,17 @@ public int compare(final SAMRecord samRecord1, final SAMRecord samRecord2) { /** * Compares: Library identifier, reference index, read coordinate, orientation of the read (or read pair), mate's coordinate (if paired and mapped), * mapped ends, ... - * + * * collapseOrientation - true if we want cases where fragment orientation to paired end orientation can be equal (ex. F == FR), false otherwise * considerNumberOfEndsMappedAndPairing - true if we want to prefer paired ends with both ends mapped over paired ends with only one end mapped, or paired ends with end * mapped over fragment reads, false otherwise. - * + * */ - private int fileOrderCompare(final SAMRecord samRecord1, final SAMRecord samRecord2, final boolean collapseOrientation, final boolean considerNumberOfEndsMappedAndPairing) { + private int fileOrderCompare( + final SAMRecord samRecord1, + final SAMRecord samRecord2, + final boolean collapseOrientation, + final boolean considerNumberOfEndsMappedAndPairing) { populateTransientAttributes(samRecord1, samRecord2); int cmp; @@ -304,11 +311,9 @@ private int fileOrderCompare(final SAMRecord samRecord1, final SAMRecord samReco // NB: this accounts for unmapped reads to be placed at the ends of the file if (samRecord1Value == -1) { cmp = (samRecord2Value == -1) ? 0 : 1; - } - else if (samRecord2Value == -1) { + } else if (samRecord2Value == -1) { cmp = -1; - } - else { + } else { cmp = samRecord1Value - samRecord2Value; } } @@ -324,8 +329,7 @@ else if (samRecord2Value == -1) { samRecord2Value = getPairedOrientation(samRecord2); if (collapseOrientation) { cmp = compareOrientationByteCollapseOrientation(samRecord1Value, samRecord2Value); - } - else { + } else { cmp = samRecord1Value - samRecord2Value; } } @@ -340,7 +344,8 @@ else if (samRecord2Value == -1) { // mate's coordinate if (cmp == 0) { samRecord1Value = (Integer) samRecord1.getTransientAttribute(Attr.MateCoordinate); - samRecord2Value = (Integer) samRecord2.getTransientAttribute(Attr.MateCoordinate);; + samRecord2Value = (Integer) samRecord2.getTransientAttribute(Attr.MateCoordinate); + ; cmp = samRecord1Value - samRecord2Value; } } @@ -357,8 +362,7 @@ else if (samRecord2Value == -1) { samRecord1Value = hasUnmappedEnd(samRecord1) ? 1 : 0; samRecord2Value = hasUnmappedEnd(samRecord2) ? 1 : 0; cmp = samRecord1Value - samRecord2Value; - } - else { // if we care if one is paired and the other is not + } else { // if we care if one is paired and the other is not cmp = samRecord1.getReadPairedFlag() ? -1 : 1; } } diff --git a/src/main/java/htsjdk/samtools/SAMRecordFactory.java b/src/main/java/htsjdk/samtools/SAMRecordFactory.java index 0db0646c4b..f87f1950ab 100644 --- a/src/main/java/htsjdk/samtools/SAMRecordFactory.java +++ b/src/main/java/htsjdk/samtools/SAMRecordFactory.java @@ -12,17 +12,18 @@ public interface SAMRecordFactory { public SAMRecord createSAMRecord(SAMFileHeader header); /** Create a new BAM Record. */ - public BAMRecord createBAMRecord(final SAMFileHeader header, - final int referenceSequenceIndex, - final int alignmentStart, - final short readNameLength, - final short mappingQuality, - final int indexingBin, - final int cigarLen, - final int flags, - final int readLen, - final int mateReferenceSequenceIndex, - final int mateAlignmentStart, - final int insertSize, - final byte[] variableLengthBlock); + public BAMRecord createBAMRecord( + final SAMFileHeader header, + final int referenceSequenceIndex, + final int alignmentStart, + final short readNameLength, + final short mappingQuality, + final int indexingBin, + final int cigarLen, + final int flags, + final int readLen, + final int mateReferenceSequenceIndex, + final int mateAlignmentStart, + final int insertSize, + final byte[] variableLengthBlock); } diff --git a/src/main/java/htsjdk/samtools/SAMRecordIterator.java b/src/main/java/htsjdk/samtools/SAMRecordIterator.java index 6955043bfd..c337c3836c 100755 --- a/src/main/java/htsjdk/samtools/SAMRecordIterator.java +++ b/src/main/java/htsjdk/samtools/SAMRecordIterator.java @@ -48,5 +48,4 @@ public interface SAMRecordIterator extends CloseableIterator { * @return This SAMRecordIterator */ public SAMRecordIterator assertSorted(SAMFileHeader.SortOrder sortOrder); - } diff --git a/src/main/java/htsjdk/samtools/SAMRecordQueryHashComparator.java b/src/main/java/htsjdk/samtools/SAMRecordQueryHashComparator.java index dce2ffb6de..8b8bcfe987 100644 --- a/src/main/java/htsjdk/samtools/SAMRecordQueryHashComparator.java +++ b/src/main/java/htsjdk/samtools/SAMRecordQueryHashComparator.java @@ -24,7 +24,6 @@ package htsjdk.samtools; import htsjdk.samtools.util.Murmur3; - import java.io.Serializable; /** @@ -67,6 +66,7 @@ public int fileOrderCompare(final SAMRecord lhs, final SAMRecord rhs) { /** Compares the hash values for two records. */ private int compareHashes(final SAMRecord lhs, final SAMRecord rhs) { - return Integer.compare(this.hasher.hashUnencodedChars(lhs.getReadName()), this.hasher.hashUnencodedChars(rhs.getReadName())); + return Integer.compare( + this.hasher.hashUnencodedChars(lhs.getReadName()), this.hasher.hashUnencodedChars(rhs.getReadName())); } } diff --git a/src/main/java/htsjdk/samtools/SAMRecordQueryNameComparator.java b/src/main/java/htsjdk/samtools/SAMRecordQueryNameComparator.java index 6e222f61fb..5ef404000c 100644 --- a/src/main/java/htsjdk/samtools/SAMRecordQueryNameComparator.java +++ b/src/main/java/htsjdk/samtools/SAMRecordQueryNameComparator.java @@ -44,15 +44,15 @@ public int compare(final SAMRecord samRecord1, final SAMRecord samRecord2) { if (r1Paired || r2Paired) { if (!r1Paired) return 1; else if (!r2Paired) return -1; - else if (samRecord1.getFirstOfPairFlag() && samRecord2.getSecondOfPairFlag()) return -1; + else if (samRecord1.getFirstOfPairFlag() && samRecord2.getSecondOfPairFlag()) return -1; else if (samRecord1.getSecondOfPairFlag() && samRecord2.getFirstOfPairFlag()) return 1; } if (samRecord1.getReadNegativeStrandFlag() != samRecord2.getReadNegativeStrandFlag()) { - return (samRecord1.getReadNegativeStrandFlag()? 1: -1); + return (samRecord1.getReadNegativeStrandFlag() ? 1 : -1); } if (samRecord1.isSecondaryAlignment() != samRecord2.isSecondaryAlignment()) { - return samRecord2.isSecondaryAlignment()? -1: 1; + return samRecord2.isSecondaryAlignment() ? -1 : 1; } if (samRecord1.getSupplementaryAlignmentFlag() != samRecord2.getSupplementaryAlignmentFlag()) { return samRecord2.getSupplementaryAlignmentFlag() ? -1 : 1; diff --git a/src/main/java/htsjdk/samtools/SAMRecordSetBuilder.java b/src/main/java/htsjdk/samtools/SAMRecordSetBuilder.java index 111c67ad49..a89b98ccf0 100644 --- a/src/main/java/htsjdk/samtools/SAMRecordSetBuilder.java +++ b/src/main/java/htsjdk/samtools/SAMRecordSetBuilder.java @@ -31,13 +31,11 @@ import htsjdk.samtools.util.RuntimeIOException; import htsjdk.samtools.util.SequenceUtil; import htsjdk.samtools.util.TestUtil; - import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.util.*; - /** * Factory class for creating SAMRecords for testing purposes. Various methods can be called * to add new SAM records (or pairs of records) to a list which can then be returned at @@ -49,12 +47,11 @@ */ public class SAMRecordSetBuilder implements Iterable { private static final String[] chroms = { - "chr1", "chr2", "chr3", "chr4", "chr5", "chr6", "chr7", "chr8", "chr9", "chr10", - "chr11", "chr12", "chr13", "chr14", "chr15", "chr16", "chr17", "chr18", "chr19", "chr20", - "chr21", "chr22", "chrX", "chrY", "chrM" + "chr1", "chr2", "chr3", "chr4", "chr5", "chr6", "chr7", "chr8", "chr9", "chr10", + "chr11", "chr12", "chr13", "chr14", "chr15", "chr16", "chr17", "chr18", "chr19", "chr20", + "chr21", "chr22", "chrX", "chrY", "chrM" }; - private static final String READ_GROUP_ID = "1"; private static final String SAMPLE = "FREE_SAMPLE"; private final Random random = new Random(TestUtil.RANDOM_SEED); @@ -74,7 +71,8 @@ public class SAMRecordSetBuilder implements Iterable { public static final int DEFAULT_CHROMOSOME_LENGTH = 200_000_000; - public static final ScoringStrategy DEFAULT_DUPLICATE_SCORING_STRATEGY = ScoringStrategy.TOTAL_MAPPED_REFERENCE_LENGTH; + public static final ScoringStrategy DEFAULT_DUPLICATE_SCORING_STRATEGY = + ScoringStrategy.TOTAL_MAPPED_REFERENCE_LENGTH; /** * Constructs a new SAMRecordSetBuilder with all the data needed to keep the records @@ -94,16 +92,25 @@ public SAMRecordSetBuilder(final boolean sortForMe, final SAMFileHeader.SortOrde this(sortForMe, sortOrder, true); } - public SAMRecordSetBuilder(final boolean sortForMe, final SAMFileHeader.SortOrder sortOrder, final boolean addReadGroup) { + public SAMRecordSetBuilder( + final boolean sortForMe, final SAMFileHeader.SortOrder sortOrder, final boolean addReadGroup) { this(sortForMe, sortOrder, addReadGroup, DEFAULT_CHROMOSOME_LENGTH); } - public SAMRecordSetBuilder(final boolean sortForMe, final SAMFileHeader.SortOrder sortOrder, final boolean addReadGroup, final int defaultChromosomeLength) { + public SAMRecordSetBuilder( + final boolean sortForMe, + final SAMFileHeader.SortOrder sortOrder, + final boolean addReadGroup, + final int defaultChromosomeLength) { this(sortForMe, sortOrder, addReadGroup, defaultChromosomeLength, DEFAULT_DUPLICATE_SCORING_STRATEGY); } - public SAMRecordSetBuilder(final boolean sortForMe, final SAMFileHeader.SortOrder sortOrder, final boolean addReadGroup, - final int defaultChromosomeLength, final ScoringStrategy duplicateScoringStrategy) { + public SAMRecordSetBuilder( + final boolean sortForMe, + final SAMFileHeader.SortOrder sortOrder, + final boolean addReadGroup, + final int defaultChromosomeLength, + final ScoringStrategy duplicateScoringStrategy) { this.header = makeDefaultHeader(sortOrder, defaultChromosomeLength, addReadGroup); @@ -180,8 +187,9 @@ public void setHeader(final SAMFileHeader header) { * The record should already have the DS and MC tags computed */ public void addRecord(final SAMRecord record) { - if (record.getReadPairedFlag() && !record.getMateUnmappedFlag() && - null == record.getAttribute(SAMTag.MC.getBinaryTag())) { + if (record.getReadPairedFlag() + && !record.getMateUnmappedFlag() + && null == record.getAttribute(SAMTag.MC.getBinaryTag())) { throw new SAMException("Mate Cigar tag (MC) not found in: " + record.getReadName()); } this.records.add(record); @@ -196,7 +204,9 @@ public CloseableIterator iterator() { private final Iterator iterator = records.iterator(); @Override - public void close() { /** Do nothing. */} + public void close() { + /** Do nothing. */ + } @Override public boolean hasNext() { @@ -220,13 +230,21 @@ public void remove() { * cigar string, quality string or default quality score. This does not modify the flag field, which should be updated * if desired before adding the return to the list of records. */ - private SAMRecord createReadNoFlag(final String name, final int contig, final int start, final boolean negativeStrand, - final boolean recordUnmapped, final String cigar, final String qualityString, - final int defaultQuality) throws SAMException { + private SAMRecord createReadNoFlag( + final String name, + final int contig, + final int start, + final boolean negativeStrand, + final boolean recordUnmapped, + final String cigar, + final String qualityString, + final int defaultQuality) + throws SAMException { final SAMRecord rec = new SAMRecord(this.header); rec.setReadName(name); if (header.getSequenceDictionary().size() <= contig) { - throw new SAMException("Contig too big [" + header.getSequenceDictionary().size() + " < " + contig); + throw new SAMException( + "Contig too big [" + header.getSequenceDictionary().size() + " < " + contig); } if (0 <= contig) { rec.setReferenceIndex(contig); @@ -277,20 +295,37 @@ public SAMRecord addFrag(final String name, final int contig, final int start, f * Adds a fragment record (mapped or unmapped) to the set using the provided contig start and optionally the strand, * cigar string, quality string or default quality score. */ - public SAMRecord addFrag(final String name, final int contig, final int start, final boolean negativeStrand, - final boolean recordUnmapped, final String cigar, final String qualityString, - final int defaultQuality) throws SAMException { - return addFrag(name, contig, start, negativeStrand, recordUnmapped, cigar, qualityString, defaultQuality, false); + public SAMRecord addFrag( + final String name, + final int contig, + final int start, + final boolean negativeStrand, + final boolean recordUnmapped, + final String cigar, + final String qualityString, + final int defaultQuality) + throws SAMException { + return addFrag( + name, contig, start, negativeStrand, recordUnmapped, cigar, qualityString, defaultQuality, false); } /** * Adds a fragment record (mapped or unmapped) to the set using the provided contig start and optionally the strand, * cigar string, quality string or default quality score. */ - public SAMRecord addFrag(final String name, final int contig, final int start, final boolean negativeStrand, - final boolean recordUnmapped, final String cigar, final String qualityString, - final int defaultQuality, final boolean isSecondary) throws SAMException { - final htsjdk.samtools.SAMRecord rec = createReadNoFlag(name, contig, start, negativeStrand, recordUnmapped, cigar, qualityString, defaultQuality); + public SAMRecord addFrag( + final String name, + final int contig, + final int start, + final boolean negativeStrand, + final boolean recordUnmapped, + final String cigar, + final String qualityString, + final int defaultQuality, + final boolean isSecondary) + throws SAMException { + final htsjdk.samtools.SAMRecord rec = createReadNoFlag( + name, contig, start, negativeStrand, recordUnmapped, cigar, qualityString, defaultQuality); if (isSecondary) { rec.setSecondaryAlignment(true); } @@ -302,10 +337,20 @@ public SAMRecord addFrag(final String name, final int contig, final int start, f * Adds a fragment record (mapped or unmapped) to the set using the provided contig start and optionally the strand, * cigar string, quality string or default quality score. */ - public SAMRecord addFrag(final String name, final int contig, final int start, final boolean negativeStrand, - final boolean recordUnmapped, final String cigar, final String qualityString, - final int defaultQuality, final boolean isSecondary, final boolean isSupplementary) throws SAMException { - final htsjdk.samtools.SAMRecord rec = createReadNoFlag(name, contig, start, negativeStrand, recordUnmapped, cigar, qualityString, defaultQuality); + public SAMRecord addFrag( + final String name, + final int contig, + final int start, + final boolean negativeStrand, + final boolean recordUnmapped, + final String cigar, + final String qualityString, + final int defaultQuality, + final boolean isSecondary, + final boolean isSupplementary) + throws SAMException { + final htsjdk.samtools.SAMRecord rec = createReadNoFlag( + name, contig, start, negativeStrand, recordUnmapped, cigar, qualityString, defaultQuality); if (isSecondary) { rec.setSecondaryAlignment(true); } @@ -335,8 +380,9 @@ private void fillInBasesAndQualities(final SAMRecord rec, final String qualitySt * If the record contains a cigar with non-zero read length, return that length, otherwise, return readLength */ private int getReadLengthFromCigar(final SAMRecord rec) { - return (rec.getCigar() != null && - rec.getCigar().getReadLength() != 0) ? rec.getCigar().getReadLength() : readLength; + return (rec.getCigar() != null && rec.getCigar().getReadLength() != 0) + ? rec.getCigar().getReadLength() + : readLength; } /** @@ -420,24 +466,60 @@ public void addPair(final String name, final int contig, final int start1, final * Adds a pair of records (mapped or unmmapped) to the set using the provided contig starts. * The pair is assumed to be a well formed pair sitting on a single contig. */ - public List addPair(final String name, final int contig, final int start1, final int start2, - final boolean record1Unmapped, final boolean record2Unmapped, final String cigar1, - final String cigar2, final boolean strand1, final boolean strand2, final int defaultQuality) { - return this.addPair(name, contig, contig, start1, start2, record1Unmapped, record2Unmapped, cigar1, cigar2, strand1, strand2, false, false, defaultQuality); + public List addPair( + final String name, + final int contig, + final int start1, + final int start2, + final boolean record1Unmapped, + final boolean record2Unmapped, + final String cigar1, + final String cigar2, + final boolean strand1, + final boolean strand2, + final int defaultQuality) { + return this.addPair( + name, + contig, + contig, + start1, + start2, + record1Unmapped, + record2Unmapped, + cigar1, + cigar2, + strand1, + strand2, + false, + false, + defaultQuality); } /** * Adds a pair of records (mapped or unmmapped) to the set using the provided contig starts. * The pair is assumed to be a well formed pair sitting on a single contig. */ - public List addPair(final String name, final int contig1, final int contig2, final int start1, final int start2, - final boolean record1Unmapped, final boolean record2Unmapped, final String cigar1, - final String cigar2, final boolean strand1, final boolean strand2, final boolean record1NonPrimary, - final boolean record2NonPrimary, final int defaultQuality) { + public List addPair( + final String name, + final int contig1, + final int contig2, + final int start1, + final int start2, + final boolean record1Unmapped, + final boolean record2Unmapped, + final String cigar1, + final String cigar2, + final boolean strand1, + final boolean strand2, + final boolean record1NonPrimary, + final boolean record2NonPrimary, + final int defaultQuality) { final List recordsList = new LinkedList<>(); - final SAMRecord end1 = createReadNoFlag(name, contig1, start1, strand1, record1Unmapped, cigar1, null, defaultQuality); - final SAMRecord end2 = createReadNoFlag(name, contig2, start2, strand2, record2Unmapped, cigar2, null, defaultQuality); + final SAMRecord end1 = + createReadNoFlag(name, contig1, start1, strand1, record1Unmapped, cigar1, null, defaultQuality); + final SAMRecord end2 = + createReadNoFlag(name, contig2, start2, strand2, record2Unmapped, cigar2, null, defaultQuality); end1.setReadPairedFlag(true); end1.setFirstOfPairFlag(true); @@ -472,12 +554,35 @@ public List addPair(final String name, final int contig1, final int c * Adds a pair of records (mapped or unmmapped) to the set using the provided contig starts. * The pair is assumed to be a well formed pair sitting on a single contig. */ - public List addPair(final String name, final int contig, final int start1, final int start2, - final boolean record1Unmapped, final boolean record2Unmapped, final String cigar1, - final String cigar2, final boolean strand1, final boolean strand2, final boolean record1NonPrimary, - final boolean record2NonPrimary, final int defaultQuality) { - return addPair(name, contig, contig, start1, start2, record1Unmapped, record2Unmapped, cigar1, cigar2, strand1, strand2, - record1NonPrimary, record2NonPrimary, defaultQuality); + public List addPair( + final String name, + final int contig, + final int start1, + final int start2, + final boolean record1Unmapped, + final boolean record2Unmapped, + final String cigar1, + final String cigar2, + final boolean strand1, + final boolean strand2, + final boolean record1NonPrimary, + final boolean record2NonPrimary, + final int defaultQuality) { + return addPair( + name, + contig, + contig, + start1, + start2, + record1Unmapped, + record2Unmapped, + cigar1, + cigar2, + strand1, + strand2, + record1NonPrimary, + record2NonPrimary, + defaultQuality); } /** @@ -569,15 +674,17 @@ public SamReader getSamReader() { } this.header.setAttribute("VN", "1.0"); - try (final SAMFileWriter w = this.useBamFile ? - new SAMFileWriterFactory().makeBAMWriter(this.header, true, tempFile) : - new SAMFileWriterFactory().makeSAMWriter(this.header, true, tempFile)) { + try (final SAMFileWriter w = this.useBamFile + ? new SAMFileWriterFactory().makeBAMWriter(this.header, true, tempFile) + : new SAMFileWriterFactory().makeSAMWriter(this.header, true, tempFile)) { for (final SAMRecord r : this.getRecords()) { w.addAlignment(r); } } - return SamReaderFactory.makeDefault().validationStringency(ValidationStringency.SILENT).open(tempFile); + return SamReaderFactory.makeDefault() + .validationStringency(ValidationStringency.SILENT) + .open(tempFile); } public SAMFileHeader getHeader() { @@ -595,7 +702,8 @@ public void setReadLength(final int readLength) { * @param contigLength length of the other contigs * @return newly formed header */ - static public SAMFileHeader makeDefaultHeader(final SAMFileHeader.SortOrder sortOrder, final int contigLength, final boolean addReadGroup) { + public static SAMFileHeader makeDefaultHeader( + final SAMFileHeader.SortOrder sortOrder, final int contigLength, final boolean addReadGroup) { final List sequences = new ArrayList<>(); for (final String chrom : chroms) { final SAMSequenceRecord sequenceRecord = new SAMSequenceRecord(chrom, contigLength); @@ -610,8 +718,8 @@ static public SAMFileHeader makeDefaultHeader(final SAMFileHeader.SortOrder sort final SAMReadGroupRecord readGroupRecord = new SAMReadGroupRecord(READ_GROUP_ID); readGroupRecord.setSample(SAMPLE); readGroupRecord.setPlatform(PlatformValue.ILLUMINA.name()); - //This must be a mutable list because setReadGroups doesn't perform a copy and tests expect to be able - //to modify it. + // This must be a mutable list because setReadGroups doesn't perform a copy and tests expect to be able + // to modify it. final List readGroups = new ArrayList<>(); readGroups.add(readGroupRecord); header.setReadGroups(readGroups); @@ -619,7 +727,6 @@ static public SAMFileHeader makeDefaultHeader(final SAMFileHeader.SortOrder sort return header; } - /** * Writes a random (but deterministic) reference file given a {@link SAMFileHeader} * output file is expected to have a non-compressed fasta suffix. @@ -631,7 +738,6 @@ static public SAMFileHeader makeDefaultHeader(final SAMFileHeader.SortOrder sort * performed regarding the writability, or existence of the files prior to writing. * @throws IOException In case of problem during writing the files. **/ - public void writeRandomReference(final Path fasta) throws IOException { writeRandomReference(getHeader(), fasta); } @@ -651,7 +757,8 @@ public void writeRandomReference(final Path fasta) throws IOException { public static void writeRandomReference(final SAMFileHeader header, final Path fasta) throws IOException { final int MAX_WRITE_AT_A_TIME = 10_000; final byte[] buffer = new byte[MAX_WRITE_AT_A_TIME]; - final FastaReferenceWriterBuilder builder = new FastaReferenceWriterBuilder().setEmitMd5(true).setFastaFile(fasta); + final FastaReferenceWriterBuilder builder = + new FastaReferenceWriterBuilder().setEmitMd5(true).setFastaFile(fasta); try (FastaReferenceWriter writer = builder.build()) { diff --git a/src/main/java/htsjdk/samtools/SAMSequenceDictionary.java b/src/main/java/htsjdk/samtools/SAMSequenceDictionary.java index cf40fe6532..0482fae756 100644 --- a/src/main/java/htsjdk/samtools/SAMSequenceDictionary.java +++ b/src/main/java/htsjdk/samtools/SAMSequenceDictionary.java @@ -23,30 +23,26 @@ */ package htsjdk.samtools; +import static htsjdk.samtools.SAMSequenceRecord.*; + import htsjdk.beta.plugin.HtsHeader; import htsjdk.samtools.util.Log; - import java.io.Serializable; import java.math.BigInteger; import java.security.MessageDigest; import java.util.*; import java.util.stream.Collectors; - -import static htsjdk.samtools.SAMSequenceRecord.*; - /** * Collection of SAMSequenceRecords. */ - public class SAMSequenceDictionary implements HtsHeader, Serializable { public static final long serialVersionUID = 1L; private List mSequences = new ArrayList<>(); private final Map mSequenceMap = new HashMap<>(); - public SAMSequenceDictionary() { - } + public SAMSequenceDictionary() {} public SAMSequenceDictionary(final List list) { this(); @@ -77,13 +73,15 @@ public void setSequences(final List list) { public void addSequence(final SAMSequenceRecord sequenceRecord) { if (mSequenceMap.containsKey(sequenceRecord.getSequenceName())) { - throw new IllegalArgumentException("Cannot add sequence that already exists in SAMSequenceDictionary: " + - sequenceRecord.getSequenceName()); + throw new IllegalArgumentException("Cannot add sequence that already exists in SAMSequenceDictionary: " + + sequenceRecord.getSequenceName()); } sequenceRecord.setSequenceIndex(mSequences.size()); mSequences.add(sequenceRecord); mSequenceMap.put(sequenceRecord.getSequenceName(), sequenceRecord); - sequenceRecord.getAlternativeSequenceNames().forEach(an -> addSequenceAlias(sequenceRecord.getSequenceName(), an)); + sequenceRecord + .getAlternativeSequenceNames() + .forEach(an -> addSequenceAlias(sequenceRecord.getSequenceName(), an)); } /** @@ -118,8 +116,7 @@ public int size() { * @return The sum of the lengths of the sequences in this dictionary */ public long getReferenceLength() { - return getSequences() - .stream() + return getSequences().stream() .mapToLong(SAMSequenceRecord::getSequenceLength) .sum(); } @@ -146,18 +143,20 @@ public void assertSameDictionary(final SAMSequenceDictionary that) { final Iterator thatSequences = that.mSequences.iterator(); for (final SAMSequenceRecord thisSequence : mSequences) { if (!thatSequences.hasNext()) { - throw new AssertionError(String.format(DICT_MISMATCH_TEMPLATE, thisSequence + " is present in only one dictionary")); + throw new AssertionError( + String.format(DICT_MISMATCH_TEMPLATE, thisSequence + " is present in only one dictionary")); } else { final SAMSequenceRecord thatSequence = thatSequences.next(); - if(!thatSequence.isSameSequence(thisSequence)) { - throw new AssertionError( - String.format(DICT_MISMATCH_TEMPLATE, thatSequence + " was found when " + thisSequence + " was expected") - ); + if (!thatSequence.isSameSequence(thisSequence)) { + throw new AssertionError(String.format( + DICT_MISMATCH_TEMPLATE, + thatSequence + " was found when " + thisSequence + " was expected")); } } } if (thatSequences.hasNext()) - throw new AssertionError(String.format(DICT_MISMATCH_TEMPLATE, thatSequences.next() + " is present in only one dictionary")); + throw new AssertionError( + String.format(DICT_MISMATCH_TEMPLATE, thatSequences.next() + " is present in only one dictionary")); } /** @@ -200,7 +199,7 @@ public boolean equals(Object o) { SAMSequenceDictionary that = (SAMSequenceDictionary) o; - return mSequences.equals(that.mSequences); + return mSequences.equals(that.mSequences); } /** @@ -216,12 +215,12 @@ public boolean equals(Object o) { * @param altName new contig name * @return the contig associated to the 'originalName/altName' */ - public SAMSequenceRecord addSequenceAlias(final String originalName, - final String altName) { + public SAMSequenceRecord addSequenceAlias(final String originalName, final String altName) { if (originalName == null) throw new IllegalArgumentException("original name cannot be null"); if (altName == null) throw new IllegalArgumentException("alt name cannot be null"); final SAMSequenceRecord originalSeqRecord = getSequence(originalName); - if (originalSeqRecord == null) throw new IllegalArgumentException("Sequence " + originalName + " doesn't exist in dictionary."); + if (originalSeqRecord == null) + throw new IllegalArgumentException("Sequence " + originalName + " doesn't exist in dictionary."); // same name, nothing to do if (originalName.equals(altName)) return originalSeqRecord; final SAMSequenceRecord altSeqRecord = getSequence(altName); @@ -229,8 +228,8 @@ public SAMSequenceRecord addSequenceAlias(final String originalName, // alias was already set to the same record if (altSeqRecord.equals(originalSeqRecord)) return originalSeqRecord; // alias was already set to another record - throw new IllegalArgumentException("Alias " + altName + " for " + originalSeqRecord + - " was already set to " + altSeqRecord.getSequenceName()); + throw new IllegalArgumentException("Alias " + altName + " for " + originalSeqRecord + " was already set to " + + altSeqRecord.getSequenceName()); } mSequenceMap.put(altName, originalSeqRecord); return originalSeqRecord; @@ -248,8 +247,7 @@ public SAMSequenceRecord addSequenceAlias(final String originalName, * @param altName new contig name * @return the contig associated to the 'originalName/altName', with the AN tag including the altName */ - public SAMSequenceRecord addAlternativeSequenceName(final String originalName, - final String altName) { + public SAMSequenceRecord addAlternativeSequenceName(final String originalName, final String altName) { final SAMSequenceRecord record = addSequenceAlias(originalName, altName); record.addAlternativeSequenceName(altName); return record; @@ -267,20 +265,19 @@ public SAMSequenceRecord addAlternativeSequenceName(final String originalName, * empty */ public String md5() { - if (isEmpty()) - return ""; + if (isEmpty()) return ""; try { final MessageDigest md5 = MessageDigest.getInstance("MD5"); md5.reset(); for (final SAMSequenceRecord samSequenceRecord : mSequences) { - if (samSequenceRecord.getSequenceIndex() > 0) - md5.update((byte) ' '); + if (samSequenceRecord.getSequenceIndex() > 0) md5.update((byte) ' '); final String md5_tag = samSequenceRecord.getAttribute(SAMSequenceRecord.MD5_TAG); if (md5_tag != null) { md5.update(md5_tag.getBytes()); } else { md5.update(samSequenceRecord.getSequenceName().getBytes()); - md5.update(String.valueOf(samSequenceRecord.getSequenceLength()).getBytes()); + md5.update(String.valueOf(samSequenceRecord.getSequenceLength()) + .getBytes()); } } String hash = new BigInteger(1, md5.digest()).toString(16); @@ -301,14 +298,13 @@ public int hashCode() { @Override public String toString() { - return "SAMSequenceDictionary:( sequences:"+ size()+ - " length:"+ getReferenceLength()+" "+ - " md5:"+md5()+")"; + return "SAMSequenceDictionary:( sequences:" + size() + " length:" + + getReferenceLength() + " " + " md5:" + + md5() + ")"; } - public static final List DEFAULT_DICTIONARY_EQUAL_TAG = Arrays.asList( - SAMSequenceRecord.MD5_TAG, - SAMSequenceRecord.SEQUENCE_LENGTH_TAG); + public static final List DEFAULT_DICTIONARY_EQUAL_TAG = + Arrays.asList(SAMSequenceRecord.MD5_TAG, SAMSequenceRecord.SEQUENCE_LENGTH_TAG); /** * Will merge dictionaryTags from two dictionaries into one focusing on merging the tags rather than the sequences. @@ -324,23 +320,31 @@ public String toString() { * @param tagsToMatch list of tags that must be equal if present in both sequence. Must contain MD, and LN * @return dictionary consisting of the same sequences as the two inputs with the merged values of tags. */ - public static SAMSequenceDictionary mergeDictionaries(final SAMSequenceDictionary dict1, - final SAMSequenceDictionary dict2, - final List tagsToMatch) { + public static SAMSequenceDictionary mergeDictionaries( + final SAMSequenceDictionary dict1, final SAMSequenceDictionary dict2, final List tagsToMatch) { // We require MD and LN to match. if (!tagsToMatch.contains(MD5_TAG) || !tagsToMatch.contains(SEQUENCE_LENGTH_TAG)) { - throw new IllegalArgumentException("Both " + MD5_TAG + " and " + SEQUENCE_LENGTH_TAG + " must be matched " + - "when merging dictionaries. Found: " + String.join(",", tagsToMatch)); + throw new IllegalArgumentException("Both " + MD5_TAG + " and " + SEQUENCE_LENGTH_TAG + " must be matched " + + "when merging dictionaries. Found: " + String.join(",", tagsToMatch)); } - if (!dict1.getSequences().stream().map(SAMSequenceRecord::getSequenceName).collect(Collectors.toList()).equals( - dict2.getSequences().stream().map(SAMSequenceRecord::getSequenceName).collect(Collectors.toList()))) { - - throw new IllegalArgumentException(String.format("Do not use this function to merge dictionaries with " + - "different sequences in them. Sequences must be in the same order as well. Found [%s] and [%s].", - dict1.getSequences().stream().map(SAMSequenceRecord::getSequenceName).collect(Collectors.joining(", ")), - dict2.getSequences().stream().map(SAMSequenceRecord::getSequenceName).collect(Collectors.joining(", ")))); + if (!dict1.getSequences().stream() + .map(SAMSequenceRecord::getSequenceName) + .collect(Collectors.toList()) + .equals(dict2.getSequences().stream() + .map(SAMSequenceRecord::getSequenceName) + .collect(Collectors.toList()))) { + + throw new IllegalArgumentException(String.format( + "Do not use this function to merge dictionaries with " + + "different sequences in them. Sequences must be in the same order as well. Found [%s] and [%s].", + dict1.getSequences().stream() + .map(SAMSequenceRecord::getSequenceName) + .collect(Collectors.joining(", ")), + dict2.getSequences().stream() + .map(SAMSequenceRecord::getSequenceName) + .collect(Collectors.joining(", ")))); } final SAMSequenceDictionary finalDict = new SAMSequenceDictionary(); @@ -361,8 +365,9 @@ public static SAMSequenceDictionary mergeDictionaries(final SAMSequenceDictionar final String value2 = s2.getAttribute(tag); if (value1 != null && value2 != null && !value1.equals(value2)) { - String baseMessage = String.format("Found sequence entry for which " + - "tags differ: %s and tag %s has the two values: %s and %s.", + String baseMessage = String.format( + "Found sequence entry for which " + + "tags differ: %s and tag %s has the two values: %s and %s.", sName, tag, value1, value2); if (tagsToMatch.contains(tag)) { @@ -379,12 +384,13 @@ public static SAMSequenceDictionary mergeDictionaries(final SAMSequenceDictionar final int length2 = s2.getSequenceLength(); if (length1 != UNKNOWN_SEQUENCE_LENGTH && length2 != UNKNOWN_SEQUENCE_LENGTH && length1 != length2) { - throw new IllegalArgumentException(String.format("Cannot merge the two dictionaries. " + - "Found sequence entry for which " + "lengths differ: %s has lengths %s and %s", sName, length1, length2)); + throw new IllegalArgumentException(String.format( + "Cannot merge the two dictionaries. " + "Found sequence entry for which " + + "lengths differ: %s has lengths %s and %s", + sName, length1, length2)); } sMerged.setSequenceLength(length1 == UNKNOWN_SEQUENCE_LENGTH ? length2 : length1); } return finalDict; } } - diff --git a/src/main/java/htsjdk/samtools/SAMSequenceDictionaryCodec.java b/src/main/java/htsjdk/samtools/SAMSequenceDictionaryCodec.java index 4bdbbd0e22..79e75b8ec8 100644 --- a/src/main/java/htsjdk/samtools/SAMSequenceDictionaryCodec.java +++ b/src/main/java/htsjdk/samtools/SAMSequenceDictionaryCodec.java @@ -25,7 +25,6 @@ package htsjdk.samtools; import htsjdk.samtools.util.LineReader; - import java.io.Writer; /** @@ -97,7 +96,7 @@ public void encodeHeaderLine(final boolean keepExistingVersionNumber) { * @return complete SAMSequenceDictionary object. */ public SAMSequenceDictionary decode(final LineReader reader, final String source) { - return codec.decode(reader, source).getSequenceDictionary(); + return codec.decode(reader, source).getSequenceDictionary(); } /** diff --git a/src/main/java/htsjdk/samtools/SAMSequenceRecord.java b/src/main/java/htsjdk/samtools/SAMSequenceRecord.java index 227f704f48..18afd65841 100644 --- a/src/main/java/htsjdk/samtools/SAMSequenceRecord.java +++ b/src/main/java/htsjdk/samtools/SAMSequenceRecord.java @@ -24,16 +24,12 @@ package htsjdk.samtools; import htsjdk.samtools.util.Locatable; -import htsjdk.samtools.util.StringUtil; - import java.math.BigInteger; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashSet; -import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; @@ -42,7 +38,6 @@ /** * Header information about a reference sequence. Corresponds to @SQ header record in SAM text header. */ - public class SAMSequenceRecord extends AbstractSAMHeaderRecord implements Cloneable, Locatable { public static final long serialVersionUID = 1L; // AbstractSAMHeaderRecord implements Serializable public static final int UNAVAILABLE_SEQUENCE_INDEX = -1; @@ -69,7 +64,6 @@ public class SAMSequenceRecord extends AbstractSAMHeaderRecord implements Clonea * This is not a valid sequence name, because it is reserved in the RNEXT field of SAM text format * to mean "same reference as RNAME field." */ - public static final String RESERVED_RNEXT_SEQUENCE_NAME = "="; /* use RESERVED_RNEXT_SEQUENCE_NAME instead. */ @@ -79,15 +73,22 @@ public class SAMSequenceRecord extends AbstractSAMHeaderRecord implements Clonea /** * The standard tags are stored in text header without type information, because the type of these tags is known. */ - public static final Set STANDARD_TAGS = - new HashSet<>(Arrays.asList(SEQUENCE_NAME_TAG, SEQUENCE_LENGTH_TAG, ASSEMBLY_TAG, ALTERNATIVE_SEQUENCE_NAME_TAG, MD5_TAG, URI_TAG, SPECIES_TAG)); + public static final Set STANDARD_TAGS = new HashSet<>(Arrays.asList( + SEQUENCE_NAME_TAG, + SEQUENCE_LENGTH_TAG, + ASSEMBLY_TAG, + ALTERNATIVE_SEQUENCE_NAME_TAG, + MD5_TAG, + URI_TAG, + SPECIES_TAG)); // These are the chars matched by \\s. private static final char[] WHITESPACE_CHARS = {' ', '\t', '\n', '\013', '\f', '\r'}; // \013 is vertical tab // alternative sequence name separator private static final String ALTERNATIVE_SEQUENCE_NAME_SEPARATOR = ","; - private static final Pattern LEGAL_RNAME_PATTERN = Pattern.compile("[0-9A-Za-z!#$%&+./:;?@^_|~-][0-9A-Za-z!#$%&*+./:;=?@^_|~-]*"); + private static final Pattern LEGAL_RNAME_PATTERN = + Pattern.compile("[0-9A-Za-z!#$%&+./:;?@^_|~-][0-9A-Za-z!#$%&*+./:;=?@^_|~-]*"); /** * @deprecated Use {@link #SAMSequenceRecord(String, int)} instead. @@ -175,8 +176,10 @@ public SAMSequenceRecord setSequenceIndex(final int value) { */ public Set getAlternativeSequenceNames() { final String anTag = getAttribute(ALTERNATIVE_SEQUENCE_NAME_TAG); - return (anTag == null) ? Collections.emptySet() - : Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList(anTag.split(ALTERNATIVE_SEQUENCE_NAME_SEPARATOR)))); + return (anTag == null) + ? Collections.emptySet() + : Collections.unmodifiableSet( + new LinkedHashSet<>(Arrays.asList(anTag.split(ALTERNATIVE_SEQUENCE_NAME_SEPARATOR)))); } /** @@ -206,18 +209,23 @@ public SAMSequenceRecord setAlternativeSequenceName(final Collection alt private static void validateAltRegExp(final String name) { if (!LEGAL_RNAME_PATTERN.matcher(name).matches()) { - throw new IllegalArgumentException(String.format("Invalid alternative sequence name '%s': do not match the pattern %s", name, LEGAL_RNAME_PATTERN)); + throw new IllegalArgumentException(String.format( + "Invalid alternative sequence name '%s': do not match the pattern %s", name, LEGAL_RNAME_PATTERN)); } } private void encodeAltSequences(final Collection alternativeSequences) { - //make sure that the order in which alternate names are joined is determined - setAttribute(ALTERNATIVE_SEQUENCE_NAME_TAG, alternativeSequences.isEmpty() ? null : alternativeSequences.stream() - .sorted() - .distinct() - .peek(SAMSequenceRecord::validateAltRegExp) - .collect(Collectors.joining(ALTERNATIVE_SEQUENCE_NAME_SEPARATOR))); + // make sure that the order in which alternate names are joined is determined + setAttribute( + ALTERNATIVE_SEQUENCE_NAME_TAG, + alternativeSequences.isEmpty() + ? null + : alternativeSequences.stream() + .sorted() + .distinct() + .peek(SAMSequenceRecord::validateAltRegExp) + .collect(Collectors.joining(ALTERNATIVE_SEQUENCE_NAME_SEPARATOR))); } /** @@ -243,10 +251,13 @@ public boolean isSameSequence(final SAMSequenceRecord that) { return false; } // PIC-439. Allow undefined length. - if (mSequenceLength != UNKNOWN_SEQUENCE_LENGTH && that.mSequenceLength != UNKNOWN_SEQUENCE_LENGTH && mSequenceLength != that.mSequenceLength) { + if (mSequenceLength != UNKNOWN_SEQUENCE_LENGTH + && that.mSequenceLength != UNKNOWN_SEQUENCE_LENGTH + && mSequenceLength != that.mSequenceLength) { return false; } - if (this.getAttribute(SAMSequenceRecord.MD5_TAG) != null && that.getAttribute(SAMSequenceRecord.MD5_TAG) != null) { + if (this.getAttribute(SAMSequenceRecord.MD5_TAG) != null + && that.getAttribute(SAMSequenceRecord.MD5_TAG) != null) { final BigInteger thisMd5 = new BigInteger((String) this.getAttribute(SAMSequenceRecord.MD5_TAG), 16); final BigInteger thatMd5 = new BigInteger((String) that.getAttribute(SAMSequenceRecord.MD5_TAG), 16); if (!thisMd5.equals(thatMd5)) { @@ -256,8 +267,8 @@ public boolean isSameSequence(final SAMSequenceRecord that) { // Compare using == since we intern() the Strings if (mSequenceName != that.mSequenceName) { // if they are different, they could still be the same based on the alternative sequences - if (getAlternativeSequenceNames().contains(that.mSequenceName) || - that.getAlternativeSequenceNames().contains(mSequenceName)) { + if (getAlternativeSequenceNames().contains(that.mSequenceName) + || that.getAlternativeSequenceNames().contains(mSequenceName)) { return true; } return false; @@ -340,7 +351,8 @@ public static String truncateSequenceName(final String sequenceName) { */ public static void validateSequenceName(final String name) { if (!LEGAL_RNAME_PATTERN.matcher(name).useAnchoringBounds(true).matches()) { - throw new SAMException(String.format("Sequence name '%s' doesn't match regex: '%s' ", name, LEGAL_RNAME_PATTERN)); + throw new SAMException( + String.format("Sequence name '%s' doesn't match regex: '%s' ", name, LEGAL_RNAME_PATTERN)); } } @@ -352,8 +364,7 @@ public String toString() { getSequenceLength(), getSequenceIndex(), getAssembly(), - getAlternativeSequenceNames() - ); + getAlternativeSequenceNames()); } @Override @@ -389,4 +400,3 @@ public final int getEnd() { return this.getSequenceLength(); } } - diff --git a/src/main/java/htsjdk/samtools/SAMTag.java b/src/main/java/htsjdk/samtools/SAMTag.java index a2259c4a81..f925c0f3c9 100644 --- a/src/main/java/htsjdk/samtools/SAMTag.java +++ b/src/main/java/htsjdk/samtools/SAMTag.java @@ -124,7 +124,7 @@ public static short makeBinaryTag(String tag) { if (tag.length() != 2) { throw new IllegalArgumentException("String tag does not have length() == 2: " + tag); } - return (short)(tag.charAt(1) << 8 | tag.charAt(0)); + return (short) (tag.charAt(1) << 8 | tag.charAt(0)); } /** @@ -137,8 +137,8 @@ public static String makeStringTag(final short tag) { String ret = stringTags[tag]; if (ret == null) { final byte[] stringConversionBuf = new byte[2]; - stringConversionBuf[0] = (byte)(tag & 0xff); - stringConversionBuf[1] = (byte)((tag >> 8) & 0xff); + stringConversionBuf[0] = (byte) (tag & 0xff); + stringConversionBuf[1] = (byte) ((tag >> 8) & 0xff); ret = StringUtil.bytesToString(stringConversionBuf); stringTags[tag] = ret; } @@ -151,7 +151,7 @@ public static String makeStringTag(final short tag) { * * @return the binary representation of this tag name */ - public short getBinaryTag(){ + public short getBinaryTag() { return this.shortValue; } } diff --git a/src/main/java/htsjdk/samtools/SAMTagUtil.java b/src/main/java/htsjdk/samtools/SAMTagUtil.java index b23a735844..f1692a0576 100644 --- a/src/main/java/htsjdk/samtools/SAMTagUtil.java +++ b/src/main/java/htsjdk/samtools/SAMTagUtil.java @@ -23,8 +23,6 @@ */ package htsjdk.samtools; -import htsjdk.samtools.util.StringUtil; - /** * Facility for converting between String and short representation of a SAM tag. short representation * is used by HTSJDK internally and is much more efficient. Callers are encouraged to obtain the short @@ -40,127 +38,188 @@ public class SAMTagUtil { /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short AM = SAMTag.AM.getBinaryTag(); + @Deprecated + public final short AM = SAMTag.AM.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short AS = SAMTag.AS.getBinaryTag(); + @Deprecated + public final short AS = SAMTag.AS.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short BC = SAMTag.BC.getBinaryTag(); + @Deprecated + public final short BC = SAMTag.BC.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short BQ = SAMTag.BQ.getBinaryTag(); + @Deprecated + public final short BQ = SAMTag.BQ.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short BZ = SAMTag.BZ.getBinaryTag(); + @Deprecated + public final short BZ = SAMTag.BZ.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short CB = SAMTag.CB.getBinaryTag(); + @Deprecated + public final short CB = SAMTag.CB.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short CC = SAMTag.CC.getBinaryTag(); + @Deprecated + public final short CC = SAMTag.CC.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short CG = SAMTag.CG.getBinaryTag(); + @Deprecated + public final short CG = SAMTag.CG.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short CM = SAMTag.CM.getBinaryTag(); + @Deprecated + public final short CM = SAMTag.CM.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short CO = SAMTag.CO.getBinaryTag(); + @Deprecated + public final short CO = SAMTag.CO.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short CP = SAMTag.CP.getBinaryTag(); + @Deprecated + public final short CP = SAMTag.CP.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short CQ = SAMTag.CQ.getBinaryTag(); + @Deprecated + public final short CQ = SAMTag.CQ.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short CR = SAMTag.CR.getBinaryTag(); + @Deprecated + public final short CR = SAMTag.CR.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short CS = SAMTag.CS.getBinaryTag(); + @Deprecated + public final short CS = SAMTag.CS.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short CT = SAMTag.CT.getBinaryTag(); + @Deprecated + public final short CT = SAMTag.CT.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short CY = SAMTag.CY.getBinaryTag(); + @Deprecated + public final short CY = SAMTag.CY.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short E2 = SAMTag.E2.getBinaryTag(); + @Deprecated + public final short E2 = SAMTag.E2.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short FI = SAMTag.FI.getBinaryTag(); + @Deprecated + public final short FI = SAMTag.FI.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short FS = SAMTag.FS.getBinaryTag(); + @Deprecated + public final short FS = SAMTag.FS.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short FT = SAMTag.FT.getBinaryTag(); + @Deprecated + public final short FT = SAMTag.FT.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short FZ = SAMTag.FZ.getBinaryTag(); + @Deprecated + public final short FZ = SAMTag.FZ.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short GC = SAMTag.GC.getBinaryTag(); + @Deprecated + public final short GC = SAMTag.GC.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short GS = SAMTag.GS.getBinaryTag(); + @Deprecated + public final short GS = SAMTag.GS.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short GQ = SAMTag.GQ.getBinaryTag(); + @Deprecated + public final short GQ = SAMTag.GQ.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short LB = SAMTag.LB.getBinaryTag(); + @Deprecated + public final short LB = SAMTag.LB.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short H0 = SAMTag.H0.getBinaryTag(); + @Deprecated + public final short H0 = SAMTag.H0.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short H1 = SAMTag.H1.getBinaryTag(); + @Deprecated + public final short H1 = SAMTag.H1.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short H2 = SAMTag.H2.getBinaryTag(); + @Deprecated + public final short H2 = SAMTag.H2.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short HI = SAMTag.HI.getBinaryTag(); + @Deprecated + public final short HI = SAMTag.HI.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short IH = SAMTag.IH.getBinaryTag(); + @Deprecated + public final short IH = SAMTag.IH.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short MC = SAMTag.MC.getBinaryTag(); + @Deprecated + public final short MC = SAMTag.MC.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short MF = SAMTag.MF.getBinaryTag(); + @Deprecated + public final short MF = SAMTag.MF.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short MI = SAMTag.MI.getBinaryTag(); + @Deprecated + public final short MI = SAMTag.MI.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short MD = SAMTag.MD.getBinaryTag(); + @Deprecated + public final short MD = SAMTag.MD.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short MQ = SAMTag.MQ.getBinaryTag(); + @Deprecated + public final short MQ = SAMTag.MQ.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short NH = SAMTag.NH.getBinaryTag(); + @Deprecated + public final short NH = SAMTag.NH.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short NM = SAMTag.NM.getBinaryTag(); + @Deprecated + public final short NM = SAMTag.NM.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short OQ = SAMTag.OQ.getBinaryTag(); + @Deprecated + public final short OQ = SAMTag.OQ.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short OP = SAMTag.OP.getBinaryTag(); + @Deprecated + public final short OP = SAMTag.OP.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short OC = SAMTag.OC.getBinaryTag(); + @Deprecated + public final short OC = SAMTag.OC.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short OF = SAMTag.OF.getBinaryTag(); + @Deprecated + public final short OF = SAMTag.OF.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short OR = SAMTag.OR.getBinaryTag(); + @Deprecated + public final short OR = SAMTag.OR.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short OX = SAMTag.OX.getBinaryTag(); + @Deprecated + public final short OX = SAMTag.OX.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short PG = SAMTag.PG.getBinaryTag(); + @Deprecated + public final short PG = SAMTag.PG.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short PQ = SAMTag.PQ.getBinaryTag(); + @Deprecated + public final short PQ = SAMTag.PQ.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short PT = SAMTag.PT.getBinaryTag(); + @Deprecated + public final short PT = SAMTag.PT.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short PU = SAMTag.PU.getBinaryTag(); + @Deprecated + public final short PU = SAMTag.PU.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short QT = SAMTag.QT.getBinaryTag(); + @Deprecated + public final short QT = SAMTag.QT.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short Q2 = SAMTag.Q2.getBinaryTag(); + @Deprecated + public final short Q2 = SAMTag.Q2.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short QX = SAMTag.QX.getBinaryTag(); + @Deprecated + public final short QX = SAMTag.QX.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short R2 = SAMTag.R2.getBinaryTag(); + @Deprecated + public final short R2 = SAMTag.R2.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short RG = SAMTag.RG.getBinaryTag(); + @Deprecated + public final short RG = SAMTag.RG.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short RT = SAMTag.RT.getBinaryTag(); + @Deprecated + public final short RT = SAMTag.RT.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short RX = SAMTag.RX.getBinaryTag(); + @Deprecated + public final short RX = SAMTag.RX.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short S2 = SAMTag.S2.getBinaryTag(); + @Deprecated + public final short S2 = SAMTag.S2.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short SA = SAMTag.SA.getBinaryTag(); + @Deprecated + public final short SA = SAMTag.SA.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short SM = SAMTag.SM.getBinaryTag(); + @Deprecated + public final short SM = SAMTag.SM.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short SQ = SAMTag.SQ.getBinaryTag(); + @Deprecated + public final short SQ = SAMTag.SQ.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short TC = SAMTag.TC.getBinaryTag(); + @Deprecated + public final short TC = SAMTag.TC.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short U2 = SAMTag.U2.getBinaryTag(); + @Deprecated + public final short U2 = SAMTag.U2.getBinaryTag(); /** @deprecated use {@link SAMTag#getBinaryTag()} instead. */ - @Deprecated public final short UQ = SAMTag.UQ.getBinaryTag(); + @Deprecated + public final short UQ = SAMTag.UQ.getBinaryTag(); private static final SAMTagUtil SINGLETON = new SAMTagUtil(); @@ -195,6 +254,6 @@ public short makeBinaryTag(final String tag) { */ @Deprecated public String makeStringTag(final short tag) { - return SAMTag.makeStringTag(tag); + return SAMTag.makeStringTag(tag); } } diff --git a/src/main/java/htsjdk/samtools/SAMTestUtil.java b/src/main/java/htsjdk/samtools/SAMTestUtil.java index ec85ce2da7..304a321124 100644 --- a/src/main/java/htsjdk/samtools/SAMTestUtil.java +++ b/src/main/java/htsjdk/samtools/SAMTestUtil.java @@ -51,8 +51,7 @@ public void assertPairValid(final SAMRecord firstEnd, final SAMRecord secondEnd) assertFalse(secondEnd.getFirstOfPairFlag()); assertFalse(firstEnd.getSecondOfPairFlag()); if (!firstEnd.getReadUnmappedFlag() && !secondEnd.getReadUnmappedFlag()) { - assertNotSame(firstEnd.getReadNegativeStrandFlag(), - secondEnd.getReadNegativeStrandFlag()); + assertNotSame(firstEnd.getReadNegativeStrandFlag(), secondEnd.getReadNegativeStrandFlag()); } } @@ -68,7 +67,7 @@ public static void assertReadValid(final SAMRecord read) throws SanityCheckFaile } final List errors = read.isValid(false); - if ( errors != null) { + if (errors != null) { errors.forEach(v -> System.out.println(v.toString())); } assertTrue(errors.isEmpty()); diff --git a/src/main/java/htsjdk/samtools/SAMTextHeaderCodec.java b/src/main/java/htsjdk/samtools/SAMTextHeaderCodec.java index d26380a2a2..889e67602b 100644 --- a/src/main/java/htsjdk/samtools/SAMTextHeaderCodec.java +++ b/src/main/java/htsjdk/samtools/SAMTextHeaderCodec.java @@ -24,13 +24,11 @@ package htsjdk.samtools; import htsjdk.samtools.SAMFileHeader.SortOrder; -import htsjdk.samtools.SAMValidationError.Type; import htsjdk.samtools.util.DateParser; import htsjdk.samtools.util.LineReader; +import htsjdk.samtools.util.Log; import htsjdk.samtools.util.RuntimeIOException; import htsjdk.samtools.util.StringUtil; -import htsjdk.samtools.util.Log; - import java.io.BufferedWriter; import java.io.IOException; import java.io.Writer; @@ -99,7 +97,6 @@ public SAMFileHeader decode(final LineReader reader, final String source) { continue; } switch (parsedHeaderLine.getHeaderRecordType()) { - case HD: parseHDLine(parsedHeaderLine); break; @@ -116,8 +113,8 @@ public SAMFileHeader decode(final LineReader reader, final String source) { mFileHeader.addComment(mCurrentLine); break; default: - throw new IllegalStateException("Unrecognized header record type: " + - parsedHeaderLine.getHeaderRecordType()); + throw new IllegalStateException( + "Unrecognized header record type: " + parsedHeaderLine.getHeaderRecordType()); } } mFileHeader.setSequenceDictionary(new SAMSequenceDictionary(sequences)); @@ -144,46 +141,51 @@ private void transferAttributes(final AbstractSAMHeaderRecord record, final Map< for (final Map.Entry entry : textAttributes.entrySet()) { record.setAttribute(entry.getKey(), entry.getValue()); } - } private void parsePGLine(final ParsedHeaderLine parsedHeaderLine) { - assert(HeaderRecordType.PG.equals(parsedHeaderLine.getHeaderRecordType())); + assert (HeaderRecordType.PG.equals(parsedHeaderLine.getHeaderRecordType())); if (!parsedHeaderLine.requireTag(SAMProgramRecord.PROGRAM_GROUP_ID_TAG)) { return; } - final SAMProgramRecord programRecord = new SAMProgramRecord(parsedHeaderLine.removeValue(SAMProgramRecord.PROGRAM_GROUP_ID_TAG)); + final SAMProgramRecord programRecord = + new SAMProgramRecord(parsedHeaderLine.removeValue(SAMProgramRecord.PROGRAM_GROUP_ID_TAG)); transferAttributes(programRecord, parsedHeaderLine.mKeyValuePairs); mFileHeader.addProgramRecord(programRecord); } private void parseRGLine(final ParsedHeaderLine parsedHeaderLine) { - assert(HeaderRecordType.RG.equals(parsedHeaderLine.getHeaderRecordType())); + assert (HeaderRecordType.RG.equals(parsedHeaderLine.getHeaderRecordType())); if (!parsedHeaderLine.requireTag(SAMReadGroupRecord.READ_GROUP_ID_TAG)) { return; } // Allow no SM tag if validation stringency is not strict. This call has the side effect of reporting an error // or throwing an exception depending on validation stringency if this is missing. parsedHeaderLine.requireTag(SAMReadGroupRecord.READ_GROUP_SAMPLE_TAG); - final SAMReadGroupRecord samReadGroupRecord = new SAMReadGroupRecord(parsedHeaderLine.removeValue(SAMReadGroupRecord.READ_GROUP_ID_TAG)); + final SAMReadGroupRecord samReadGroupRecord = + new SAMReadGroupRecord(parsedHeaderLine.removeValue(SAMReadGroupRecord.READ_GROUP_ID_TAG)); transferAttributes(samReadGroupRecord, parsedHeaderLine.mKeyValuePairs); // Convert non-String attributes to the appropriate types final String predictedMedianInsertSize = - (String)samReadGroupRecord.getAttribute(SAMReadGroupRecord.PREDICTED_MEDIAN_INSERT_SIZE_TAG); + (String) samReadGroupRecord.getAttribute(SAMReadGroupRecord.PREDICTED_MEDIAN_INSERT_SIZE_TAG); if (predictedMedianInsertSize != null) { try { Integer.parseInt(predictedMedianInsertSize); - samReadGroupRecord.setAttribute(SAMReadGroupRecord.PREDICTED_MEDIAN_INSERT_SIZE_TAG,predictedMedianInsertSize); + samReadGroupRecord.setAttribute( + SAMReadGroupRecord.PREDICTED_MEDIAN_INSERT_SIZE_TAG, predictedMedianInsertSize); } catch (NumberFormatException e) { - reportErrorParsingLine(SAMReadGroupRecord.PREDICTED_MEDIAN_INSERT_SIZE_TAG + - " is not numeric: " + predictedMedianInsertSize, SAMValidationError.Type.INVALID_PREDICTED_MEDIAN_INSERT_SIZE, + reportErrorParsingLine( + SAMReadGroupRecord.PREDICTED_MEDIAN_INSERT_SIZE_TAG + " is not numeric: " + + predictedMedianInsertSize, + SAMValidationError.Type.INVALID_PREDICTED_MEDIAN_INSERT_SIZE, e); } } - final String dateRunProduced = (String)samReadGroupRecord.getAttribute(SAMReadGroupRecord.DATE_RUN_PRODUCED_TAG); + final String dateRunProduced = + (String) samReadGroupRecord.getAttribute(SAMReadGroupRecord.DATE_RUN_PRODUCED_TAG); if (dateRunProduced != null) { Object date; try { @@ -192,8 +194,10 @@ private void parseRGLine(final ParsedHeaderLine parsedHeaderLine) { // Can't convert date string into Date object. Treat it as a string if validation // stringency allows it. date = dateRunProduced; - reportErrorParsingLine(SAMReadGroupRecord.DATE_RUN_PRODUCED_TAG + " tag value '" + - dateRunProduced + "' is not parseable as a date", SAMValidationError.Type.INVALID_DATE_STRING, + reportErrorParsingLine( + SAMReadGroupRecord.DATE_RUN_PRODUCED_TAG + " tag value '" + dateRunProduced + + "' is not parseable as a date", + SAMValidationError.Type.INVALID_DATE_STRING, e); } samReadGroupRecord.setAttribute(SAMReadGroupRecord.DATE_RUN_PRODUCED_TAG, date.toString()); @@ -203,21 +207,21 @@ private void parseRGLine(final ParsedHeaderLine parsedHeaderLine) { } private void parseSQLine(final ParsedHeaderLine parsedHeaderLine) { - assert(HeaderRecordType.SQ.equals(parsedHeaderLine.getHeaderRecordType())); - if (!parsedHeaderLine.requireTag(SAMSequenceRecord.SEQUENCE_NAME_TAG) || - !parsedHeaderLine.requireTag(SAMSequenceRecord.SEQUENCE_LENGTH_TAG)) { + assert (HeaderRecordType.SQ.equals(parsedHeaderLine.getHeaderRecordType())); + if (!parsedHeaderLine.requireTag(SAMSequenceRecord.SEQUENCE_NAME_TAG) + || !parsedHeaderLine.requireTag(SAMSequenceRecord.SEQUENCE_LENGTH_TAG)) { return; } String sequenceName = parsedHeaderLine.removeValue(SAMSequenceRecord.SEQUENCE_NAME_TAG); sequenceName = SAMSequenceRecord.truncateSequenceName(sequenceName); - final SAMSequenceRecord samSequenceRecord = new SAMSequenceRecord(sequenceName, - Integer.parseInt(parsedHeaderLine.removeValue(SAMSequenceRecord.SEQUENCE_LENGTH_TAG))); + final SAMSequenceRecord samSequenceRecord = new SAMSequenceRecord( + sequenceName, Integer.parseInt(parsedHeaderLine.removeValue(SAMSequenceRecord.SEQUENCE_LENGTH_TAG))); transferAttributes(samSequenceRecord, parsedHeaderLine.mKeyValuePairs); sequences.add(samSequenceRecord); } private void parseHDLine(final ParsedHeaderLine parsedHeaderLine) { - assert(HeaderRecordType.HD.equals(parsedHeaderLine.getHeaderRecordType())); + assert (HeaderRecordType.HD.equals(parsedHeaderLine.getHeaderRecordType())); if (!parsedHeaderLine.requireTag(SAMFileHeader.VERSION_TAG)) { return; } @@ -226,24 +230,29 @@ private void parseHDLine(final ParsedHeaderLine parsedHeaderLine) { try { if (soString != null) SortOrder.valueOf(soString); } catch (IllegalArgumentException e) { - reportErrorParsingLine(HEADER_LINE_START + parsedHeaderLine.getHeaderRecordType() + - " line has non-conforming SO tag value: " + soString + ".", - SAMValidationError.Type.HEADER_TAG_NON_CONFORMING_VALUE, null); + reportErrorParsingLine( + HEADER_LINE_START + parsedHeaderLine.getHeaderRecordType() + + " line has non-conforming SO tag value: " + soString + ".", + SAMValidationError.Type.HEADER_TAG_NON_CONFORMING_VALUE, + null); } final String goString = parsedHeaderLine.getValue(SAMFileHeader.GROUP_ORDER_TAG); try { if (goString != null) SAMFileHeader.GroupOrder.valueOf(goString); } catch (IllegalArgumentException e) { - reportErrorParsingLine(HEADER_LINE_START + parsedHeaderLine.getHeaderRecordType() + - " line has non-conforming GO tag value: "+ goString + ".", - SAMValidationError.Type.HEADER_TAG_NON_CONFORMING_VALUE, null); + reportErrorParsingLine( + HEADER_LINE_START + parsedHeaderLine.getHeaderRecordType() + + " line has non-conforming GO tag value: " + goString + ".", + SAMValidationError.Type.HEADER_TAG_NON_CONFORMING_VALUE, + null); } transferAttributes(mFileHeader, parsedHeaderLine.mKeyValuePairs); } - private void reportErrorParsingLine(String reason, final SAMValidationError.Type type, final Throwable nestedException) { + private void reportErrorParsingLine( + String reason, final SAMValidationError.Type type, final Throwable nestedException) { reason = "Error parsing SAM header. " + reason + ". Line:\n" + mCurrentLine; if (validationStringency != ValidationStringency.STRICT) { final SAMValidationError error = new SAMValidationError(type, reason, null, mReader.getLineNumber()); @@ -254,13 +263,17 @@ private void reportErrorParsingLine(String reason, final SAMValidationError.Type if (mSource != null) { fileMessage = "File " + mSource; } - throw new SAMFormatException(reason + "; " + fileMessage + - "; Line number " + mReader.getLineNumber(), nestedException); + throw new SAMFormatException( + reason + "; " + fileMessage + "; Line number " + mReader.getLineNumber(), nestedException); } } private enum HeaderRecordType { - HD, SQ, RG, PG, CO + HD, + SQ, + RG, + PG, + CO } /** @@ -274,7 +287,7 @@ private class ParsedHeaderLine { private boolean lineValid = false; ParsedHeaderLine(final String line) { - assert(line.startsWith(HEADER_LINE_START)); + assert (line.startsWith(HEADER_LINE_START)); // Tab-separate String[] fields = new String[1024]; @@ -289,7 +302,8 @@ private class ParsedHeaderLine { try { mHeaderRecordType = HeaderRecordType.valueOf(fields[0].substring(1)); } catch (IllegalArgumentException e) { - reportErrorParsingLine("Unrecognized header record type", SAMValidationError.Type.UNRECOGNIZED_HEADER_TYPE, null); + reportErrorParsingLine( + "Unrecognized header record type", SAMValidationError.Type.UNRECOGNIZED_HEADER_TYPE, null); mHeaderRecordType = null; return; } @@ -303,23 +317,30 @@ private class ParsedHeaderLine { final String[] keyAndValue = new String[2]; // Parse they key:value pairs for (int i = 1; i < numFields; ++i) { - if (StringUtil.splitConcatenateExcessTokens(fields[i], keyAndValue, TAG_KEY_VALUE_SEPARATOR_CHAR) != 2) { - reportErrorParsingLine("Problem parsing " + HEADER_LINE_START + mHeaderRecordType + - " key:value pair", SAMValidationError.Type.POORLY_FORMATTED_HEADER_TAG, null); + if (StringUtil.splitConcatenateExcessTokens(fields[i], keyAndValue, TAG_KEY_VALUE_SEPARATOR_CHAR) + != 2) { + reportErrorParsingLine( + "Problem parsing " + HEADER_LINE_START + mHeaderRecordType + " key:value pair", + SAMValidationError.Type.POORLY_FORMATTED_HEADER_TAG, + null); continue; } - if (mKeyValuePairs.containsKey(keyAndValue[0]) && - ! mKeyValuePairs.get(keyAndValue[0]).equals(keyAndValue[1])) { - reportErrorParsingLine("Problem parsing " + HEADER_LINE_START + mHeaderRecordType + - " key:value pair " + keyAndValue[0] + ":" + keyAndValue[1] + - " clashes with " + keyAndValue[0] + ":" + mKeyValuePairs.get(keyAndValue[0]), - SAMValidationError.Type.HEADER_TAG_MULTIPLY_DEFINED, null); + if (mKeyValuePairs.containsKey(keyAndValue[0]) + && !mKeyValuePairs.get(keyAndValue[0]).equals(keyAndValue[1])) { + reportErrorParsingLine( + "Problem parsing " + HEADER_LINE_START + mHeaderRecordType + " key:value pair " + + keyAndValue[0] + ":" + keyAndValue[1] + " clashes with " + + keyAndValue[0] + ":" + mKeyValuePairs.get(keyAndValue[0]), + SAMValidationError.Type.HEADER_TAG_MULTIPLY_DEFINED, + null); continue; } if (keyAndValue[0].length() != 2) { - reportErrorParsingLine("Problem parsing " + HEADER_LINE_START + mHeaderRecordType + - " key:value pair " + keyAndValue[0] + ": key is not two characters", - SAMValidationError.Type.HEADER_TAG_INVALID_KEY, null); + reportErrorParsingLine( + "Problem parsing " + HEADER_LINE_START + mHeaderRecordType + " key:value pair " + + keyAndValue[0] + ": key is not two characters", + SAMValidationError.Type.HEADER_TAG_INVALID_KEY, + null); continue; } validateSortOrderValue(keyAndValue); @@ -335,11 +356,10 @@ private void validateSortOrderValue(String[] value) { } catch (IllegalArgumentException e) { if (validationStringency == ValidationStringency.STRICT) { throw new SAMFormatException("Found non-conforming header SO tag: " - + value[1] - + ", exiting because VALIDATION_STRINGENCY=STRICT"); + + value[1] + + ", exiting because VALIDATION_STRINGENCY=STRICT"); } else if (validationStringency == ValidationStringency.LENIENT) { - log.warn("Found non-conforming header SO tag: " - + value[1] + ". Treating as 'unknown'."); + log.warn("Found non-conforming header SO tag: " + value[1] + ". Treating as 'unknown'."); } value[1] = SortOrder.unknown.toString(); } @@ -361,8 +381,10 @@ public boolean isLineValid() { */ boolean requireTag(final String tag) { if (!mKeyValuePairs.containsKey(tag)) { - reportErrorParsingLine(HEADER_LINE_START + mHeaderRecordType + " line missing " + tag + " tag", - SAMValidationError.Type.HEADER_RECORD_MISSING_REQUIRED_TAG, null); + reportErrorParsingLine( + HEADER_LINE_START + mHeaderRecordType + " line missing " + tag + " tag", + SAMValidationError.Type.HEADER_RECORD_MISSING_REQUIRED_TAG, + null); return false; } return true; @@ -388,7 +410,6 @@ String removeValue(final String key) { mKeyValuePairs.remove(key); return ret; } - } /** @@ -412,7 +433,8 @@ public void encode(final Writer writer, final SAMFileHeader header, final boolea mFileHeader = header; this.writer = new BufferedWriter(writer); writeHDLine(keepExistingVersionNumber); - for (final SAMSequenceRecord sequenceRecord: header.getSequenceDictionary().getSequences()) { + for (final SAMSequenceRecord sequenceRecord : + header.getSequenceDictionary().getSequences()) { writeSQLine(sequenceRecord); } @@ -482,11 +504,11 @@ private void writeRGLine(final SAMReadGroupRecord readGroup) { } protected String getRGLine(final SAMReadGroupRecord readGroup) { - final String[] fields = new String[2 + readGroup.getAttributes().size()]; - fields[0] = HEADER_LINE_START + HeaderRecordType.RG; - fields[1] = SAMReadGroupRecord.READ_GROUP_ID_TAG + TAG_KEY_VALUE_SEPARATOR + readGroup.getReadGroupId(); - encodeTags(readGroup, fields, 2); - return StringUtil.join(FIELD_SEPARATOR, fields); + final String[] fields = new String[2 + readGroup.getAttributes().size()]; + fields[0] = HEADER_LINE_START + HeaderRecordType.RG; + fields[1] = SAMReadGroupRecord.READ_GROUP_ID_TAG + TAG_KEY_VALUE_SEPARATOR + readGroup.getReadGroupId(); + encodeTags(readGroup, fields, 2); + return StringUtil.join(FIELD_SEPARATOR, fields); } private void writeHDLine(final boolean keepExistingVersionNumber) { @@ -516,11 +538,15 @@ private void writeSQLine(final SAMSequenceRecord sequenceRecord) { } protected String getSQLine(final SAMSequenceRecord sequenceRecord) { - final int numAttributes = sequenceRecord.getAttributes() != null ? sequenceRecord.getAttributes().size() : 0; + final int numAttributes = sequenceRecord.getAttributes() != null + ? sequenceRecord.getAttributes().size() + : 0; final String[] fields = new String[3 + numAttributes]; fields[0] = HEADER_LINE_START + HeaderRecordType.SQ; fields[1] = SAMSequenceRecord.SEQUENCE_NAME_TAG + TAG_KEY_VALUE_SEPARATOR + sequenceRecord.getSequenceName(); - fields[2] = SAMSequenceRecord.SEQUENCE_LENGTH_TAG + TAG_KEY_VALUE_SEPARATOR + Integer.toString(sequenceRecord.getSequenceLength()); + fields[2] = SAMSequenceRecord.SEQUENCE_LENGTH_TAG + + TAG_KEY_VALUE_SEPARATOR + + Integer.toString(sequenceRecord.getSequenceLength()); encodeTags(sequenceRecord, fields, 3); return StringUtil.join(FIELD_SEPARATOR, fields); } @@ -532,7 +558,7 @@ protected String getSQLine(final SAMSequenceRecord sequenceRecord) { * @param offset where to start putting text tag representations. */ private void encodeTags(final AbstractSAMHeaderRecord rec, final String[] fields, int offset) { - for (final Map.Entry entry: rec.getAttributes()) { + for (final Map.Entry entry : rec.getAttributes()) { fields[offset++] = mTagCodec.encodeUntypedTag(entry.getKey(), entry.getValue()); } } diff --git a/src/main/java/htsjdk/samtools/SAMTextReader.java b/src/main/java/htsjdk/samtools/SAMTextReader.java index 62f8717528..b2fb376dc1 100644 --- a/src/main/java/htsjdk/samtools/SAMTextReader.java +++ b/src/main/java/htsjdk/samtools/SAMTextReader.java @@ -23,20 +23,16 @@ */ package htsjdk.samtools; - import htsjdk.samtools.util.BufferedLineReader; import htsjdk.samtools.util.CloseableIterator; - import java.io.File; import java.io.InputStream; - /** * Internal class for reading SAM text files. */ class SAMTextReader extends SamReader.ReaderImplementation { - private SAMRecordFactory samRecordFactory; private BufferedLineReader mReader; private SAMFileHeader mFileHeader = null; @@ -56,7 +52,8 @@ class SAMTextReader extends SamReader.ReaderImplementation { * * @param stream Need not be buffered, as this class provides buffered reading. */ - public SAMTextReader(final InputStream stream, final ValidationStringency validationStringency, final SAMRecordFactory factory) { + public SAMTextReader( + final InputStream stream, final ValidationStringency validationStringency, final SAMRecordFactory factory) { mReader = new BufferedLineReader(stream); this.validationStringency = validationStringency; this.samRecordFactory = factory; @@ -69,7 +66,11 @@ public SAMTextReader(final InputStream stream, final ValidationStringency valida * @param stream Need not be buffered, as this class provides buffered reading. * @param file For error reporting only. */ - public SAMTextReader(final InputStream stream, final File file, final ValidationStringency validationStringency, final SAMRecordFactory factory) { + public SAMTextReader( + final InputStream stream, + final File file, + final ValidationStringency validationStringency, + final SAMRecordFactory factory) { this(stream, validationStringency, factory); mFile = file; } @@ -188,7 +189,8 @@ public SAMFileSpan getFilePointerSpanningReads() { /** * Unsupported for SAM text files. */ - public CloseableIterator query(final String sequence, final int start, final int end, final boolean contained) { + public CloseableIterator query( + final String sequence, final int start, final int end, final boolean contained) { throw new UnsupportedOperationException("Cannot query SAM text files"); } @@ -227,8 +229,8 @@ private String advanceLine() { */ private class RecordIterator implements CloseableIterator { - private final SAMLineParser parser = new SAMLineParser(samRecordFactory, validationStringency, - mFileHeader, mParentReader, mFile); + private final SAMLineParser parser = + new SAMLineParser(samRecordFactory, validationStringency, mFileHeader, mParentReader, mFile); private RecordIterator() { if (mReader == null) { @@ -267,7 +269,5 @@ private SAMRecord parseLine() { return parser.parseLine(mCurrentLine, mReader.getLineNumber()); } - } } - diff --git a/src/main/java/htsjdk/samtools/SAMTextWriter.java b/src/main/java/htsjdk/samtools/SAMTextWriter.java index aa6233f8d1..547e8e9c40 100644 --- a/src/main/java/htsjdk/samtools/SAMTextWriter.java +++ b/src/main/java/htsjdk/samtools/SAMTextWriter.java @@ -25,7 +25,6 @@ import htsjdk.samtools.util.AsciiWriter; import htsjdk.samtools.util.RuntimeIOException; - import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -45,7 +44,7 @@ public class SAMTextWriter extends SAMFileWriterImpl { private final TextTagCodec tagCodec = new TextTagCodec(); private final SamFlagField samFlagFieldOutput; - + /** * Constructs a SAMTextWriter that outputs to a Writer. * @param out Writer. @@ -66,13 +65,13 @@ public SAMTextWriter(final File file) { * Returns the Writer used by this instance. Useful for flushing the output. */ public Writer getWriter() { - return out; + return out; } /** * Constructs a SAMTextWriter that writes to an OutputStream. The OutputStream * is wrapped in an AsciiWriter, which can be retrieved with getWriter(). - * @param stream Need not be buffered because this class provides buffering. + * @param stream Need not be buffered because this class provides buffering. */ public SAMTextWriter(final OutputStream stream) { this(stream, SamFlagField.DECIMAL); @@ -148,8 +147,8 @@ private void writeAlignmentNoNewline(final SAMRecord alignment) { out.write(FIELD_SEPARATOR); // == is OK here because these strings are interned - if (alignment.getReferenceName() == alignment.getMateReferenceName() && - SAMRecord.NO_ALIGNMENT_REFERENCE_NAME != alignment.getReferenceName()) { + if (alignment.getReferenceName() == alignment.getMateReferenceName() + && SAMRecord.NO_ALIGNMENT_REFERENCE_NAME != alignment.getReferenceName()) { out.write("="); } else { out.write(alignment.getMateReferenceName()); diff --git a/src/main/java/htsjdk/samtools/SAMUtils.java b/src/main/java/htsjdk/samtools/SAMUtils.java index fca3e72b4f..a8e778bd30 100644 --- a/src/main/java/htsjdk/samtools/SAMUtils.java +++ b/src/main/java/htsjdk/samtools/SAMUtils.java @@ -32,7 +32,6 @@ import htsjdk.samtools.util.RuntimeEOFException; import htsjdk.samtools.util.StringUtil; import htsjdk.tribble.annotation.Strand; - import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -98,22 +97,7 @@ public final class SAMUtils { private static final byte COMPRESSED_B_HIGH = (byte) (COMPRESSED_B_LOW << 4); private static final byte[] COMPRESSED_LOOKUP_TABLE = { - '=', - 'A', - 'C', - 'M', - 'G', - 'R', - 'S', - 'V', - 'T', - 'W', - 'Y', - 'H', - 'K', - 'D', - 'B', - 'N' + '=', 'A', 'C', 'M', 'G', 'R', 'S', 'V', 'T', 'W', 'Y', 'H', 'K', 'D', 'B', 'N' }; /** @@ -123,9 +107,10 @@ public final class SAMUtils { * calls and bit manipulation in the hot decode loop. Ported from htslib's {@code code2base} table. */ private static final byte[] NIBBLE_PAIR_LOOKUP = new byte[512]; + static { for (int i = 0; i < 256; i++) { - NIBBLE_PAIR_LOOKUP[i * 2] = COMPRESSED_LOOKUP_TABLE[(i >> 4) & 0xf]; + NIBBLE_PAIR_LOOKUP[i * 2] = COMPRESSED_LOOKUP_TABLE[(i >> 4) & 0xf]; NIBBLE_PAIR_LOOKUP[i * 2 + 1] = COMPRESSED_LOOKUP_TABLE[i & 0xf]; } } @@ -143,8 +128,8 @@ static byte[] bytesToCompressedBases(final byte[] readBases) { final byte[] compressedBases = new byte[(readBases.length + 1) / 2]; int i; for (i = 1; i < readBases.length; i += 2) { - compressedBases[i / 2] = (byte) (charToCompressedBaseHigh(readBases[i - 1]) | - charToCompressedBaseLow(readBases[i])); + compressedBases[i / 2] = + (byte) (charToCompressedBaseHigh(readBases[i - 1]) | charToCompressedBaseLow(readBases[i])); } // Last nybble if (i == readBases.length) { @@ -170,12 +155,13 @@ static byte[] bytesToCompressedBases(final byte[] readBases) { * @param compressedOffset byte offset into {@code compressedBases} at which to start decoding * @return new byte array of length {@code length} with bases as uppercase ASCII bytes */ - public static byte[] compressedBasesToBytes(final int length, final byte[] compressedBases, final int compressedOffset) { + public static byte[] compressedBasesToBytes( + final int length, final byte[] compressedBases, final int compressedOffset) { final byte[] ret = new byte[length]; final int pairs = length / 2; for (int i = 0; i < pairs; i++) { final int lookupIndex = (compressedBases[i + compressedOffset] & 0xFF) * 2; - ret[i * 2] = NIBBLE_PAIR_LOOKUP[lookupIndex]; + ret[i * 2] = NIBBLE_PAIR_LOOKUP[lookupIndex]; ret[i * 2 + 1] = NIBBLE_PAIR_LOOKUP[lookupIndex + 1]; } // Odd-length: last base is in the high nibble of the final byte @@ -245,7 +231,8 @@ private static byte charToCompressedBaseLow(final byte base) { case 'b': return COMPRESSED_B_LOW; default: - throw new IllegalArgumentException("Bad base passed to charToCompressedBaseLow: " + Character.toString((char) base) + "(" + base + ")"); + throw new IllegalArgumentException("Bad base passed to charToCompressedBaseLow: " + + Character.toString((char) base) + "(" + base + ")"); } } @@ -309,7 +296,8 @@ private static byte charToCompressedBaseHigh(final byte base) { case 'b': return COMPRESSED_B_HIGH; default: - throw new IllegalArgumentException("Bad base passed to charToCompressedBaseHigh: " + Character.toString((char) base) + "(" + base + ")"); + throw new IllegalArgumentException("Bad base passed to charToCompressedBaseHigh: " + + Character.toString((char) base) + "(" + base + ")"); } } @@ -436,9 +424,10 @@ static int reg2bin(final int beg, final int end) { * @param validationStringency If STRICT, throw a SAMFormatException. If LENIENT, print the validation * errors to stderr. If SILENT, do nothing. */ - public static void processValidationErrors(final List validationErrors, - final long samRecordIndex, - final ValidationStringency validationStringency) { + public static void processValidationErrors( + final List validationErrors, + final long samRecordIndex, + final ValidationStringency validationStringency) { if (validationErrors != null && !validationErrors.isEmpty()) { for (final SAMValidationError validationError : validationErrors) { validationError.setRecordNumber(samRecordIndex); @@ -453,8 +442,8 @@ public static void processValidationErrors(final List valida } } - public static void processValidationError(final SAMValidationError validationError, - final ValidationStringency validationStringency) { + public static void processValidationError( + final SAMValidationError validationError, final ValidationStringency validationStringency) { if (validationStringency == ValidationStringency.STRICT) { throw new SAMFormatException("SAM validation error: " + validationError); } else if (validationStringency == ValidationStringency.LENIENT) { @@ -474,7 +463,7 @@ public static void processValidationError(final SAMValidationError validationErr SAMReadGroupRecord.READ_GROUP_ID_TAG // We don't actually want to compare with ID but it's suitable // "just in case" since it's the only one that's actually required - ); + ); /** * Calculate a hash code from identifying information in the RG (read group) records in a SAM file's @@ -492,8 +481,10 @@ public static String calculateReadGroupRecordChecksum(final File input, final Fi } // Sort the read group records by their first - final SamReader reader = SamReaderFactory.makeDefault().referenceSequence(referenceFasta).open(input); - final List sortedRecords = new ArrayList<>(reader.getFileHeader().getReadGroups()); + final SamReader reader = + SamReaderFactory.makeDefault().referenceSequence(referenceFasta).open(input); + final List sortedRecords = + new ArrayList<>(reader.getFileHeader().getReadGroups()); Collections.sort(sortedRecords, HEADER_RECORD_COMPARATOR); for (final SAMReadGroupRecord rgRecord : sortedRecords) { @@ -504,7 +495,9 @@ public static String calculateReadGroupRecordChecksum(final File input, final Fi try { for (final Map.Entry sortedEntry : sortedAttributes.entrySet()) { - if (!sortedEntry.getKey().equals(SAMReadGroupRecord.READ_GROUP_ID_TAG)) { // Redundant check, safety first + if (!sortedEntry + .getKey() + .equals(SAMReadGroupRecord.READ_GROUP_ID_TAG)) { // Redundant check, safety first digest.update(sortedEntry.getKey().getBytes(ENCODING)); digest.update(sortedEntry.getValue().getBytes(ENCODING)); } @@ -623,9 +616,11 @@ public static boolean cigarMapsNoBasesToRef(final Cigar cigar) { */ public static boolean recordMapsEntirelyBeyondEndOfReference(final SAMRecord record) { if (record.getHeader() == null) { - throw new SAMException("A non-null SAMHeader is required to resolve the mapping position: " + record.getReadName()); + throw new SAMException( + "A non-null SAMHeader is required to resolve the mapping position: " + record.getReadName()); } else { - return record.getHeader().getSequence(record.getReferenceIndex()).getSequenceLength() < record.getAlignmentStart(); + return record.getHeader().getSequence(record.getReferenceIndex()).getSequenceLength() + < record.getAlignmentStart(); } } @@ -663,12 +658,10 @@ public static int combineMapqs(int m1, int m2) { } return m1 + m2; - } - public static long findVirtualOffsetOfFirstRecordInBam(final Path bamFile) { - try (SeekableStream ss = new SeekablePathStream(bamFile)){ + try (SeekableStream ss = new SeekablePathStream(bamFile)) { return BAMFileReader.findVirtualOffsetOfFirstRecord(ss); } catch (final IOException ioe) { throw new RuntimeEOFException(ioe); @@ -709,7 +702,8 @@ public static long findVirtualOffsetOfFirstRecordInBam(final SeekableStream seek * @param cigarTypeName The type of cigar passed - for error logging. * @return List of alignment blocks */ - public static List getAlignmentBlocks(final Cigar cigar, final int alignmentStart, final String cigarTypeName) { + public static List getAlignmentBlocks( + final Cigar cigar, final int alignmentStart, final String cigarTypeName) { if (cigar == null) return Collections.emptyList(); final List alignmentBlocks = new ArrayList<>(); @@ -727,7 +721,7 @@ public static List getAlignmentBlocks(final Cigar cigar, final i break; // soft clip read bases case N: refBase += e.getLength(); - break; // reference skip + break; // reference skip case D: refBase += e.getLength(); break; @@ -743,7 +737,8 @@ public static List getAlignmentBlocks(final Cigar cigar, final i refBase += length; break; default: - throw new IllegalStateException("Case statement didn't deal with " + cigarTypeName + " op: " + e.getOperator() + "in CIGAR: " + cigar); + throw new IllegalStateException("Case statement didn't deal with " + cigarTypeName + " op: " + + e.getOperator() + "in CIGAR: " + cigar); } } return Collections.unmodifiableList(alignmentBlocks); @@ -823,8 +818,12 @@ public static Cigar getMateCigar(final SAMRecord rec, final boolean withValidati if (mateCigarString != null) { mateCigar = TextCigarCodec.decode(mateCigarString); if (withValidation && rec.getValidationStringency() != ValidationStringency.SILENT) { - final List alignmentBlocks = getAlignmentBlocks(mateCigar, rec.getMateAlignmentStart(), "mate cigar"); - SAMUtils.processValidationErrors(validateCigar(rec, mateCigar, rec.getMateReferenceIndex(), alignmentBlocks, -1, "Mate CIGAR"), -1L, rec.getValidationStringency()); + final List alignmentBlocks = + getAlignmentBlocks(mateCigar, rec.getMateAlignmentStart(), "mate cigar"); + SAMUtils.processValidationErrors( + validateCigar(rec, mateCigar, rec.getMateReferenceIndex(), alignmentBlocks, -1, "Mate CIGAR"), + -1L, + rec.getValidationStringency()); } } return mateCigar; @@ -925,29 +924,35 @@ public static List getMateAlignmentBlocks(final SAMRecord rec) { * @param cigarTypeName For error reporting. "Read CIGAR" or "Mate Cigar" * @return List of errors, or null if no errors. */ - - public static List validateCigar(final SAMRecord rec, - final Cigar cigar, - final Integer referenceIndex, - final List alignmentBlocks, - final long recordNumber, - final String cigarTypeName) { + public static List validateCigar( + final SAMRecord rec, + final Cigar cigar, + final Integer referenceIndex, + final List alignmentBlocks, + final long recordNumber, + final String cigarTypeName) { // Don't know line number, and don't want to force read name to be decoded. List ret = cigar.isValid(rec.getReadName(), recordNumber); if (referenceIndex != SAMRecord.NO_ALIGNMENT_REFERENCE_INDEX) { SAMFileHeader samHeader = rec.getHeader(); if (null == samHeader) { if (ret == null) ret = new ArrayList<>(); - ret.add(new SAMValidationError(SAMValidationError.Type.MISSING_HEADER, - cigarTypeName + " A non-null SAMHeader is required to validate cigar elements for: ", rec.getReadName(), recordNumber)); + ret.add(new SAMValidationError( + SAMValidationError.Type.MISSING_HEADER, + cigarTypeName + " A non-null SAMHeader is required to validate cigar elements for: ", + rec.getReadName(), + recordNumber)); } else { final SAMSequenceRecord sequence = samHeader.getSequence(referenceIndex); final int referenceSequenceLength = sequence.getSequenceLength(); for (final AlignmentBlock alignmentBlock : alignmentBlocks) { if (alignmentBlock.getReferenceStart() + alignmentBlock.getLength() - 1 > referenceSequenceLength) { if (ret == null) ret = new ArrayList<>(); - ret.add(new SAMValidationError(SAMValidationError.Type.CIGAR_MAPS_OFF_REFERENCE, - cigarTypeName + " M operator maps off end of reference", rec.getReadName(), recordNumber)); + ret.add(new SAMValidationError( + SAMValidationError.Type.CIGAR_MAPS_OFF_REFERENCE, + cigarTypeName + " M operator maps off end of reference", + rec.getReadName(), + recordNumber)); break; } } @@ -968,21 +973,36 @@ public static List validateMateCigar(final SAMRecord rec, fi List ret = null; if (rec.getValidationStringency() != ValidationStringency.SILENT) { - if (rec.getReadPairedFlag() && !rec.getMateUnmappedFlag()) { // The mateCigar will be defined if the mate is mapped + if (rec.getReadPairedFlag() + && !rec.getMateUnmappedFlag()) { // The mateCigar will be defined if the mate is mapped if (getMateCigarString(rec) != null) { - ret = SAMUtils.validateCigar(rec, getMateCigar(rec), rec.getMateReferenceIndex(), getMateAlignmentBlocks(rec), recordNumber, "Mate CIGAR"); + ret = SAMUtils.validateCigar( + rec, + getMateCigar(rec), + rec.getMateReferenceIndex(), + getMateAlignmentBlocks(rec), + recordNumber, + "Mate CIGAR"); } } else { if (getMateCigarString(rec) != null) { ret = new ArrayList<>(); if (!rec.getReadPairedFlag()) { - // If the read is not paired, and the Mate Cigar String (MC Attribute) exists, that is a validation error - ret.add(new SAMValidationError(SAMValidationError.Type.MATE_CIGAR_STRING_INVALID_PRESENCE, - "Mate CIGAR String (MC Attribute) present for a read that is not paired", rec.getReadName(), recordNumber)); + // If the read is not paired, and the Mate Cigar String (MC Attribute) exists, that is a + // validation error + ret.add(new SAMValidationError( + SAMValidationError.Type.MATE_CIGAR_STRING_INVALID_PRESENCE, + "Mate CIGAR String (MC Attribute) present for a read that is not paired", + rec.getReadName(), + recordNumber)); } else { // will hit here if rec.getMateUnmappedFlag() is true - // If the Mate is unmapped, and the Mate Cigar String (MC Attribute) exists, that is a validation error. - ret.add(new SAMValidationError(SAMValidationError.Type.MATE_CIGAR_STRING_INVALID_PRESENCE, - "Mate CIGAR String (MC Attribute) present for a read whose mate is unmapped", rec.getReadName(), recordNumber)); + // If the Mate is unmapped, and the Mate Cigar String (MC Attribute) exists, that is a + // validation error. + ret.add(new SAMValidationError( + SAMValidationError.Type.MATE_CIGAR_STRING_INVALID_PRESENCE, + "Mate CIGAR String (MC Attribute) present for a read whose mate is unmapped", + rec.getReadName(), + recordNumber)); } } } @@ -1027,7 +1047,8 @@ public static String getCanonicalRecordName(final SAMRecord record) { * Read bases include only those from insertion, match, or mismatch Cigar operators. */ public static int getNumOverlappingAlignedBasesToClip(final SAMRecord rec) { - // NB: ignores how to handle supplemental records when present for both ends by just using the mate information in the record. + // NB: ignores how to handle supplemental records when present for both ends by just using the mate information + // in the record. if (!rec.getReadPairedFlag() || rec.getReadUnmappedFlag() || rec.getMateUnmappedFlag()) return 0; @@ -1038,7 +1059,8 @@ else if (rec.getMateAlignmentStart() == rec.getAlignmentStart() && rec.getFirstO // Find the number of read bases after the given mate's alignment start. int numBasesToClip = 0; - final int refStartPos = rec.getMateAlignmentStart(); // relative reference position after which we should start clipping + final int refStartPos = + rec.getMateAlignmentStart(); // relative reference position after which we should start clipping final Cigar cigar = rec.getCigar(); int refPos = rec.getAlignmentStart(); for (final CigarElement el : cigar.getCigarElements()) { @@ -1048,11 +1070,18 @@ else if (rec.getMateAlignmentStart() == rec.getAlignmentStart() && rec.getFirstO if (operator == CigarOperator.MATCH_OR_MISMATCH) { // M if (refStartPos < refPos) numBasesToClip += refBasesLength; // use all of the bases else - numBasesToClip += (refPos + refBasesLength) - refStartPos; // since the mate's alignment start can be in the middle of a cigar element - } else if (operator == CigarOperator.SOFT_CLIP || operator == CigarOperator.HARD_CLIP || operator == CigarOperator.PADDING || operator == CigarOperator.SKIPPED_REGION) { + numBasesToClip += (refPos + refBasesLength) + - refStartPos; // since the mate's alignment start can be in the middle of a cigar + // element + } else if (operator == CigarOperator.SOFT_CLIP + || operator == CigarOperator.HARD_CLIP + || operator == CigarOperator.PADDING + || operator == CigarOperator.SKIPPED_REGION) { // ignore } else { // ID - numBasesToClip += operator.consumesReadBases() ? el.getLength() : 0; // clip all the bases in the read from this operator + numBasesToClip += operator.consumesReadBases() + ? el.getLength() + : 0; // clip all the bases in the read from this operator } } refPos += refBasesLength; @@ -1088,8 +1117,10 @@ public static SAMRecord clipOverlappingAlignedBases(final SAMRecord record, fina * @param noSideEffects if true a modified clone of the original record is returned, otherwise we modify the record directly. * @return Returns a (possibly new) SAMRecord with the given number of bases soft-clipped */ - public static SAMRecord clipOverlappingAlignedBases(final SAMRecord record, final int numOverlappingBasesToClip, final boolean noSideEffects) { - // NB: ignores how to handle supplemental records when present for both ends by just using the mate information in the record. + public static SAMRecord clipOverlappingAlignedBases( + final SAMRecord record, final int numOverlappingBasesToClip, final boolean noSideEffects) { + // NB: ignores how to handle supplemental records when present for both ends by just using the mate information + // in the record. if (numOverlappingBasesToClip <= 0 || record.getReadUnmappedFlag() || record.getMateUnmappedFlag()) { return record; @@ -1112,7 +1143,8 @@ public static SAMRecord clipOverlappingAlignedBases(final SAMRecord record, fina // FIXME: does not properly consider a cigar like: 100M20S10H // clip it, clip it good - rec.setCigar(new Cigar(CigarUtil.softClipEndOfRead(clipFrom, rec.getCigar().getCigarElements()))); + rec.setCigar(new Cigar( + CigarUtil.softClipEndOfRead(clipFrom, rec.getCigar().getCigarElements()))); return rec; } catch (final CloneNotSupportedException e) { throw new SAMException(e.getMessage(), e); @@ -1143,8 +1175,9 @@ public static List getOtherCanonicalAlignments(final SAMRecord record /* extract value of SA tag */ final Object saValue = record.getAttribute(SAMTag.SA); if (saValue == null) return Collections.emptyList(); - if (!(saValue instanceof String)) throw new SAMException( - "Expected a String for attribute 'SA' but got " + saValue.getClass() + ". Record: " + record); + if (!(saValue instanceof String)) + throw new SAMException( + "Expected a String for attribute 'SA' but got " + saValue.getClass() + ". Record: " + record); final SAMRecordFactory samReaderFactory = new DefaultSAMRecordFactory(); @@ -1188,11 +1221,9 @@ public static List getOtherCanonicalAlignments(final SAMRecord record otherRec.setMateAlignmentStart(record.getMateAlignmentStart()); } - /* get reference sequence */ final int tid = record.getHeader().getSequenceIndex(commaStrs[0]); - if (tid == -1) - throw new SAMException("Unknown contig in " + semiColonStr + ". Record: " + record); + if (tid == -1) throw new SAMException("Unknown contig in " + semiColonStr + ". Record: " + record); otherRec.setReferenceIndex(tid); /* fill POS */ @@ -1206,22 +1237,20 @@ public static List getOtherCanonicalAlignments(final SAMRecord record otherRec.setAlignmentStart(alignStart); /* set TLEN */ - if (record.getReadPairedFlag() && - !record.getMateUnmappedFlag() && - record.getMateReferenceIndex() == tid) { + if (record.getReadPairedFlag() && !record.getMateUnmappedFlag() && record.getMateReferenceIndex() == tid) { otherRec.setInferredInsertSize(record.getMateAlignmentStart() - alignStart); } /* set FLAG */ int other_flag = record_flag; other_flag |= (commaStrs[2].equals("+") ? 0 : SAMFlag.READ_REVERSE_STRAND.flag); - /* spec: Conventionally, at a supplementary line, the 1st element points to the primary line */ + /* spec: Conventionally, at a supplementary line, the 1st element points to the primary line */ if (!(record.getSupplementaryAlignmentFlag() && i == 0)) { other_flag |= SAMFlag.SUPPLEMENTARY_ALIGNMENT.flag; } otherRec.setFlags(other_flag); - /* set CIGAR */ + /* set CIGAR */ otherRec.setCigar(TextCigarCodec.decode(commaStrs[3])); /* set MAPQ */ @@ -1255,7 +1284,8 @@ public static List getOtherCanonicalAlignments(final SAMRecord record * @deprecated because the method does the exact opposite of what it says. Use the correctly named * isReferenceSequenceIncompatibleWithBAI() instead. */ - @Deprecated public static boolean isReferenceSequenceCompatibleWithBAI(final SAMSequenceRecord sequence) { + @Deprecated + public static boolean isReferenceSequenceCompatibleWithBAI(final SAMSequenceRecord sequence) { return isReferenceSequenceIncompatibleWithBAI(sequence); } @@ -1275,15 +1305,20 @@ public static boolean isReferenceSequenceIncompatibleWithBAI(final SAMSequenceRe */ public static String calculateOATagValue(SAMRecord record) { if (record.getReferenceName().contains(",")) { - throw new SAMException(String.format("Reference name for record %s contains a comma character.", record.getReadName())); + throw new SAMException( + String.format("Reference name for record %s contains a comma character.", record.getReadName())); } final String oaValue; if (record.getReadUnmappedFlag()) { - oaValue = String.format(Locale.US, "*,0,%s,*,%s,", + oaValue = String.format( + Locale.US, + "*,0,%s,*,%s,", record.getReadNegativeStrandFlag() ? Strand.NEGATIVE : Strand.POSITIVE, record.getMappingQuality()); } else { - oaValue = String.format(Locale.US, "%s,%s,%s,%s,%s,%s", + oaValue = String.format( + Locale.US, + "%s,%s,%s,%s,%s,%s", record.getReferenceName(), record.getAlignmentStart(), record.getReadNegativeStrandFlag() ? Strand.NEGATIVE : Strand.POSITIVE, @@ -1292,6 +1327,5 @@ public static String calculateOATagValue(SAMRecord record) { Optional.ofNullable(record.getAttribute(SAMTag.NM)).orElse("")); } return oaValue; - } } diff --git a/src/main/java/htsjdk/samtools/SAMValidationError.java b/src/main/java/htsjdk/samtools/SAMValidationError.java index 5fd6f7a6d3..e5f479b994 100644 --- a/src/main/java/htsjdk/samtools/SAMValidationError.java +++ b/src/main/java/htsjdk/samtools/SAMValidationError.java @@ -35,7 +35,8 @@ public class SAMValidationError implements Serializable { public static final long serialVersionUID = 1L; public enum Severity { - WARNING, ERROR + WARNING, + ERROR } public enum Type { @@ -240,7 +241,6 @@ public enum Type { /** Header tag key contains invalid characters or is not length two */ HEADER_TAG_INVALID_KEY; - public final Severity severity; private Type() { @@ -305,16 +305,27 @@ public String toString() { return builder.append(message).toString(); } - public Type getType() { return type; } - public String getMessage() { return message; } + public Type getType() { + return type; + } + + public String getMessage() { + return message; + } /** may be null */ - public String getReadName() { return readName; } + public String getReadName() { + return readName; + } /** 1-based. -1 if not known. */ - public long getRecordNumber() { return recordNumber; } + public long getRecordNumber() { + return recordNumber; + } - public void setRecordNumber(final long recordNumber) { this.recordNumber = recordNumber; } + public void setRecordNumber(final long recordNumber) { + this.recordNumber = recordNumber; + } public String getSource() { return source; diff --git a/src/main/java/htsjdk/samtools/SBIIndex.java b/src/main/java/htsjdk/samtools/SBIIndex.java index 79e244a4db..734c4cbb74 100644 --- a/src/main/java/htsjdk/samtools/SBIIndex.java +++ b/src/main/java/htsjdk/samtools/SBIIndex.java @@ -26,7 +26,6 @@ import htsjdk.samtools.util.BinaryCodec; import htsjdk.samtools.util.BlockCompressedFilePointerUtil; import htsjdk.samtools.util.FileExtensions; - import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; @@ -36,10 +35,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.NavigableSet; import java.util.Objects; -import java.util.TreeSet; -import java.util.stream.Collectors; /** * SBI is an index into BGZF-compressed data files, which has an entry for the file position of the start of every @@ -87,11 +83,11 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; final Header header = (Header) o; - return fileLength == header.fileLength && - totalNumberOfRecords == header.totalNumberOfRecords && - granularity == header.granularity && - Arrays.equals(md5, header.md5) && - Arrays.equals(uuid, header.uuid); + return fileLength == header.fileLength + && totalNumberOfRecords == header.totalNumberOfRecords + && granularity == header.granularity + && Arrays.equals(md5, header.md5) + && Arrays.equals(uuid, header.uuid); } @Override @@ -104,13 +100,12 @@ public int hashCode() { @Override public String toString() { - return "Header{" + - "fileLength=" + fileLength + - ", md5=" + Arrays.toString(md5) + - ", uuid=" + Arrays.toString(uuid) + - ", totalNumberOfRecords=" + totalNumberOfRecords + - ", granularity=" + granularity + - '}'; + return "Header{" + "fileLength=" + + fileLength + ", md5=" + + Arrays.toString(md5) + ", uuid=" + + Arrays.toString(uuid) + ", totalNumberOfRecords=" + + totalNumberOfRecords + ", granularity=" + + granularity + '}'; } } @@ -172,9 +167,7 @@ private static SBIIndex readIndex(final InputStream in) { for (int i = 0; i < numOffsets; i++) { final long cur = binaryCodec.readLong(); if (prev > cur) { - throw new RuntimeException(String.format( - "Invalid SBI; offsets not in order: %#x > %#x", - prev, cur)); + throw new RuntimeException(String.format("Invalid SBI; offsets not in order: %#x > %#x", prev, cur)); } virtualOffsets[i] = cur; prev = cur; @@ -186,7 +179,8 @@ private static Header readHeader(final BinaryCodec binaryCodec) { final byte[] buffer = new byte[SBI_MAGIC.length]; binaryCodec.readBytes(buffer); if (!Arrays.equals(buffer, SBI_MAGIC)) { - throw new RuntimeException("Invalid file header in SBI: " + new String(buffer) + " (" + Arrays.toString(buffer) + ")"); + throw new RuntimeException( + "Invalid file header in SBI: " + new String(buffer) + " (" + Arrays.toString(buffer) + ")"); } final long fileLength = binaryCodec.readLong(); final byte[] md5 = new byte[16]; @@ -281,7 +275,8 @@ public List split(final long splitSize) { */ public Chunk getChunk(final long splitStart, final long splitEnd) { if (splitStart >= splitEnd) { - throw new IllegalArgumentException(String.format("Split start (%s) must be less than end (%s)", splitStart, splitEnd)); + throw new IllegalArgumentException( + String.format("Split start (%s) must be less than end (%s)", splitStart, splitEnd)); } final long lastVirtualOffset = virtualOffsets[virtualOffsets.length - 1]; final long maxEnd = BlockCompressedFilePointerUtil.getBlockAddress(lastVirtualOffset); @@ -303,8 +298,10 @@ private long ceiling(final long virtualOffset) { index = -index - 1; if (index == virtualOffsets.length) { long lastVirtualOffset = virtualOffsets[virtualOffsets.length - 1]; - throw new IllegalArgumentException(String.format("No virtual offset found for virtual file pointer %s, last virtual offset %s", - BlockCompressedFilePointerUtil.asString(virtualOffset), BlockCompressedFilePointerUtil.asString(lastVirtualOffset))); + throw new IllegalArgumentException(String.format( + "No virtual offset found for virtual file pointer %s, last virtual offset %s", + BlockCompressedFilePointerUtil.asString(virtualOffset), + BlockCompressedFilePointerUtil.asString(lastVirtualOffset))); } } return virtualOffsets[index]; @@ -315,8 +312,7 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; final SBIIndex sbiIndex = (SBIIndex) o; - return Objects.equals(header, sbiIndex.header) && - Arrays.equals(virtualOffsets, sbiIndex.virtualOffsets); + return Objects.equals(header, sbiIndex.header) && Arrays.equals(virtualOffsets, sbiIndex.virtualOffsets); } @Override @@ -330,14 +326,14 @@ public int hashCode() { public String toString() { String virtualOffsetsString; if (virtualOffsets.length > 30) { - virtualOffsetsString = Arrays.toString(Arrays.copyOfRange(virtualOffsets, 0, 30)).replace("]", ", ...]"); + virtualOffsetsString = + Arrays.toString(Arrays.copyOfRange(virtualOffsets, 0, 30)).replace("]", ", ...]"); } else { virtualOffsetsString = Arrays.toString(virtualOffsets); } - return "SBIIndex{" + - "header=" + header + - ", numVirtualOffsets=" + virtualOffsets.length + - ", virtualOffsets=" + virtualOffsetsString + - '}'; + return "SBIIndex{" + "header=" + + header + ", numVirtualOffsets=" + + virtualOffsets.length + ", virtualOffsets=" + + virtualOffsetsString + '}'; } } diff --git a/src/main/java/htsjdk/samtools/SBIIndexMerger.java b/src/main/java/htsjdk/samtools/SBIIndexMerger.java index d71b048b99..98c080e994 100644 --- a/src/main/java/htsjdk/samtools/SBIIndexMerger.java +++ b/src/main/java/htsjdk/samtools/SBIIndexMerger.java @@ -25,7 +25,6 @@ import htsjdk.samtools.util.BlockCompressedFilePointerUtil; import htsjdk.samtools.util.Log; - import java.io.OutputStream; /** @@ -82,13 +81,8 @@ public void processIndex(final SBIIndex index, final long partLength) { */ @Override public void finish(final long dataFileLength) { - final SBIIndex.Header header = - new SBIIndex.Header( - dataFileLength, - SBIIndexWriter.EMPTY_MD5, - SBIIndexWriter.EMPTY_UUID, - recordCount, - granularity); + final SBIIndex.Header header = new SBIIndex.Header( + dataFileLength, SBIIndexWriter.EMPTY_MD5, SBIIndexWriter.EMPTY_UUID, recordCount, granularity); indexWriter.finish(header, finalVirtualOffset); } } diff --git a/src/main/java/htsjdk/samtools/SBIIndexWriter.java b/src/main/java/htsjdk/samtools/SBIIndexWriter.java index 20fbee9029..ae750ee067 100644 --- a/src/main/java/htsjdk/samtools/SBIIndexWriter.java +++ b/src/main/java/htsjdk/samtools/SBIIndexWriter.java @@ -26,7 +26,6 @@ import htsjdk.samtools.util.BinaryCodec; import htsjdk.samtools.util.IOUtil; import htsjdk.samtools.util.RuntimeIOException; - import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.IOException; @@ -104,9 +103,7 @@ public void processRecord(final long virtualOffset) { void writeVirtualOffset(final long virtualOffset) { if (prev > virtualOffset) { - throw new IllegalArgumentException(String.format( - "Offsets not in order: %#x > %#x", - prev, virtualOffset)); + throw new IllegalArgumentException(String.format("Offsets not in order: %#x > %#x", prev, virtualOffset)); } tempOffsetsCodec.writeLong(virtualOffset); virtualOffsetCount++; @@ -138,7 +135,12 @@ public void finish(final long finalVirtualOffset, final long dataFileLength, fin if (uuid != null && uuid.length != 16) { throw new IllegalArgumentException("Invalid UUID length: " + uuid.length); } - final SBIIndex.Header header = new SBIIndex.Header(dataFileLength, md5 == null ? EMPTY_MD5 : md5, uuid == null ? EMPTY_UUID : uuid, recordCount, granularity); + final SBIIndex.Header header = new SBIIndex.Header( + dataFileLength, + md5 == null ? EMPTY_MD5 : md5, + uuid == null ? EMPTY_UUID : uuid, + recordCount, + granularity); finish(header, finalVirtualOffset); } @@ -147,7 +149,7 @@ void finish(final SBIIndex.Header header, final long finalVirtualOffset) { writeVirtualOffset(finalVirtualOffset); tempOffsetsCodec.close(); try (BinaryCodec binaryCodec = new BinaryCodec(out); - InputStream tempOffsets = new BufferedInputStream(Files.newInputStream(tempOffsetsFile))) { + InputStream tempOffsets = new BufferedInputStream(Files.newInputStream(tempOffsetsFile))) { // header binaryCodec.writeBytes(SBIIndex.SBI_MAGIC); binaryCodec.writeLong(header.getFileLength()); diff --git a/src/main/java/htsjdk/samtools/SQTagUtil.java b/src/main/java/htsjdk/samtools/SQTagUtil.java index 4038e698cd..419dd0e177 100755 --- a/src/main/java/htsjdk/samtools/SQTagUtil.java +++ b/src/main/java/htsjdk/samtools/SQTagUtil.java @@ -25,7 +25,7 @@ /** * Utility methods for encoding and decoding the SQ tag value of SAMRecord. - * + * * @author alecw@broadinstitute.org * @deprecated since 11/2018. SQ is a reserved tag that shouldn't be used and this code untested. */ @@ -37,7 +37,10 @@ public class SQTagUtil { * the two low-order bits, is the complementary base. */ public enum SQBase { - SQ_A('A'), SQ_C('C'), SQ_G('G'), SQ_T('T'); + SQ_A('A'), + SQ_C('C'), + SQ_G('G'), + SQ_T('T'); private final Character base; SQBase(final Character base) { @@ -66,11 +69,12 @@ public Character getBase() { */ public static byte sqScaledProbabilityRatio(final double secondBestLikelihood, final double thirdBestLikelihood) { if (secondBestLikelihood >= 1.0 || thirdBestLikelihood <= 0 || thirdBestLikelihood > secondBestLikelihood) { - throw new IllegalArgumentException("Likelihoods out of range. second best: " + secondBestLikelihood + - "; third best: " + thirdBestLikelihood); + throw new IllegalArgumentException("Likelihoods out of range. second best: " + secondBestLikelihood + + "; third best: " + thirdBestLikelihood); } // Cap value at QUALITY_MASK - return (byte)(Math.min(Math.round(-10.0 * Math.log10(thirdBestLikelihood/secondBestLikelihood)), QUALITY_MASK)); + return (byte) + (Math.min(Math.round(-10.0 * Math.log10(thirdBestLikelihood / secondBestLikelihood)), QUALITY_MASK)); } /** @@ -96,7 +100,7 @@ public static byte baseAndProbDiffToSqValue(final SQBase base, final byte probRa * @return a byte containing the index and the log probability difference. */ public static byte baseAndProbDiffToSqValue(final int base, final byte probRatio) { - return (byte)((base << BASE_INDEX_SHIFT) | Math.min(probRatio, QUALITY_MASK)); + return (byte) ((base << BASE_INDEX_SHIFT) | Math.min(probRatio, QUALITY_MASK)); } /** @@ -105,7 +109,7 @@ public static byte baseAndProbDiffToSqValue(final int base, final byte probRatio * @return the log probability difference between the secondary and tertiary bases (-10log10(p3/p2)). */ public static byte sqValueToProbRatio(final byte sqValue) { - return (byte)(sqValue & QUALITY_MASK); + return (byte) (sqValue & QUALITY_MASK); } /** @@ -126,7 +130,6 @@ public static int sqValueToBaseOrdinal(final byte sqValue) { return (sqValue & 0xff) >>> BASE_INDEX_SHIFT; } - /** * Reverses and complements the sqValues in place. * @param sqArray Array of SQ-values, with 2nd-best base in high-order 2 bits, and probability diff @@ -136,7 +139,7 @@ public static void reverseComplementSqArray(final byte[] sqArray) { final int lastIndex = sqArray.length - 1; int i, j; - for (i=0, j=lastIndex; i getIterator(SAMFileSpan chunks) { List chunkList = ((BAMFileSpan) chunks).getChunks(); - final SRAIterator newIterator = new SRAIterator(acc, run, virtualHeader, cachedReferences, recordRangeInfo, chunkList); + final SRAIterator newIterator = + new SRAIterator(acc, run, virtualHeader, cachedReferences, recordRangeInfo, chunkList); if (validationStringency != null) { newIterator.setValidationStringency(validationStringency); } @@ -166,7 +160,8 @@ public CloseableIterator queryUnmapped() { throw new RuntimeException("Cannot create file span - SRA file is empty"); } - SAMFileSpan span = new BAMFileSpan(new Chunk(recordRangeInfo.getTotalReferencesLength(), recordRangeInfo.getTotalRecordRangeLength())); + SAMFileSpan span = new BAMFileSpan( + new Chunk(recordRangeInfo.getTotalReferencesLength(), recordRangeInfo.getTotalRecordRangeLength())); return getIterator(span); } @@ -180,10 +175,8 @@ public ValidationStringency getValidationStringency() { return validationStringency; } - /** INDEXING */ - /** * Returns true if the supported index is browseable, meaning the bins in it can be traversed * and chunk data inspected and retrieved. @@ -270,8 +263,7 @@ private SAMFileHeader loadSamHeader() throws ErrorMsg { ReadGroupIterator itRg = run.getReadGroups(); while (itRg.nextReadGroup()) { String rgName = itRg.getName(); - if (rgName.isEmpty()) - rgName = runName; + if (rgName.isEmpty()) rgName = runName; SAMReadGroupRecord rg = new SAMReadGroupRecord(rgName); rg.setSample(runName); header.addReadGroup(rg); diff --git a/src/main/java/htsjdk/samtools/SRAIndex.java b/src/main/java/htsjdk/samtools/SRAIndex.java index b74ee635b6..d546aada7b 100644 --- a/src/main/java/htsjdk/samtools/SRAIndex.java +++ b/src/main/java/htsjdk/samtools/SRAIndex.java @@ -1,28 +1,28 @@ /*=========================================================================== -* -* PUBLIC DOMAIN NOTICE -* National Center for Biotechnology Information -* -* This software/database is a "United States Government Work" under the -* terms of the United States Copyright Act. It was written as part of -* the author's official duties as a United States Government employee and -* thus cannot be copyrighted. This software/database is freely available -* to the public for use. The National Library of Medicine and the U.S. -* Government have not placed any restriction on its use or reproduction. -* -* Although all reasonable efforts have been taken to ensure the accuracy -* and reliability of the software and data, the NLM and the U.S. -* Government do not and cannot warrant the performance or results that -* may be obtained by using this software or data. The NLM and the U.S. -* Government disclaim all warranties, express or implied, including -* warranties of performance, merchantability or fitness for any particular -* purpose. -* -* Please cite the author in any work or product based on this material. -* -* =========================================================================== -* -*/ + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + */ package htsjdk.samtools; @@ -74,7 +74,8 @@ public class SRAIndex implements BrowseableBAMIndex { /** * First bin number in last level */ - private static final int SRA_BIN_INDEX_OFFSET = GenomicIndexUtil.LEVEL_STARTS[GenomicIndexUtil.LEVEL_STARTS.length - 1]; + private static final int SRA_BIN_INDEX_OFFSET = + GenomicIndexUtil.LEVEL_STARTS[GenomicIndexUtil.LEVEL_STARTS.length - 1]; /** * How many bases should we go left on the reference to find all fragments that start before requested interval @@ -102,9 +103,8 @@ public SRAIndex(SAMFileHeader header, SRAIterator.RecordRangeInfo recordRangeInf @Override public int getLevelSize(int levelNumber) { if (levelNumber == GenomicIndexUtil.LEVEL_STARTS.length - 1) - return GenomicIndexUtil.MAX_BINS - GenomicIndexUtil.LEVEL_STARTS[levelNumber]-1; - else - return GenomicIndexUtil.LEVEL_STARTS[levelNumber+1] - GenomicIndexUtil.LEVEL_STARTS[levelNumber]; + return GenomicIndexUtil.MAX_BINS - GenomicIndexUtil.LEVEL_STARTS[levelNumber] - 1; + else return GenomicIndexUtil.LEVEL_STARTS[levelNumber + 1] - GenomicIndexUtil.LEVEL_STARTS[levelNumber]; } /** @@ -160,16 +160,16 @@ public BinList getBinsOverlapping(int referenceIndex, int startPos, int endPos) long refLength = recordRangeInfo.getReferenceLengthsAligned().get(referenceIndex); // convert to chunk address space within reference - long refStartPos = startPos - 1; + long refStartPos = startPos - 1; long refEndPos = endPos; if (refEndPos >= refLength) { throw new RuntimeException("refEndPos is larger than reference length"); } - int firstBinNumber = (int)refStartPos / SRA_BIN_SIZE; - int lastBinNumber = (int)(refEndPos - 1) / SRA_BIN_SIZE; + int firstBinNumber = (int) refStartPos / SRA_BIN_SIZE; + int lastBinNumber = (int) (refEndPos - 1) / SRA_BIN_SIZE; - int numberOfBins = ((int)refLength / SRA_BIN_SIZE) + 1; + int numberOfBins = ((int) refLength / SRA_BIN_SIZE) + 1; BitSet binBitSet = new BitSet(); binBitSet.set(0, SRA_BIN_INDEX_OFFSET, false); @@ -214,7 +214,8 @@ public BAMFileSpan getSpanOverlapping(int referenceIndex, int startPos, int endP public long getStartOfLastLinearBin() { int numberOfReferences = recordRangeInfo.getReferenceLengthsAligned().size(); long refOffset = recordRangeInfo.getReferenceOffsets().get(numberOfReferences - 1); - long lastChunkNumber = recordRangeInfo.getReferenceLengthsAligned().get(numberOfReferences - 1) / SRA_CHUNK_SIZE; + long lastChunkNumber = + recordRangeInfo.getReferenceLengthsAligned().get(numberOfReferences - 1) / SRA_CHUNK_SIZE; return lastChunkNumber * SRA_CHUNK_SIZE + refOffset; } @@ -224,7 +225,7 @@ public BAMIndexMetaData getMetaData(int reference) { } @Override - public void close() { } + public void close() {} /** * @param bin Requested bin @@ -241,7 +242,8 @@ private List getBinChunks(Bin bin) { int binNumber = bin.getBinNumber() - SRA_BIN_INDEX_OFFSET; long refOffset = recordRangeInfo.getReferenceOffsets().get(bin.getReferenceSequence()); - // move requested position MAX_FRAGMENT_OVERLAP bases behind, so that we take all the reads that overlap requested position + // move requested position MAX_FRAGMENT_OVERLAP bases behind, so that we take all the reads that overlap + // requested position int firstChunkCorrection = binNumber == 0 ? 0 : -MAX_FRAGMENT_OVERLAP; long binGlobalOffset = binNumber * SRA_BIN_SIZE + refOffset; diff --git a/src/main/java/htsjdk/samtools/SRAIterator.java b/src/main/java/htsjdk/samtools/SRAIterator.java index 9fbbc97b9f..026a6bf500 100644 --- a/src/main/java/htsjdk/samtools/SRAIterator.java +++ b/src/main/java/htsjdk/samtools/SRAIterator.java @@ -1,51 +1,47 @@ /*=========================================================================== -* -* PUBLIC DOMAIN NOTICE -* National Center for Biotechnology Information -* -* This software/database is a "United States Government Work" under the -* terms of the United States Copyright Act. It was written as part of -* the author's official duties as a United States Government employee and -* thus cannot be copyrighted. This software/database is freely available -* to the public for use. The National Library of Medicine and the U.S. -* Government have not placed any restriction on its use or reproduction. -* -* Although all reasonable efforts have been taken to ensure the accuracy -* and reliability of the software and data, the NLM and the U.S. -* Government do not and cannot warrant the performance or results that -* may be obtained by using this software or data. The NLM and the U.S. -* Government disclaim all warranties, express or implied, including -* warranties of performance, merchantability or fitness for any particular -* purpose. -* -* Please cite the author in any work or product based on this material. -* -* =========================================================================== -* -*/ + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + */ /** * Created by andrii.nikitiuk on 8/11/15. */ - package htsjdk.samtools; import htsjdk.samtools.SAMFileHeader.SortOrder; - import htsjdk.samtools.sra.ReferenceCache; import htsjdk.samtools.sra.SRAAccession; import htsjdk.samtools.sra.SRAAlignmentIterator; import htsjdk.samtools.sra.SRAUnalignmentIterator; import htsjdk.samtools.sra.SRAUtils; -import ngs.ErrorMsg; -import ngs.ReadCollection; -import ngs.Reference; - import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; +import ngs.ErrorMsg; +import ngs.ReadCollection; /** * SRA iterator which returns SAMRecords for requested list of chunks @@ -134,8 +130,13 @@ public static RecordRangeInfo getRecordsRangeInfo(ReadCollection run) { * @param recordRangeInfo info about record ranges withing SRA archive * @param chunks used to determine which records the iterator should return */ - public SRAIterator(SRAAccession accession, final ReadCollection run, final SAMFileHeader header, ReferenceCache cachedReferences, - final RecordRangeInfo recordRangeInfo, final List chunks) { + public SRAIterator( + SRAAccession accession, + final ReadCollection run, + final SAMFileHeader header, + ReferenceCache cachedReferences, + final RecordRangeInfo recordRangeInfo, + final List chunks) { this.accession = accession; this.run = run; this.header = header; @@ -174,7 +175,8 @@ public boolean hasNext() { while (currentChunk != null) { if (alignmentIterator == null) { if (currentChunk.getChunkStart() < recordRangeInfo.getTotalReferencesLength()) { - alignmentIterator = new SRAAlignmentIterator(accession, run, header, cachedReferences, recordRangeInfo, currentChunk); + alignmentIterator = new SRAAlignmentIterator( + accession, run, header, cachedReferences, recordRangeInfo, currentChunk); if (validationStringency != null) { alignmentIterator.setValidationStringency(validationStringency); } @@ -187,7 +189,8 @@ public boolean hasNext() { if (unalignmentIterator == null) { if (currentChunk.getChunkEnd() > recordRangeInfo.getTotalReferencesLength()) { - unalignmentIterator = new SRAUnalignmentIterator(accession, run, header, recordRangeInfo, currentChunk); + unalignmentIterator = + new SRAUnalignmentIterator(accession, run, header, recordRangeInfo, currentChunk); if (validationStringency != null) { unalignmentIterator.setValidationStringency(validationStringency); } @@ -230,7 +233,9 @@ public SAMRecord next() { } @Override - public void remove() { throw new UnsupportedOperationException("Removal of records not implemented."); } + public void remove() { + throw new UnsupportedOperationException("Removal of records not implemented."); + } @Override public void close() { @@ -241,7 +246,9 @@ public void close() { } @Override - public SAMRecordIterator assertSorted(final SortOrder sortOrder) { throw new UnsupportedOperationException("assertSorted is not implemented."); } + public SAMRecordIterator assertSorted(final SortOrder sortOrder) { + throw new UnsupportedOperationException("assertSorted is not implemented."); + } public void setValidationStringency(ValidationStringency validationStringency) { this.validationStringency = validationStringency; diff --git a/src/main/java/htsjdk/samtools/SamFileHeaderMerger.java b/src/main/java/htsjdk/samtools/SamFileHeaderMerger.java index d3cf16adaa..e7b2cb1b65 100644 --- a/src/main/java/htsjdk/samtools/SamFileHeaderMerger.java +++ b/src/main/java/htsjdk/samtools/SamFileHeaderMerger.java @@ -24,7 +24,6 @@ package htsjdk.samtools; import htsjdk.samtools.util.SequenceUtil; - import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -66,23 +65,23 @@ public class SamFileHeaderMerger { } } - //Super Header to construct + // Super Header to construct private final SAMFileHeader mergedHeader; private Collection readers; private final Collection headers; private int recordCounter; - //Translation of old group ids to new group ids + // Translation of old group ids to new group ids private final Map> samReadGroupIdTranslation = new IdentityHashMap>(); - //the read groups from different files use the same group ids + // the read groups from different files use the same group ids private boolean hasReadGroupCollisions = false; - //the program records from different files use the same program record ids + // the program records from different files use the same program record ids private boolean hasProgramGroupCollisions = false; - //Translation of old program group ids to new program group ids + // Translation of old program group ids to new program group ids private final Map> samProgramGroupIdTranslation = new IdentityHashMap>(); @@ -96,29 +95,32 @@ public class SamFileHeaderMerger { private final Map> samSeqDictionaryIdTranslationViaHeader = new IdentityHashMap>(); - //HeaderRecordFactory that creates SAMReadGroupRecord instances. - private static final HeaderRecordFactory READ_GROUP_RECORD_FACTORY = new HeaderRecordFactory() { - @Override - public SAMReadGroupRecord createRecord(final String id, final SAMReadGroupRecord srcReadGroupRecord) { - return new SAMReadGroupRecord(id, srcReadGroupRecord); - } - }; - - //HeaderRecordFactory that creates SAMProgramRecord instances. - private static final HeaderRecordFactory PROGRAM_RECORD_FACTORY = new HeaderRecordFactory() { - @Override - public SAMProgramRecord createRecord(final String id, final SAMProgramRecord srcProgramRecord) { - return new SAMProgramRecord(id, srcProgramRecord); - } - }; - - //comparator used to sort lists of program group and read group records - private static final Comparator RECORD_ID_COMPARATOR = new Comparator() { - @Override - public int compare(final AbstractSAMHeaderRecord o1, final AbstractSAMHeaderRecord o2) { - return o1.getId().compareTo(o2.getId()); - } - }; + // HeaderRecordFactory that creates SAMReadGroupRecord instances. + private static final HeaderRecordFactory READ_GROUP_RECORD_FACTORY = + new HeaderRecordFactory() { + @Override + public SAMReadGroupRecord createRecord(final String id, final SAMReadGroupRecord srcReadGroupRecord) { + return new SAMReadGroupRecord(id, srcReadGroupRecord); + } + }; + + // HeaderRecordFactory that creates SAMProgramRecord instances. + private static final HeaderRecordFactory PROGRAM_RECORD_FACTORY = + new HeaderRecordFactory() { + @Override + public SAMProgramRecord createRecord(final String id, final SAMProgramRecord srcProgramRecord) { + return new SAMProgramRecord(id, srcProgramRecord); + } + }; + + // comparator used to sort lists of program group and read group records + private static final Comparator RECORD_ID_COMPARATOR = + new Comparator() { + @Override + public int compare(final AbstractSAMHeaderRecord o1, final AbstractSAMHeaderRecord o2) { + return o1.getId().compareTo(o2.getId()); + } + }; /** * Create SAMFileHeader with additional information. Required that sequence dictionaries agree. @@ -142,7 +144,10 @@ public SamFileHeaderMerger(final Collection readers, final SAMFileHea * @deprecated replaced by {@link #SamFileHeaderMerger(SAMFileHeader.SortOrder, Collection, boolean)} */ @Deprecated - public SamFileHeaderMerger(final Collection readers, final SAMFileHeader.SortOrder sortOrder, final boolean mergeDictionaries) { + public SamFileHeaderMerger( + final Collection readers, + final SAMFileHeader.SortOrder sortOrder, + final boolean mergeDictionaries) { this(sortOrder, getHeadersFromReaders(readers), mergeDictionaries); this.readers = readers; } @@ -155,7 +160,10 @@ public SamFileHeaderMerger(final Collection readers, final SAMFileHea * @param mergeDictionaries If true, merge sequence dictionaries in new header. If false, require that * all input sequence dictionaries be identical. */ - public SamFileHeaderMerger(final SAMFileHeader.SortOrder sortOrder, final Collection headers, final boolean mergeDictionaries) { + public SamFileHeaderMerger( + final SAMFileHeader.SortOrder sortOrder, + final Collection headers, + final boolean mergeDictionaries) { this.headers = new LinkedHashSet(headers); this.mergedHeader = new SAMFileHeader(); @@ -202,7 +210,6 @@ private static List getHeadersFromReaders(final Collection getHeadersFromReaders(final Collection mergeReadGroups(final Collection headers) { - //prepare args for mergeHeaderRecords(..) call + // prepare args for mergeHeaderRecords(..) call final HashSet idsThatAreAlreadyTaken = new HashSet(); - final List> readGroupsToProcess = new LinkedList>(); + final List> readGroupsToProcess = + new LinkedList>(); for (final SAMFileHeader header : headers) { for (final SAMReadGroupRecord readGroup : header.getReadGroups()) { - //verify that there are no existing id collisions in this input file + // verify that there are no existing id collisions in this input file if (!idsThatAreAlreadyTaken.add(readGroup.getId())) - throw new SAMException("Input file: " + header + " contains more than one RG with the same id (" + readGroup.getId() + ")"); + throw new SAMException("Input file: " + header + " contains more than one RG with the same id (" + + readGroup.getId() + ")"); readGroupsToProcess.add(new HeaderRecordAndFileHeader(readGroup, header)); } @@ -229,15 +238,19 @@ private List mergeReadGroups(final Collection final List result = new LinkedList(); recordCounter = 0; - hasReadGroupCollisions = mergeHeaderRecords(readGroupsToProcess, READ_GROUP_RECORD_FACTORY, idsThatAreAlreadyTaken, samReadGroupIdTranslation, result); - - //sort the result list by record id + hasReadGroupCollisions = mergeHeaderRecords( + readGroupsToProcess, + READ_GROUP_RECORD_FACTORY, + idsThatAreAlreadyTaken, + samReadGroupIdTranslation, + result); + + // sort the result list by record id Collections.sort(result, RECORD_ID_COMPARATOR); return result; } - /** * Checks to see if there are clashes where different readers are using the same program * group IDs. If yes, then those IDs that collided are remapped. @@ -249,16 +262,18 @@ private List mergeProgramGroups(final Collection overallResult = new LinkedList(); - //this Set will accumulate all SAMProgramRecord ids that have been encountered so far. + // this Set will accumulate all SAMProgramRecord ids that have been encountered so far. final HashSet idsThatAreAlreadyTaken = new HashSet(); - //need to process all program groups - List> programGroupsLeftToProcess = new LinkedList>(); + // need to process all program groups + List> programGroupsLeftToProcess = + new LinkedList>(); for (final SAMFileHeader header : headers) { for (final SAMProgramRecord programGroup : header.getProgramRecords()) { - //verify that there are no existing id collisions in this input file + // verify that there are no existing id collisions in this input file if (!idsThatAreAlreadyTaken.add(programGroup.getId())) - throw new SAMException("Input file: " + header + " contains more than one PG with the same id (" + programGroup.getId() + ")"); + throw new SAMException("Input file: " + header + " contains more than one PG with the same id (" + + programGroup.getId() + ")"); programGroupsLeftToProcess.add(new HeaderRecordAndFileHeader(programGroup, header)); } @@ -267,17 +282,22 @@ private List mergeProgramGroups(final Collection> currentProgramGroups = new LinkedList>(); - for (final Iterator> programGroupsLeftToProcessIterator = programGroupsLeftToProcess.iterator(); programGroupsLeftToProcessIterator.hasNext(); ) { + // A program group header (lets say ID=2 PN=B PP=1) may have a PP (previous program) attribute which chains it + // to + // another program group header (lets say ID=1 PN=A) to indicate that the given file was + // processed by program A followed by program B. These PP attributes potentially + // connect headers into one or more tree structures. Merging is done by + // first merging all headers that don't have PP attributes (eg. tree roots), + // then updating and merging all headers whose PPs point to the tree-root headers, + // and so on until all program group headers are processed. + + // currentProgramGroups is the list of records to merge next. Start by merging the programGroups that don't have + // a PP attribute (eg. the tree roots). + List> currentProgramGroups = + new LinkedList>(); + for (final Iterator> programGroupsLeftToProcessIterator = + programGroupsLeftToProcess.iterator(); + programGroupsLeftToProcessIterator.hasNext(); ) { final HeaderRecordAndFileHeader pair = programGroupsLeftToProcessIterator.next(); if (pair.getHeaderRecord().getAttribute(SAMProgramRecord.PREVIOUS_PROGRAM_GROUP_ID_TAG) == null) { programGroupsLeftToProcessIterator.remove(); @@ -285,29 +305,43 @@ private List mergeProgramGroups(final Collection currentResult = new LinkedList(); - hasProgramGroupCollisions |= mergeHeaderRecords(currentProgramGroups, PROGRAM_RECORD_FACTORY, idsThatAreAlreadyTaken, samProgramGroupIdTranslation, currentResult); + hasProgramGroupCollisions |= mergeHeaderRecords( + currentProgramGroups, + PROGRAM_RECORD_FACTORY, + idsThatAreAlreadyTaken, + samProgramGroupIdTranslation, + currentResult); - //add currentResults to overallResults + // add currentResults to overallResults overallResult.addAll(currentResult); - //apply the newly-computed id translations to currentProgramGroups and programGroupsLeftToProcess + // apply the newly-computed id translations to currentProgramGroups and programGroupsLeftToProcess currentProgramGroups = translateIds(currentProgramGroups, samProgramGroupIdTranslation, false); programGroupsLeftToProcess = translateIds(programGroupsLeftToProcess, samProgramGroupIdTranslation, true); - //find all records in programGroupsLeftToProcess whose ppId points to a record that was just processed (eg. a record that's in currentProgramGroups), - //and move them to the list of programGroupsToProcessNext. - final LinkedList> programGroupsToProcessNext = new LinkedList>(); - for (final Iterator> programGroupsLeftToProcessIterator = programGroupsLeftToProcess.iterator(); programGroupsLeftToProcessIterator.hasNext(); ) { - final HeaderRecordAndFileHeader pairLeftToProcess = programGroupsLeftToProcessIterator.next(); - final Object ppIdOfRecordLeftToProcess = pairLeftToProcess.getHeaderRecord().getAttribute(SAMProgramRecord.PREVIOUS_PROGRAM_GROUP_ID_TAG); - //find what currentProgramGroups this ppId points to (NOTE: they have to come from the same file) + // find all records in programGroupsLeftToProcess whose ppId points to a record that was just processed (eg. + // a record that's in currentProgramGroups), + // and move them to the list of programGroupsToProcessNext. + final LinkedList> programGroupsToProcessNext = + new LinkedList>(); + for (final Iterator> programGroupsLeftToProcessIterator = + programGroupsLeftToProcess.iterator(); + programGroupsLeftToProcessIterator.hasNext(); ) { + final HeaderRecordAndFileHeader pairLeftToProcess = + programGroupsLeftToProcessIterator.next(); + final Object ppIdOfRecordLeftToProcess = pairLeftToProcess + .getHeaderRecord() + .getAttribute(SAMProgramRecord.PREVIOUS_PROGRAM_GROUP_ID_TAG); + // find what currentProgramGroups this ppId points to (NOTE: they have to come from the same file) for (final HeaderRecordAndFileHeader justProcessedPair : currentProgramGroups) { - final String idJustProcessed = justProcessedPair.getHeaderRecord().getId(); - if (pairLeftToProcess.getFileHeader() == justProcessedPair.getFileHeader() && ppIdOfRecordLeftToProcess.equals(idJustProcessed)) { + final String idJustProcessed = + justProcessedPair.getHeaderRecord().getId(); + if (pairLeftToProcess.getFileHeader() == justProcessedPair.getFileHeader() + && ppIdOfRecordLeftToProcess.equals(idJustProcessed)) { programGroupsLeftToProcessIterator.remove(); programGroupsToProcessNext.add(pairLeftToProcess); break; @@ -318,23 +352,24 @@ private List mergeProgramGroups(final Collection pair : programGroupsLeftToProcess) { final SAMProgramRecord record = pair.getHeaderRecord(); - errorMsg.append("@PG ID:" + record.getProgramGroupId() + " PN:" + record.getProgramName() + " PP:" + record.getPreviousProgramGroupId() + "\n"); + errorMsg.append("@PG ID:" + record.getProgramGroupId() + " PN:" + record.getProgramName() + " PP:" + + record.getPreviousProgramGroupId() + "\n"); } throw new SAMException(errorMsg.toString()); } - //sort the result list by record id + // sort the result list by record id Collections.sort(overallResult, RECORD_ID_COMPARATOR); return overallResult; } - /** * Utility method that takes a list of program groups and remaps all their * ids (including ppIds if requested) using the given idTranslationTable. @@ -352,8 +387,9 @@ private List> translateIds( final Map> idTranslationTable, final boolean translatePpIds) { - //go through programGroups and translate any IDs and PPs based on the idTranslationTable. - final List> result = new LinkedList>(); + // go through programGroups and translate any IDs and PPs based on the idTranslationTable. + final List> result = + new LinkedList>(); for (final HeaderRecordAndFileHeader pair : programGroups) { final SAMProgramRecord record = pair.getHeaderRecord(); final String id = record.getProgramGroupId(); @@ -362,7 +398,7 @@ private List> translateIds( final SAMFileHeader header = pair.getFileHeader(); final Map translations = idTranslationTable.get(header); - //see if one or both ids need to be translated + // see if one or both ids need to be translated SAMProgramRecord translatedRecord = null; if (translations != null) { final String translatedId = translations.get(id); @@ -385,14 +421,13 @@ private List> translateIds( if (translatedRecord != null) { result.add(new HeaderRecordAndFileHeader(translatedRecord, header)); } else { - result.add(pair); //keep the original record + result.add(pair); // keep the original record } } return result; } - /** * Utility method for merging a List of AbstractSAMHeaderRecords. If it finds * records that have identical ids and attributes, it will collapse them @@ -412,18 +447,22 @@ private List> translateIds( * @param result The list of merged header records. * @return True if there were collisions. */ - private boolean mergeHeaderRecords(final List> headerRecords, final HeaderRecordFactory headerRecordFactory, - final HashSet idsThatAreAlreadyTaken, final Map> idTranslationTable, final List result) { - - //The outer Map bins the header records by their ids. The nested Map further collapses - //header records which, in addition to having the same id, also have identical attributes. - //In other words, each key in the nested map represents one or more - //header records which have both identical ids and identical attributes. The List of - //SAMFileHeaders keeps track of which readers these header record(s) came from. + private boolean mergeHeaderRecords( + final List> headerRecords, + final HeaderRecordFactory headerRecordFactory, + final HashSet idsThatAreAlreadyTaken, + final Map> idTranslationTable, + final List result) { + + // The outer Map bins the header records by their ids. The nested Map further collapses + // header records which, in addition to having the same id, also have identical attributes. + // In other words, each key in the nested map represents one or more + // header records which have both identical ids and identical attributes. The List of + // SAMFileHeaders keeps track of which readers these header record(s) came from. final Map>> idToRecord = new LinkedHashMap>>(); - //Populate the idToRecord and seenIds data structures + // Populate the idToRecord and seenIds data structures for (final HeaderRecordAndFileHeader pair : headerRecords) { final RecordType record = pair.getHeaderRecord(); final SAMFileHeader header = pair.getFileHeader(); @@ -443,32 +482,35 @@ private boolean mergeHeaderRecords( fileHeaders.add(header); } - //Resolve any collisions between header records by remapping their ids. + // Resolve any collisions between header records by remapping their ids. boolean hasCollisions = false; for (final Map.Entry>> entry : idToRecord.entrySet()) { final String recordId = entry.getKey(); final Map> recordsWithSameId = entry.getValue(); - for (final Map.Entry> recordWithUniqueAttr : recordsWithSameId.entrySet()) { final RecordType record = recordWithUniqueAttr.getKey(); final List fileHeaders = recordWithUniqueAttr.getValue(); String newId; if (!idsThatAreAlreadyTaken.contains(recordId)) { - //don't remap 1st record. If there are more records - //with this id, they will be remapped in the 'else'. + // don't remap 1st record. If there are more records + // with this id, they will be remapped in the 'else'. newId = recordId; idsThatAreAlreadyTaken.add(recordId); ++recordCounter; } else { - //there is more than one record with this id. + // there is more than one record with this id. hasCollisions = true; - //Below we tack on one of roughly 1.7 million possible 4 digit base36 at random we do this because - //our old process of just counting from 0 upward and adding that to the previous id led to 1000s of hits on - //idsThatAreAlreadyTaken.contains just to resolve 1 collision when merging 1000s of similarly processed bams - while (idsThatAreAlreadyTaken.contains(newId = recordId + "." + positiveFourDigitBase36Str(recordCounter++))) ; + // Below we tack on one of roughly 1.7 million possible 4 digit base36 at random we do this because + // our old process of just counting from 0 upward and adding that to the previous id led to 1000s of + // hits on + // idsThatAreAlreadyTaken.contains just to resolve 1 collision when merging 1000s of similarly + // processed bams + while (idsThatAreAlreadyTaken.contains( + newId = recordId + "." + positiveFourDigitBase36Str(recordCounter++))) + ; idsThatAreAlreadyTaken.add(newId); } @@ -511,7 +553,6 @@ public static String positiveFourDigitBase36Str(int leftOver) { return builder.reverse().toString(); } - /** * Get the sequences off the SAMFileHeader. Throws runtime exception if the sequence * are different from one another. @@ -558,7 +599,8 @@ private SAMSequenceDictionary mergeSequenceDictionaries(final Collection holder = new LinkedList(); @@ -569,7 +611,8 @@ private SAMSequenceDictionary mergeSequences(final SAMSequenceDictionary mergeIn resultingDict.add(sequenceRecord); } - // Index into resultingDict of previous SAMSequenceRecord from mergeFromDict that already existed in mergeIntoDict. + // Index into resultingDict of previous SAMSequenceRecord from mergeFromDict that already existed in + // mergeIntoDict. int prevloc = -1; // Previous SAMSequenceRecord from mergeFromDict that already existed in mergeIntoDict. SAMSequenceRecord previouslyMerged = null; @@ -583,9 +626,10 @@ private SAMSequenceDictionary mergeSequences(final SAMSequenceDictionary mergeIn } else if (prevloc > loc) { // If sequenceRecord already exists in resultingDict, but prior to the previous one // from mergeIntoDict that already existed, cannot merge. - throw new SAMException("Cannot merge sequence dictionaries because sequence " + - sequenceRecord.getSequenceName() + " and " + previouslyMerged.getSequenceName() + - " are in different orders in two input sequence dictionaries."); + throw new SAMException( + "Cannot merge sequence dictionaries because sequence " + sequenceRecord.getSequenceName() + + " and " + previouslyMerged.getSequenceName() + + " are in different orders in two input sequence dictionaries."); } else { // Since sequenceRecord already exists in resultingDict, don't need to add it. // Add in all the sequences prior to it that have been held in holder. @@ -626,7 +670,8 @@ private static int getIndexOfSequenceName(final List list, fi * @param headers the collections of headers. * @param masterDictionary the superset dictionary we've created. */ - private void createSequenceMapping(final Collection headers, final SAMSequenceDictionary masterDictionary) { + private void createSequenceMapping( + final Collection headers, final SAMSequenceDictionary masterDictionary) { final LinkedList resultingDictStr = new LinkedList<>(); for (final SAMSequenceRecord r : masterDictionary.getSequences()) { resultingDictStr.add(r.getSequenceName()); @@ -641,7 +686,6 @@ private void createSequenceMapping(final Collection headers, fina } } - /** * Returns the read group id that should be used for the input read and RG id. * @@ -743,13 +787,13 @@ public Integer getMergedSequenceIndex(final SAMFileHeader header, final Integer final Integer newIndex = mapping.get(oldReferenceSequenceIndex); if (newIndex == null) { - throw new SAMException("No mapping for reference index " + oldReferenceSequenceIndex + " from header: " + header); + throw new SAMException( + "No mapping for reference index " + oldReferenceSequenceIndex + " from header: " + header); } return newIndex; } - /** * Implementations of this interface are used by mergeHeaderRecords(..) to instantiate * specific subclasses of AbstractSAMHeaderRecord. diff --git a/src/main/java/htsjdk/samtools/SamFileValidator.java b/src/main/java/htsjdk/samtools/SamFileValidator.java index bbcede3d76..eabfbf0350 100644 --- a/src/main/java/htsjdk/samtools/SamFileValidator.java +++ b/src/main/java/htsjdk/samtools/SamFileValidator.java @@ -24,8 +24,8 @@ package htsjdk.samtools; -import htsjdk.samtools.SAMValidationError.Type; import htsjdk.samtools.BamIndexValidator.IndexValidationStringency; +import htsjdk.samtools.SAMValidationError.Type; import htsjdk.samtools.metrics.MetricBase; import htsjdk.samtools.metrics.MetricsFile; import htsjdk.samtools.reference.ReferenceSequence; @@ -33,7 +33,6 @@ import htsjdk.samtools.reference.ReferenceSequenceFileWalker; import htsjdk.samtools.util.BlockCompressedInputStream; import htsjdk.samtools.util.CloseableIterator; -import htsjdk.samtools.util.CloserUtil; import htsjdk.samtools.util.FastqQualityFormat; import htsjdk.samtools.util.Histogram; import htsjdk.samtools.util.IOUtil; @@ -42,12 +41,9 @@ import htsjdk.samtools.util.QualityEncodingDetector; import htsjdk.samtools.util.SequenceUtil; import htsjdk.samtools.util.StringUtil; - -import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -84,7 +80,7 @@ */ public class SamFileValidator { - private final static Log log = Log.getInstance(SamFileValidator.class); + private static final Log log = Log.getInstance(SamFileValidator.class); private final PrintWriter out; private Histogram errorsByType; @@ -221,10 +217,13 @@ public void validateBamFileTermination(final Path inputFile) { final BlockCompressedInputStream.FileTermination terminationState = BlockCompressedInputStream.checkTermination(inputFile); if (terminationState.equals(BlockCompressedInputStream.FileTermination.DEFECTIVE)) { - addError(new SAMValidationError(Type.TRUNCATED_FILE, "BAM file has defective last gzip block", + addError(new SAMValidationError( + Type.TRUNCATED_FILE, + "BAM file has defective last gzip block", inputFile.toUri().toString())); } else if (terminationState.equals(BlockCompressedInputStream.FileTermination.HAS_HEALTHY_LAST_BLOCK)) { - addError(new SAMValidationError(Type.BAM_FILE_MISSING_TERMINATOR_BLOCK, + addError(new SAMValidationError( + Type.BAM_FILE_MISSING_TERMINATOR_BLOCK, "Older BAM file -- does not have terminator block", inputFile.toUri().toString())); } @@ -337,16 +336,19 @@ private void validateSamRecordsAndQualityFormat(final Iterable samRec validateSecondaryBaseCalls(record, recordNumber); validateTags(record, recordNumber); if (sequenceDictionaryEmptyAndNoWarningEmitted && !record.getReadUnmappedFlag()) { - addError(new SAMValidationError(Type.MISSING_SEQUENCE_DICTIONARY, "Sequence dictionary is empty", null)); + addError(new SAMValidationError( + Type.MISSING_SEQUENCE_DICTIONARY, "Sequence dictionary is empty", null)); sequenceDictionaryEmptyAndNoWarningEmitted = false; - } - if ((qualityNotStoredErrorCount++ < MAX_QUALITY_NOT_STORED_ERRORS) && record.getBaseQualityString().equals("*")) { - addError(new SAMValidationError(Type.QUALITY_NOT_STORED, - "QUAL field is set to * (unspecified quality scores), this is allowed by the SAM" + - " specification but many tools expect reads to include qualities ", - record.getReadName(), recordNumber)); + if ((qualityNotStoredErrorCount++ < MAX_QUALITY_NOT_STORED_ERRORS) + && record.getBaseQualityString().equals("*")) { + addError(new SAMValidationError( + Type.QUALITY_NOT_STORED, + "QUAL field is set to * (unspecified quality scores), this is allowed by the SAM" + + " specification but many tools expect reads to include qualities ", + record.getReadName(), + recordNumber)); } progress.record(record); @@ -354,9 +356,15 @@ private void validateSamRecordsAndQualityFormat(final Iterable samRec try { if (progress.getCount() > 0) { // Avoid exception being thrown as a result of no qualities being read - final FastqQualityFormat format = qualityDetector.generateBestGuess(QualityEncodingDetector.FileContext.SAM, FastqQualityFormat.Standard); + final FastqQualityFormat format = qualityDetector.generateBestGuess( + QualityEncodingDetector.FileContext.SAM, FastqQualityFormat.Standard); if (format != FastqQualityFormat.Standard) { - addError(new SAMValidationError(Type.INVALID_QUALITY_FORMAT, String.format("Detected %s quality score encoding, but expected %s.", format, FastqQualityFormat.Standard), null)); + addError(new SAMValidationError( + Type.INVALID_QUALITY_FORMAT, + String.format( + "Detected %s quality score encoding, but expected %s.", + format, FastqQualityFormat.Standard), + null)); } } } catch (SAMException e) { @@ -378,10 +386,11 @@ private void validateSamRecordsAndQualityFormat(final Iterable samRec private void validateReadGroup(final SAMRecord record, final SAMFileHeader header) { final SAMReadGroupRecord rg = record.getReadGroup(); if (rg == null) { - addError(new SAMValidationError(Type.RECORD_MISSING_READ_GROUP, - "A record is missing a read group", record.getReadName())); + addError(new SAMValidationError( + Type.RECORD_MISSING_READ_GROUP, "A record is missing a read group", record.getReadName())); } else if (header.getReadGroup(rg.getId()) == null) { - addError(new SAMValidationError(Type.READ_GROUP_NOT_FOUND, + addError(new SAMValidationError( + Type.READ_GROUP_NOT_FOUND, "A record has a read group not found in the header: ", record.getReadName() + ", " + rg.getReadGroupId())); } @@ -399,22 +408,30 @@ private void validateTags(final SAMRecord record, final long recordNumber) { for (final SAMRecord.SAMTagAndValue tagAndValue : attributes) { if (tagAndValue.value instanceof Long) { - addError(new SAMValidationError(Type.TAG_VALUE_TOO_LARGE, + addError(new SAMValidationError( + Type.TAG_VALUE_TOO_LARGE, "Numeric value too large for tag " + tagAndValue.tag, - record.getReadName(), recordNumber)); + record.getReadName(), + recordNumber)); } if (!tags.add(tagAndValue.tag)) { - addError(new SAMValidationError(Type.DUPLICATE_SAM_TAG, - "Duplicate SAM tag (" + tagAndValue.tag + ") found.", record.getReadName(), recordNumber)); + addError(new SAMValidationError( + Type.DUPLICATE_SAM_TAG, + "Duplicate SAM tag (" + tagAndValue.tag + ") found.", + record.getReadName(), + recordNumber)); } } - if (tags.contains(SAMTag.CG.name())){ - addError(new SAMValidationError(Type.CG_TAG_FOUND_IN_ATTRIBUTES, - "The CG Tag should only be used in BAM format to hold a large cigar. " + - "It was found containing the value: " + - record.getAttribute(SAMTag.CG), record.getReadName(), recordNumber)); + if (tags.contains(SAMTag.CG.name())) { + addError(new SAMValidationError( + Type.CG_TAG_FOUND_IN_ATTRIBUTES, + "The CG Tag should only be used in BAM format to hold a large cigar. " + + "It was found containing the value: " + + record.getAttribute(SAMTag.CG), + record.getReadName(), + recordNumber)); } } @@ -422,9 +439,11 @@ private void validateSecondaryBaseCalls(final SAMRecord record, final long recor final String e2 = (String) record.getAttribute(SAMTag.E2); if (e2 != null) { if (e2.length() != record.getReadLength()) { - addError(new SAMValidationError(Type.MISMATCH_READ_LENGTH_AND_E2_LENGTH, + addError(new SAMValidationError( + Type.MISMATCH_READ_LENGTH_AND_E2_LENGTH, String.format("E2 tag length (%d) != read length (%d)", e2.length(), record.getReadLength()), - record.getReadName(), recordNumber)); + record.getReadName(), + recordNumber)); } final byte[] bases = record.getReadBases(); final byte[] secondaryBases = StringUtil.stringToBytes(e2); @@ -433,19 +452,24 @@ private void validateSecondaryBaseCalls(final SAMRecord record, final long recor continue; } if (SequenceUtil.basesEqual(bases[i], secondaryBases[i])) { - addError(new SAMValidationError(Type.E2_BASE_EQUALS_PRIMARY_BASE, - String.format("Secondary base call (%c) == primary base call (%c)", + addError(new SAMValidationError( + Type.E2_BASE_EQUALS_PRIMARY_BASE, + String.format( + "Secondary base call (%c) == primary base call (%c)", (char) secondaryBases[i], (char) bases[i]), - record.getReadName(), recordNumber)); + record.getReadName(), + recordNumber)); break; } } } final String u2 = (String) record.getAttribute(SAMTag.U2); if (u2 != null && u2.length() != record.getReadLength()) { - addError(new SAMValidationError(Type.MISMATCH_READ_LENGTH_AND_U2_LENGTH, + addError(new SAMValidationError( + Type.MISMATCH_READ_LENGTH_AND_U2_LENGTH, String.format("U2 tag length (%d) != read length (%d)", u2.length(), record.getReadLength()), - record.getReadName(), recordNumber)); + record.getReadName(), + recordNumber)); } } @@ -460,7 +484,8 @@ private boolean validateMateCigar(final SAMRecord record, final long recordNumbe private boolean validateCigar(final SAMRecord record, final long recordNumber, final boolean isReadCigar) { final ValidationStringency savedStringency = record.getValidationStringency(); record.setValidationStringency(ValidationStringency.LENIENT); - final List errors = isReadCigar ? record.validateCigar(recordNumber) : SAMUtils.validateMateCigar(record, recordNumber); + final List errors = + isReadCigar ? record.validateCigar(recordNumber) : SAMUtils.validateMateCigar(record, recordNumber); record.setValidationStringency(savedStringency); if (errors == null) { return true; @@ -520,14 +545,14 @@ private void validateNmTag(final SAMRecord record, final long recordNumber) { recordNumber)); } else if (refFileWalker != null) { final ReferenceSequence refSequence = refFileWalker.get(record.getReferenceIndex()); - final int actualNucleotideDiffs = SequenceUtil.calculateSamNmTag(record, refSequence.getBases(), - 0, isBisulfiteSequenced()); + final int actualNucleotideDiffs = + SequenceUtil.calculateSamNmTag(record, refSequence.getBases(), 0, isBisulfiteSequenced()); if (!tagNucleotideDiffs.equals(actualNucleotideDiffs)) { addError(new SAMValidationError( Type.INVALID_TAG_NM, - "NM tag (nucleotide differences) in file [" + tagNucleotideDiffs + - "] does not match reality [" + actualNucleotideDiffs + "]", + "NM tag (nucleotide differences) in file [" + tagNucleotideDiffs + + "] does not match reality [" + actualNucleotideDiffs + "]", record.getReadName(), recordNumber)); } @@ -547,7 +572,8 @@ private void validateMateFields(final SAMRecord record, final long recordNumber) final PairEndInfo pairEndInfo = pairEndInfoByName.remove(record.getReferenceIndex(), record.getReadName()); if (pairEndInfo == null) { - pairEndInfoByName.put(record.getMateReferenceIndex(), record.getReadName(), new PairEndInfo(record, recordNumber)); + pairEndInfoByName.put( + record.getMateReferenceIndex(), record.getReadName(), new PairEndInfo(record, recordNumber)); } else { final List errors = pairEndInfo.validateMates(new PairEndInfo(record, recordNumber), record.getReadName()); @@ -564,9 +590,11 @@ private void validateHeader(final SAMFileHeader fileHeader) { if (fileHeader.getVersion() == null) { addError(new SAMValidationError(Type.MISSING_VERSION_NUMBER, "Header has no version number", null)); } else if (!SAMFileHeader.ACCEPTABLE_VERSIONS.contains(fileHeader.getVersion())) { - addError(new SAMValidationError(Type.INVALID_VERSION_NUMBER, "Header version: " + - fileHeader.getVersion() + " does not match any of the acceptable versions: " + - StringUtil.join(", ", SAMFileHeader.ACCEPTABLE_VERSIONS.toArray(new String[0])), + addError(new SAMValidationError( + Type.INVALID_VERSION_NUMBER, + "Header version: " + fileHeader.getVersion() + + " does not match any of the acceptable versions: " + + StringUtil.join(", ", SAMFileHeader.ACCEPTABLE_VERSIONS.toArray(new String[0])), null)); } if (fileHeader.getSequenceDictionary().isEmpty()) { @@ -574,15 +602,18 @@ private void validateHeader(final SAMFileHeader fileHeader) { } else { if (samSequenceDictionary != null) { if (!fileHeader.getSequenceDictionary().isSameDictionary(samSequenceDictionary)) { - addError(new SAMValidationError(Type.MISMATCH_FILE_SEQ_DICT, "Mismatch between file and sequence dictionary", null)); + addError(new SAMValidationError( + Type.MISMATCH_FILE_SEQ_DICT, "Mismatch between file and sequence dictionary", null)); } } - + final List longSeqs = fileHeader.getSequenceDictionary().getSequences().stream() - .filter(s -> s.getSequenceLength() > GenomicIndexUtil.BIN_GENOMIC_SPAN).collect(Collectors.toList()); + .filter(s -> s.getSequenceLength() > GenomicIndexUtil.BIN_GENOMIC_SPAN) + .collect(Collectors.toList()); if (!longSeqs.isEmpty()) { - final String msg = "Reference sequences are too long for BAI indexing: " + StringUtil.join(", ", longSeqs); + final String msg = + "Reference sequences are too long for BAI indexing: " + StringUtil.join(", ", longSeqs); addError(new SAMValidationError(Type.REF_SEQ_TOO_LONG_FOR_BAI, msg, null)); } } @@ -593,8 +624,10 @@ private void validateHeader(final SAMFileHeader fileHeader) { for (int i = 0; i < pgs.size() - 1; i++) { for (int j = i + 1; j < pgs.size(); j++) { if (pgs.get(i).getProgramGroupId().equals(pgs.get(j).getProgramGroupId())) { - addError(new SAMValidationError(Type.DUPLICATE_PROGRAM_GROUP_ID, "Duplicate " + - "program group id: " + pgs.get(i).getProgramGroupId(), null)); + addError(new SAMValidationError( + Type.DUPLICATE_PROGRAM_GROUP_ID, + "Duplicate " + "program group id: " + pgs.get(i).getProgramGroupId(), + null)); } } } @@ -605,15 +638,16 @@ private void validateHeader(final SAMFileHeader fileHeader) { for (final SAMReadGroupRecord record : rgs) { final String readGroupID = record.getReadGroupId(); if (readGroupIDs.contains(readGroupID)) { - addError(new SAMValidationError(Type.DUPLICATE_READ_GROUP_ID, "Duplicate " + - "read group id: " + readGroupID, null)); + addError(new SAMValidationError( + Type.DUPLICATE_READ_GROUP_ID, "Duplicate " + "read group id: " + readGroupID, null)); } else { readGroupIDs.add(readGroupID); } final String platformValue = record.getPlatform(); if (platformValue == null || "".equals(platformValue)) { - addError(new SAMValidationError(Type.MISSING_PLATFORM_VALUE, + addError(new SAMValidationError( + Type.MISSING_PLATFORM_VALUE, "A platform (PL) attribute was not found for read group ", readGroupID)); } else { @@ -621,8 +655,10 @@ private void validateHeader(final SAMFileHeader fileHeader) { try { SAMReadGroupRecord.PlatformValue.valueOf(platformValue.toUpperCase()); } catch (IllegalArgumentException e) { - addError(new SAMValidationError(Type.INVALID_PLATFORM_VALUE, - "The platform (PL) attribute (" + platformValue + ") + was not one of the valid values for read group ", + addError(new SAMValidationError( + Type.INVALID_PLATFORM_VALUE, + "The platform (PL) attribute (" + platformValue + + ") + was not one of the valid values for read group ", readGroupID)); } } @@ -700,7 +736,8 @@ public void setBisulfiteSequenced(boolean bisulfiteSequenced) { @Deprecated public SamFileValidator setValidateIndex(final boolean validateIndex) { // The SamReader must also have IndexCaching enabled to have the index validated, - return this.setIndexValidationStringency(validateIndex ? IndexValidationStringency.EXHAUSTIVE : IndexValidationStringency.NONE); + return this.setIndexValidationStringency( + validateIndex ? IndexValidationStringency.EXHAUSTIVE : IndexValidationStringency.NONE); } public SamFileValidator setIndexValidationStringency(final IndexValidationStringency stringency) { @@ -708,8 +745,7 @@ public SamFileValidator setIndexValidationStringency(final IndexValidationString return this; } - public static class ValidationMetrics extends MetricBase { - } + public static class ValidationMetrics extends MetricBase {} /** * This class is used so we don't have to store the entire SAMRecord in memory while we wait @@ -751,10 +787,19 @@ public PairEndInfo(final SAMRecord record, final long recordNumber) { this.firstOfPairFlag = record.getFirstOfPairFlag(); } - private PairEndInfo(final int readAlignmentStart, final int readReferenceIndex, final boolean readNegStrandFlag, final boolean readUnmappedFlag, - final String readCigarString, - final int mateAlignmentStart, final int mateReferenceIndex, final boolean mateNegStrandFlag, final boolean mateUnmappedFlag, - final String mateCigarString, final boolean firstOfPairFlag, final long recordNumber) { + private PairEndInfo( + final int readAlignmentStart, + final int readReferenceIndex, + final boolean readNegStrandFlag, + final boolean readUnmappedFlag, + final String readCigarString, + final int mateAlignmentStart, + final int mateReferenceIndex, + final boolean mateNegStrandFlag, + final boolean mateUnmappedFlag, + final String mateCigarString, + final boolean firstOfPairFlag, + final long recordNumber) { this.readAlignmentStart = readAlignmentStart; this.readReferenceIndex = readReferenceIndex; this.readNegStrandFlag = readNegStrandFlag; @@ -780,13 +825,16 @@ public List validateMates(final PairEndInfo mate, final Stri Type.MATES_ARE_SAME_END, "Both mates are marked as " + whichEnd + " of pair", readName, - this.recordNumber - )); + this.recordNumber)); } return errors; } - private void validateMateFields(final PairEndInfo end1, final PairEndInfo end2, final String readName, final List errors) { + private void validateMateFields( + final PairEndInfo end1, + final PairEndInfo end2, + final String readName, + final List errors) { if (end1.mateAlignmentStart != end2.readAlignmentStart) { errors.add(new SAMValidationError( Type.MISMATCH_MATE_ALIGNMENT_START, @@ -922,10 +970,19 @@ public Map.Entry decode() { final boolean firstOfPairFlag = in.readBoolean(); final long recordNumber = in.readLong(); - final PairEndInfo rec = new PairEndInfo(readAlignmentStart, readReferenceIndex, readNegStrandFlag, - readUnmappedFlag, readCigarString, mateAlignmentStart, mateReferenceIndex, mateNegStrandFlag, - mateUnmappedFlag, mateCigarString, - firstOfPairFlag, recordNumber); + final PairEndInfo rec = new PairEndInfo( + readAlignmentStart, + readReferenceIndex, + readNegStrandFlag, + readUnmappedFlag, + readCigarString, + mateAlignmentStart, + mateReferenceIndex, + mateNegStrandFlag, + mateUnmappedFlag, + mateCigarString, + firstOfPairFlag, + recordNumber); return new AbstractMap.SimpleEntry(key, rec); } catch (IOException e) { throw new SAMException("Error reading PairInfo from disk", e); diff --git a/src/main/java/htsjdk/samtools/SamFiles.java b/src/main/java/htsjdk/samtools/SamFiles.java index 25bad85de5..2d65223677 100644 --- a/src/main/java/htsjdk/samtools/SamFiles.java +++ b/src/main/java/htsjdk/samtools/SamFiles.java @@ -13,7 +13,7 @@ */ public class SamFiles { - private final static Log LOG = Log.getInstance(SamFiles.class); + private static final Log LOG = Log.getInstance(SamFiles.class); /** * Finds the index file associated with the provided SAM file. The index file must exist and be reachable to be found. @@ -35,7 +35,7 @@ public static File findIndex(final File samFile) { * @return The index for the provided SAM, or null if one was not found. */ public static Path findIndex(final Path samPath) { - final Path indexPath = lookForIndex(samPath); //try to find the index + final Path indexPath = lookForIndex(samPath); // try to find the index if (indexPath == null) { return unsymlinkAndLookForIndex(samPath); } else { @@ -51,7 +51,7 @@ private static Path unsymlinkAndLookForIndex(Path samPath) { try { final Path canonicalSamPath = samPath.toRealPath(); // resolve symbolic links final Path canonicalIndexPath = lookForIndex(canonicalSamPath); - if ( canonicalIndexPath != null) { + if (canonicalIndexPath != null) { LOG.warn("The index file " + canonicalIndexPath.toAbsolutePath() + " was found by resolving the canonical path of a symlink: " + samPath.toAbsolutePath() + " -> " + samPath.toRealPath()); @@ -62,12 +62,14 @@ private static Path unsymlinkAndLookForIndex(Path samPath) { } } - private static Path lookForIndex(final Path samPath) {// If input is foo.bam, look for foo.bai or foo.csi + private static Path lookForIndex(final Path samPath) { // If input is foo.bam, look for foo.bai or foo.csi Path indexPath; final String fileName = samPath.getFileName().toString(); // works for all path types (e.g. HDFS) if (fileName.endsWith(FileExtensions.BAM)) { - final String bai = fileName.substring(0, fileName.length() - FileExtensions.BAM.length()) + FileExtensions.BAI_INDEX; - final String csi = fileName.substring(0, fileName.length() - FileExtensions.BAM.length()) + FileExtensions.CSI; + final String bai = + fileName.substring(0, fileName.length() - FileExtensions.BAM.length()) + FileExtensions.BAI_INDEX; + final String csi = + fileName.substring(0, fileName.length() - FileExtensions.BAM.length()) + FileExtensions.CSI; indexPath = samPath.resolveSibling(bai); if (Files.isRegularFile(indexPath)) { // works for all path types (e.g. HDFS) return indexPath; @@ -78,9 +80,9 @@ private static Path lookForIndex(final Path samPath) {// If input is foo.bam, lo } } - } else if (fileName.endsWith(FileExtensions.CRAM)) { - final String crai = fileName.substring(0, fileName.length() - FileExtensions.CRAM.length()) + FileExtensions.CRAM_INDEX; + final String crai = + fileName.substring(0, fileName.length() - FileExtensions.CRAM.length()) + FileExtensions.CRAM_INDEX; indexPath = samPath.resolveSibling(crai); if (Files.isRegularFile(indexPath)) { return indexPath; diff --git a/src/main/java/htsjdk/samtools/SamFlagField.java b/src/main/java/htsjdk/samtools/SamFlagField.java index 8c8b3663b6..a59fdf8257 100644 --- a/src/main/java/htsjdk/samtools/SamFlagField.java +++ b/src/main/java/htsjdk/samtools/SamFlagField.java @@ -32,14 +32,14 @@ * In a string FLAG, each character represents one bit with * p=0x1 (paired), P=0x2 (properly paired), u=0x4 (unmapped), * U=0x8 (mate unmapped), r=0x10 (reverse), R=0x20 (mate reverse) - * 1=0x40 (first), 2=0x80 (second), s=0x100 (not primary), + * 1=0x40 (first), 2=0x80 (second), s=0x100 (not primary), * x=0x200 (failure), d=0x400 (duplicate), and S=0x800 (secondary). * This was inspired by 'samtools view -X'. * * We also output a character when the following bits *are not* set: - * m=0x4 (mapped), M=0x8 (mate mapped), f=0x10 (forward), F=0x20 + * m=0x4 (mapped), M=0x8 (mate mapped), f=0x10 (forward), F=0x20 * (mate forward). - * + * * @author nhomer */ public enum SamFlagField { @@ -48,10 +48,11 @@ public enum SamFlagField { public String format(final int flag) { throw new SAMFormatException("NONE not allowed for the SamFlagField when writing the SAM flag field."); } + @Override protected int parseWithoutValidation(final String flag) { throw new SAMFormatException("NONE not allowed for the SamFlagField when reading the SAM flag field."); - } + } }, DECIMAL { @Override @@ -69,6 +70,7 @@ protected int parseWithoutValidation(final String flag) { public String format(final int flag) { return String.format(Locale.US, "%#x", flag); } + @Override protected int parseWithoutValidation(final String flag) { return Integer.parseInt(flag.substring(2), 16); @@ -79,6 +81,7 @@ protected int parseWithoutValidation(final String flag) { public String format(final int flag) { return String.format(Locale.US, "%#o", flag); } + @Override protected int parseWithoutValidation(final String flag) { return Integer.parseInt(flag, 8); @@ -96,27 +99,27 @@ public String format(final int flag) { // https://github.com/jmarshall/cansam/blob/master/lib/alignment.cpp final StringBuilder value = new StringBuilder(); - if ((flag & SAMFlag.READ_UNMAPPED.flag) != 0) value.append('u'); - else value.append('m'); + if ((flag & SAMFlag.READ_UNMAPPED.flag) != 0) value.append('u'); + else value.append('m'); - if ((flag & SAMFlag.READ_REVERSE_STRAND.flag) != 0) value.append('r'); - else if ((flag & SAMFlag.READ_UNMAPPED.flag) == 0) value.append('f'); + if ((flag & SAMFlag.READ_REVERSE_STRAND.flag) != 0) value.append('r'); + else if ((flag & SAMFlag.READ_UNMAPPED.flag) == 0) value.append('f'); - if ((flag & SAMFlag.MATE_UNMAPPED.flag) != 0) value.append('U'); - else if ((flag & SAMFlag.READ_PAIRED.flag) != 0) value.append('M'); + if ((flag & SAMFlag.MATE_UNMAPPED.flag) != 0) value.append('U'); + else if ((flag & SAMFlag.READ_PAIRED.flag) != 0) value.append('M'); - if ((flag & SAMFlag.MATE_REVERSE_STRAND.flag) != 0) value.append('R'); - else if ((flag & SAMFlag.READ_PAIRED.flag) != 0) value.append('F'); + if ((flag & SAMFlag.MATE_REVERSE_STRAND.flag) != 0) value.append('R'); + else if ((flag & SAMFlag.READ_PAIRED.flag) != 0) value.append('F'); - if ((flag & SAMFlag.READ_PAIRED.flag) != 0) value.append('p'); - if ((flag & SAMFlag.PROPER_PAIR.flag) != 0) value.append('P'); - if ((flag & SAMFlag.FIRST_OF_PAIR.flag) != 0) value.append('1'); - if ((flag & SAMFlag.SECOND_OF_PAIR.flag) != 0) value.append('2'); + if ((flag & SAMFlag.READ_PAIRED.flag) != 0) value.append('p'); + if ((flag & SAMFlag.PROPER_PAIR.flag) != 0) value.append('P'); + if ((flag & SAMFlag.FIRST_OF_PAIR.flag) != 0) value.append('1'); + if ((flag & SAMFlag.SECOND_OF_PAIR.flag) != 0) value.append('2'); - if ((flag & SAMFlag.SECONDARY_ALIGNMENT.flag) != 0) value.append('s'); - if ((flag & SAMFlag.SUPPLEMENTARY_ALIGNMENT.flag) != 0) value.append('S'); + if ((flag & SAMFlag.SECONDARY_ALIGNMENT.flag) != 0) value.append('s'); + if ((flag & SAMFlag.SUPPLEMENTARY_ALIGNMENT.flag) != 0) value.append('S'); if ((flag & SAMFlag.READ_FAILS_VENDOR_QUALITY_CHECK.flag) != 0) value.append('x'); - if ((flag & SAMFlag.DUPLICATE_READ.flag) != 0) value.append('d'); + if ((flag & SAMFlag.DUPLICATE_READ.flag) != 0) value.append('d'); return value.toString(); } @@ -132,18 +135,42 @@ protected int parseWithoutValidation(final String flag) { for (int i = 0; i < flag.length(); i++) { switch (flag.charAt(i)) { - case 'p': value |= SAMFlag.READ_PAIRED.flag; break; - case 'P': value |= SAMFlag.PROPER_PAIR.flag; break; - case 'u': value |= SAMFlag.READ_UNMAPPED.flag; break; - case 'U': value |= SAMFlag.MATE_UNMAPPED.flag; break; - case 'r': value |= SAMFlag.READ_REVERSE_STRAND.flag; break; - case 'R': value |= SAMFlag.MATE_REVERSE_STRAND.flag; break; - case '1': value |= SAMFlag.FIRST_OF_PAIR.flag; break; - case '2': value |= SAMFlag.SECOND_OF_PAIR.flag; break; - case 's': value |= SAMFlag.SECONDARY_ALIGNMENT.flag; break; - case 'x': value |= SAMFlag.READ_FAILS_VENDOR_QUALITY_CHECK.flag; break; - case 'd': value |= SAMFlag.DUPLICATE_READ.flag; break; - case 'S': value |= SAMFlag.SUPPLEMENTARY_ALIGNMENT.flag; break; + case 'p': + value |= SAMFlag.READ_PAIRED.flag; + break; + case 'P': + value |= SAMFlag.PROPER_PAIR.flag; + break; + case 'u': + value |= SAMFlag.READ_UNMAPPED.flag; + break; + case 'U': + value |= SAMFlag.MATE_UNMAPPED.flag; + break; + case 'r': + value |= SAMFlag.READ_REVERSE_STRAND.flag; + break; + case 'R': + value |= SAMFlag.MATE_REVERSE_STRAND.flag; + break; + case '1': + value |= SAMFlag.FIRST_OF_PAIR.flag; + break; + case '2': + value |= SAMFlag.SECOND_OF_PAIR.flag; + break; + case 's': + value |= SAMFlag.SECONDARY_ALIGNMENT.flag; + break; + case 'x': + value |= SAMFlag.READ_FAILS_VENDOR_QUALITY_CHECK.flag; + break; + case 'd': + value |= SAMFlag.DUPLICATE_READ.flag; + break; + case 'S': + value |= SAMFlag.SUPPLEMENTARY_ALIGNMENT.flag; + break; case 'f': case 'F': case 'm': @@ -151,7 +178,8 @@ protected int parseWithoutValidation(final String flag) { case '_': break; default: - throw new SAMFormatException("Unknown flag character '" + flag.charAt(i) + "' in flag '" + flag + "'"); + throw new SAMFormatException( + "Unknown flag character '" + flag.charAt(i) + "' in flag '" + flag + "'"); } } @@ -160,7 +188,7 @@ protected int parseWithoutValidation(final String flag) { }; /** Returns the string associated with this flag field. */ - abstract public String format(final int flag); + public abstract String format(final int flag); /** Parses the flag. Validates that the flag is of the correct type. */ public final int parse(final String flag) { @@ -175,7 +203,7 @@ public static int parseDefault(final String flag) { /** Performs the actual parsing based on the radix. No validation that the flag is of the correct radix * should be performed. */ - abstract protected int parseWithoutValidation(final String flag); + protected abstract int parseWithoutValidation(final String flag); /** Parses the flag. Performs optional validation that the flag is of the correct type. */ private int parse(final String flag, final boolean withValidation) { @@ -199,7 +227,8 @@ public static SamFlagField of(final String s) { private static void validate(final String flag, final SamFlagField expectedField) { final SamFlagField actualField = SamFlagField.of(flag); if (actualField != expectedField) { - throw new SAMFormatException(expectedField.name() + " sam flag must start with [1-9] but found '" + flag + "' (" + actualField.name() + ")"); + throw new SAMFormatException(expectedField.name() + " sam flag must start with [1-9] but found '" + flag + + "' (" + actualField.name() + ")"); } } -} \ No newline at end of file +} diff --git a/src/main/java/htsjdk/samtools/SamIndexes.java b/src/main/java/htsjdk/samtools/SamIndexes.java index 98b530c279..6317a40248 100644 --- a/src/main/java/htsjdk/samtools/SamIndexes.java +++ b/src/main/java/htsjdk/samtools/SamIndexes.java @@ -6,7 +6,6 @@ import htsjdk.samtools.util.FileExtensions; import htsjdk.samtools.util.IOUtil; import htsjdk.samtools.util.RuntimeIOException; - import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; @@ -22,7 +21,7 @@ public enum SamIndexes { BAI(FileExtensions.BAI_INDEX, "BAI\1".getBytes()), // CRAI is gzipped text, so it's magic is same as {@link java.util.zip.GZIPInputStream.GZIP_MAGIC} - CRAI(FileExtensions.CRAM_INDEX, new byte[]{(byte) 0x1f, (byte) 0x8b}), + CRAI(FileExtensions.CRAM_INDEX, new byte[] {(byte) 0x1f, (byte) 0x8b}), CSI(FileExtensions.CSI, "CSI\1".getBytes()); public final String fileNameSuffix; @@ -33,11 +32,13 @@ public enum SamIndexes { this.magic = magic; } - public static InputStream openIndexFileAsBaiOrNull(final File file, final SAMSequenceDictionary dictionary) throws IOException { + public static InputStream openIndexFileAsBaiOrNull(final File file, final SAMSequenceDictionary dictionary) + throws IOException { return openIndexUrlAsBaiOrNull(file.toURI().toURL(), dictionary); } - public static InputStream openIndexUrlAsBaiOrNull(final URL url, final SAMSequenceDictionary dictionary) throws IOException { + public static InputStream openIndexUrlAsBaiOrNull(final URL url, final SAMSequenceDictionary dictionary) + throws IOException { if (url.getFile().toLowerCase().endsWith(BAI.fileNameSuffix.toLowerCase())) { return url.openStream(); } @@ -51,7 +52,8 @@ public static InputStream openIndexUrlAsBaiOrNull(final URL url, final SAMSequen return null; } - public static InputStream asBaiStreamOrNull(final InputStream inputStream, final SAMSequenceDictionary dictionary) throws IOException { + public static InputStream asBaiStreamOrNull(final InputStream inputStream, final SAMSequenceDictionary dictionary) + throws IOException { final BufferedInputStream bis = new BufferedInputStream(inputStream); bis.mark(BAI.magic.length); if (doesStreamStartWith(bis, BAI.magic)) { @@ -80,7 +82,8 @@ public static InputStream asBaiStreamOrNull(final InputStream inputStream, final return null; } - public static SeekableStream asBaiSeekableStreamOrNull(final SeekableStream inputStream, final SAMSequenceDictionary dictionary) throws IOException { + public static SeekableStream asBaiSeekableStreamOrNull( + final SeekableStream inputStream, final SAMSequenceDictionary dictionary) throws IOException { final SeekableBufferedStream bis = new SeekableBufferedStream(inputStream); bis.seek(0); if (doesStreamStartWith(bis, BAI.magic)) { diff --git a/src/main/java/htsjdk/samtools/SamInputResource.java b/src/main/java/htsjdk/samtools/SamInputResource.java index 863351ddc9..df854681a8 100644 --- a/src/main/java/htsjdk/samtools/SamInputResource.java +++ b/src/main/java/htsjdk/samtools/SamInputResource.java @@ -32,7 +32,6 @@ import htsjdk.samtools.util.IOUtil; import htsjdk.samtools.util.Lazy; import htsjdk.samtools.util.RuntimeIOException; - import java.io.*; import java.net.MalformedURLException; import java.net.URI; @@ -118,15 +117,23 @@ public static SamInputResource of(final Path path, Function wrapper) { // See if this is an Htsget source first if (uri.getScheme().equalsIgnoreCase(HtsgetBAMFileReader.HTSGET_SCHEME)) { @@ -156,31 +164,30 @@ public static SamInputResource of(final URI uri, final Function lazySeekableStream = new Lazy<>(new Supplier() { @Override public SeekableStream get() { - try { return SeekableStreamFactory.getInstance().getStreamFor(urlResource); } - catch (final IOException ioe) { throw new RuntimeIOException(ioe); } + try { + return SeekableStreamFactory.getInstance().getStreamFor(urlResource); + } catch (final IOException ioe) { + throw new RuntimeIOException(ioe); + } } }); @@ -448,8 +463,7 @@ public File asFile() { public Path asPath() { try { return IOUtil.getPath(urlResource.toExternalForm()); - } catch (IOException | IllegalArgumentException | - FileSystemNotFoundException | SecurityException e) { + } catch (IOException | IllegalArgumentException | FileSystemNotFoundException | SecurityException e) { return null; } } @@ -595,7 +609,8 @@ public SRAAccession asSRAAccession() { } } -// TODO: replace this with an InputResource type taking HtsPath once this interface is available, see https://github.com/samtools/htsjdk/pull/1496 +// TODO: replace this with an InputResource type taking HtsPath once this interface is available, see +// https://github.com/samtools/htsjdk/pull/1496 class HtsgetInputResource extends InputResource { final URI uri; diff --git a/src/main/java/htsjdk/samtools/SamPairUtil.java b/src/main/java/htsjdk/samtools/SamPairUtil.java index 7f84804994..81cef3fe2f 100644 --- a/src/main/java/htsjdk/samtools/SamPairUtil.java +++ b/src/main/java/htsjdk/samtools/SamPairUtil.java @@ -26,7 +26,6 @@ import htsjdk.samtools.util.CoordMath; import htsjdk.samtools.util.PeekableIterator; - import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -52,15 +51,12 @@ public class SamPairUtil { * * PairOrientation only makes sense for a pair of reads that are both mapped to the same contig/chromosome */ - public static enum PairOrientation - { - FR, // ( 5' --F--> <--R-- 5' ) - aka. innie - RF, // ( <--R-- 5' 5' --F--> ) - aka. outie + public static enum PairOrientation { + FR, // ( 5' --F--> <--R-- 5' ) - aka. innie + RF, // ( <--R-- 5' 5' --F--> ) - aka. outie TANDEM // ( 5' --F--> 5' --F--> or ( <--R-- 5' <--R-- 5' ) - } - /** * Computes the pair orientation of the given SAMRecord. * @param record the record for which the pair orientation is requested @@ -82,29 +78,29 @@ public static enum PairOrientation * that need symmetric orientation on such pairs should ensure the MC tag * is set on at least the forward-strand record. */ - public static PairOrientation getPairOrientation(final SAMRecord record) - { + public static PairOrientation getPairOrientation(final SAMRecord record) { final boolean readIsOnReverseStrand = record.getReadNegativeStrandFlag(); - if(record.getReadUnmappedFlag() || !record.getReadPairedFlag() || record.getMateUnmappedFlag()) { - throw new IllegalArgumentException("Invalid SAMRecord: " + record.getReadName() + - ". This method only works for SAMRecords that are paired reads with both reads aligned."); + if (record.getReadUnmappedFlag() || !record.getReadPairedFlag() || record.getMateUnmappedFlag()) { + throw new IllegalArgumentException("Invalid SAMRecord: " + record.getReadName() + + ". This method only works for SAMRecords that are paired reads with both reads aligned."); } if (!record.getReferenceIndex().equals(record.getMateReferenceIndex())) { - throw new IllegalArgumentException("Invalid SAMRecord: " + record.getReadName() + - ". This method only works for SAMRecords that are paired reads with both reads aligned to the" + - " same reference. Found difference references:" + record.getReferenceName() + " and " + - record.getMateReferenceName() + "."); + throw new IllegalArgumentException("Invalid SAMRecord: " + record.getReadName() + + ". This method only works for SAMRecords that are paired reads with both reads aligned to the" + + " same reference. Found difference references:" + + record.getReferenceName() + " and " + record.getMateReferenceName() + + "."); } - if(readIsOnReverseStrand == record.getMateNegativeStrandFlag() ) { + if (readIsOnReverseStrand == record.getMateNegativeStrandFlag()) { return PairOrientation.TANDEM; } - final long positiveStrandFivePrimePos = ( readIsOnReverseStrand - ? record.getMateAlignmentStart() //mate's 5' position ( x---> ) - : record.getAlignmentStart() ); //read's 5' position ( x---> ) + final long positiveStrandFivePrimePos = (readIsOnReverseStrand + ? record.getMateAlignmentStart() // mate's 5' position ( x---> ) + : record.getAlignmentStart()); // read's 5' position ( x---> ) final long negativeStrandFivePrimePos; if (readIsOnReverseStrand) { @@ -119,7 +115,8 @@ public static PairOrientation getPairOrientation(final SAMRecord record) // SAMUtils.getMateAlignmentEnd. final Cigar mateCigar = SAMUtils.getMateCigar(record); if (mateCigar != null) { - negativeStrandFivePrimePos = CoordMath.getEnd(record.getMateAlignmentStart(), mateCigar.getReferenceLength()); + negativeStrandFivePrimePos = + CoordMath.getEnd(record.getMateAlignmentStart(), mateCigar.getReferenceLength()); } else { // Fallback: derive the mate's 5' position from TLEN under // htsjdk's convention (see computeInsertSize), where TLEN @@ -131,20 +128,17 @@ public static PairOrientation getPairOrientation(final SAMRecord record) // convention (e.g., bwa on a dovetail pair); callers that // need symmetric results in that situation must provide the // MC tag. - negativeStrandFivePrimePos = CoordMath.getEnd(record.getAlignmentStart(), record.getInferredInsertSize()); + negativeStrandFivePrimePos = + CoordMath.getEnd(record.getAlignmentStart(), record.getInferredInsertSize()); } } - return ( positiveStrandFivePrimePos <= negativeStrandFivePrimePos - ? PairOrientation.FR - : PairOrientation.RF ); + return (positiveStrandFivePrimePos <= negativeStrandFivePrimePos ? PairOrientation.FR : PairOrientation.RF); } - - // TODO: KT and TF say this is more complicated than what I have here - public static boolean isProperPair(final SAMRecord firstEnd, final SAMRecord secondEnd, - final List expectedOrientations) { + public static boolean isProperPair( + final SAMRecord firstEnd, final SAMRecord secondEnd, final List expectedOrientations) { // are both records mapped? if (firstEnd.getReadUnmappedFlag() || secondEnd.getReadUnmappedFlag()) { return false; @@ -167,27 +161,20 @@ public static void assertMate(final SAMRecord firstOfPair, final SAMRecord secon // Validate paired reads arrive as first of pair, then second of pair if (firstOfPair == null) { - throw new SAMException( - "First record does not exist - cannot perform mate assertion!"); + throw new SAMException("First record does not exist - cannot perform mate assertion!"); } else if (secondOfPair == null) { - throw new SAMException( - firstOfPair.toString() + " is missing its mate"); + throw new SAMException(firstOfPair.toString() + " is missing its mate"); } else if (!firstOfPair.getReadPairedFlag()) { - throw new SAMException( - "First record is not marked as paired: " + firstOfPair.toString()); + throw new SAMException("First record is not marked as paired: " + firstOfPair.toString()); } else if (!secondOfPair.getReadPairedFlag()) { - throw new SAMException( - "Second record is not marked as paired: " + secondOfPair.toString()); + throw new SAMException("Second record is not marked as paired: " + secondOfPair.toString()); } else if (!firstOfPair.getFirstOfPairFlag()) { - throw new SAMException( - "First record is not marked as first of pair: " + firstOfPair.toString()); + throw new SAMException("First record is not marked as first of pair: " + firstOfPair.toString()); } else if (!secondOfPair.getSecondOfPairFlag()) { - throw new SAMException( - "Second record is not marked as second of pair: " + secondOfPair.toString()); + throw new SAMException("Second record is not marked as second of pair: " + secondOfPair.toString()); } else if (!firstOfPair.getReadName().equals(secondOfPair.getReadName())) { - throw new SAMException( - "First [" + firstOfPair.getReadName() + "] and Second [" + - secondOfPair.getReadName() + "] readnames do not match!"); + throw new SAMException("First [" + firstOfPair.getReadName() + "] and Second [" + secondOfPair.getReadName() + + "] readnames do not match!"); } } @@ -200,15 +187,14 @@ public static void assertMate(final SAMRecord firstOfPair, final SAMRecord secon * @return the secondOfPair SAMRecord * @throws SAMException when the secondOfPair mate cannot be obtained due to assertion failures */ - public static SAMRecord obtainAssertedMate(final Iterator samRecordIterator, - final SAMRecord firstOfPair) { + public static SAMRecord obtainAssertedMate( + final Iterator samRecordIterator, final SAMRecord firstOfPair) { if (samRecordIterator.hasNext()) { final SAMRecord secondOfPair = samRecordIterator.next(); assertMate(firstOfPair, secondOfPair); return secondOfPair; } else { - throw new SAMException( - "Second record does not exist: " + firstOfPair.getReadName()); + throw new SAMException("Second record does not exist: " + firstOfPair.getReadName()); } } @@ -226,8 +212,10 @@ public static int computeInsertSize(final SAMRecord firstEnd, final SAMRecord se return 0; } - final int firstEnd5PrimePosition = firstEnd.getReadNegativeStrandFlag()? firstEnd.getAlignmentEnd(): firstEnd.getAlignmentStart(); - final int secondEnd5PrimePosition = secondEnd.getReadNegativeStrandFlag()? secondEnd.getAlignmentEnd(): secondEnd.getAlignmentStart(); + final int firstEnd5PrimePosition = + firstEnd.getReadNegativeStrandFlag() ? firstEnd.getAlignmentEnd() : firstEnd.getAlignmentStart(); + final int secondEnd5PrimePosition = + secondEnd.getReadNegativeStrandFlag() ? secondEnd.getAlignmentEnd() : secondEnd.getAlignmentStart(); final int adjustment = (secondEnd5PrimePosition >= firstEnd5PrimePosition) ? +1 : -1; return secondEnd5PrimePosition - firstEnd5PrimePosition + adjustment; @@ -266,8 +254,7 @@ public static void setMateInfo(final SAMRecord rec1, final SAMRecord rec2, final if (setMateCigar) { rec1.setAttribute(SAMTag.MC, rec2.getCigarString()); rec2.setAttribute(SAMTag.MC, rec1.getCigarString()); - } - else { + } else { rec1.setAttribute(SAMTag.MC, null); rec2.setAttribute(SAMTag.MC, null); } @@ -296,7 +283,7 @@ else if (rec1.getReadUnmappedFlag() && rec2.getReadUnmappedFlag()) { } // And if only one is mapped copy it's coordinate information to the mate else { - final SAMRecord mapped = rec1.getReadUnmappedFlag() ? rec2 : rec1; + final SAMRecord mapped = rec1.getReadUnmappedFlag() ? rec2 : rec1; final SAMRecord unmapped = rec1.getReadUnmappedFlag() ? rec1 : rec2; unmapped.setReferenceIndex(mapped.getReferenceIndex()); unmapped.setAlignmentStart(mapped.getAlignmentStart()); @@ -334,7 +321,8 @@ else if (rec1.getReadUnmappedFlag() && rec2.getReadUnmappedFlag()) { * @deprecated use {@link #setMateInfo(SAMRecord, SAMRecord, boolean)} instead */ @Deprecated - public static void setMateInfo(final SAMRecord rec1, final SAMRecord rec2, final SAMFileHeader header, final boolean setMateCigar) { + public static void setMateInfo( + final SAMRecord rec1, final SAMRecord rec2, final SAMFileHeader header, final boolean setMateCigar) { setMateInfo(rec1, rec2, setMateCigar); } @@ -357,9 +345,8 @@ public static void setMateInfo(final SAMRecord rec1, final SAMRecord rec2, final * @param matePrimary the primary alignment of the the mate pair of the supplemental * @param setMateCigar true if we are to update/create the Mate CIGAR (MC) optional tag, false if we are to clear any mate cigar tag that is present. */ - public static void setMateInformationOnSupplementalAlignment( final SAMRecord supplemental, - final SAMRecord matePrimary, - final boolean setMateCigar) { + public static void setMateInformationOnSupplementalAlignment( + final SAMRecord supplemental, final SAMRecord matePrimary, final boolean setMateCigar) { supplemental.setMateReferenceIndex(matePrimary.getReferenceIndex()); supplemental.setMateAlignmentStart(matePrimary.getAlignmentStart()); supplemental.setMateNegativeStrandFlag(matePrimary.getReadNegativeStrandFlag()); @@ -367,8 +354,7 @@ public static void setMateInformationOnSupplementalAlignment( final SAMRecord su supplemental.setInferredInsertSize(-matePrimary.getInferredInsertSize()); if (setMateCigar && !matePrimary.getReadUnmappedFlag()) { supplemental.setAttribute(SAMTag.MC, matePrimary.getCigarString()); - } - else { + } else { supplemental.setAttribute(SAMTag.MC, null); } supplemental.setAttribute(SAMTag.MQ, matePrimary.getMappingQuality()); @@ -380,8 +366,8 @@ public static void setMateInformationOnSupplementalAlignment( final SAMRecord su * @param supplemental a supplemental alignment for the mate pair of the primary supplied * @param matePrimary the primary alignment of the the mate pair of the supplemental */ - public static void setMateInformationOnSupplementalAlignment( final SAMRecord supplemental, - final SAMRecord matePrimary) { + public static void setMateInformationOnSupplementalAlignment( + final SAMRecord supplemental, final SAMRecord matePrimary) { setMateInformationOnSupplementalAlignment(supplemental, matePrimary, false); } @@ -390,9 +376,11 @@ public static void setMateInformationOnSupplementalAlignment( final SAMRecord su * @deprecated use {@link #setProperPairAndMateInfo(SAMRecord, SAMRecord, List)} instead */ @Deprecated - public static void setProperPairAndMateInfo(final SAMRecord rec1, final SAMRecord rec2, - final SAMFileHeader header, - final List expectedOrientations) { + public static void setProperPairAndMateInfo( + final SAMRecord rec1, + final SAMRecord rec2, + final SAMFileHeader header, + final List expectedOrientations) { setProperPairAndMateInfo(rec1, rec2, expectedOrientations); } @@ -401,33 +389,38 @@ public static void setProperPairAndMateInfo(final SAMRecord rec1, final SAMRecor * @deprecated use {@link #setProperPairAndMateInfo(SAMRecord, SAMRecord, List, boolean)} */ @Deprecated - public static void setProperPairAndMateInfo(final SAMRecord rec1, final SAMRecord rec2, - final SAMFileHeader header, - final List expectedOrientations, - final boolean addMateCigar) { + public static void setProperPairAndMateInfo( + final SAMRecord rec1, + final SAMRecord rec2, + final SAMFileHeader header, + final List expectedOrientations, + final boolean addMateCigar) { setProperPairAndMateInfo(rec1, rec2, expectedOrientations, addMateCigar); } /** * This method will clear any mate cigar already present. */ - public static void setProperPairAndMateInfo(final SAMRecord rec1, final SAMRecord rec2, - final List expectedOrientations) { + public static void setProperPairAndMateInfo( + final SAMRecord rec1, final SAMRecord rec2, final List expectedOrientations) { setProperPairAndMateInfo(rec1, rec2, expectedOrientations, false); } /** * @param addMateCigar true if we are to update/create the Mate CIGAR (MC) optional tag, false if we are to clear any mate cigar tag that is present. */ - public static void setProperPairAndMateInfo(final SAMRecord rec1, final SAMRecord rec2, - final List expectedOrientations, - final boolean addMateCigar) { + public static void setProperPairAndMateInfo( + final SAMRecord rec1, + final SAMRecord rec2, + final List expectedOrientations, + final boolean addMateCigar) { setMateInfo(rec1, rec2, addMateCigar); setProperPairFlags(rec1, rec2, expectedOrientations); } - public static void setProperPairFlags(final SAMRecord rec1, final SAMRecord rec2, final List expectedOrientations) { - final boolean properPair = (!rec1.getReadUnmappedFlag() && !rec2.getReadUnmappedFlag()) + public static void setProperPairFlags( + final SAMRecord rec1, final SAMRecord rec2, final List expectedOrientations) { + final boolean properPair = (!rec1.getReadUnmappedFlag() && !rec2.getReadUnmappedFlag()) ? isProperPair(rec1, rec2, expectedOrientations) : false; rec1.setProperPairFlag(properPair); @@ -466,7 +459,8 @@ public SetMateInfoIterator(final Iterator iterator, final boolean set * @param setMateCigar true if we are to update/create the Mate CIGAR (MC) optional tag, false if we are to clear any mate cigar tag that is present. * @param ignoreMissingMates set this to true if we are to ignore missing mates, otherwise an exception will be thrown when a missing mate is encountered */ - public SetMateInfoIterator(final Iterator iterator, final boolean setMateCigar, final boolean ignoreMissingMates) { + public SetMateInfoIterator( + final Iterator iterator, final boolean setMateCigar, final boolean ignoreMissingMates) { super(iterator); this.setMateCigar = setMateCigar; this.ignoreMissingMates = ignoreMissingMates; @@ -475,7 +469,9 @@ public SetMateInfoIterator(final Iterator iterator, final boolean set /** * @return the current number of mate cigars added. This could be more than the number of records returned. */ - public long getNumMateCigarsAdded() { return this.numMateCigarsAdded; } + public long getNumMateCigarsAdded() { + return this.numMateCigarsAdded; + } @Override public boolean hasNext() { @@ -491,9 +487,9 @@ private void advance() { if (!records.isEmpty()) return; /* - Get all records with the same name, and then identify the canonical first and second end to which we - want to set mate info. - */ + Get all records with the same name, and then identify the canonical first and second end to which we + want to set mate info. + */ SAMRecord firstPrimaryRecord = null, secondPrimaryRecord = null; final SAMRecord first = super.peek(); // peek so we consider it in the following loop boolean containsSupplementalRecord = false; @@ -504,12 +500,16 @@ private void advance() { if (!record.isSecondaryOrSupplementary()) { if (record.getFirstOfPairFlag()) { if (null != firstPrimaryRecord) { - throw new SAMException("Found two records that are paired, not supplementary, and first of the pair: " + record.getReadName()); + throw new SAMException( + "Found two records that are paired, not supplementary, and first of the pair: " + + record.getReadName()); } firstPrimaryRecord = record; } else if (record.getSecondOfPairFlag()) { if (null != secondPrimaryRecord) { - throw new SAMException("Found two records that are paired, not supplementary, and second of the pair: " + record.getReadName()); + throw new SAMException( + "Found two records that are paired, not supplementary, and second of the pair: " + + record.getReadName()); } secondPrimaryRecord = record; } @@ -520,7 +520,6 @@ private void advance() { } // TODO: should we check that we do not have a mix of paired and fragment reads? - // we must find both records to update the mate info if (null != firstPrimaryRecord && null != secondPrimaryRecord) { // Update mate info @@ -532,9 +531,11 @@ private void advance() { for (final SAMRecord record : records) { if (record.getReadPairedFlag() && record.getSupplementaryAlignmentFlag()) { if (record.getFirstOfPairFlag()) { - SamPairUtil.setMateInformationOnSupplementalAlignment(record, secondPrimaryRecord, this.setMateCigar); + SamPairUtil.setMateInformationOnSupplementalAlignment( + record, secondPrimaryRecord, this.setMateCigar); } else { - SamPairUtil.setMateInformationOnSupplementalAlignment(record, firstPrimaryRecord, this.setMateCigar); + SamPairUtil.setMateInformationOnSupplementalAlignment( + record, firstPrimaryRecord, this.setMateCigar); } this.numMateCigarsAdded++; } diff --git a/src/main/java/htsjdk/samtools/SamReader.java b/src/main/java/htsjdk/samtools/SamReader.java index 01a46b75a6..d288db464c 100644 --- a/src/main/java/htsjdk/samtools/SamReader.java +++ b/src/main/java/htsjdk/samtools/SamReader.java @@ -25,9 +25,7 @@ package htsjdk.samtools; import htsjdk.samtools.util.CloseableIterator; - import java.io.Closeable; -import java.text.MessageFormat; /** * Describes functionality for objects that produce {@link SAMRecord}s and associated information. @@ -77,7 +75,9 @@ public String indexExtension() { @Override public String toString() { - return String.format("TypeImpl{name='%s', fileExtension='%s', indexExtension='%s'}", name, fileExtension, indexExtension); + return String.format( + "TypeImpl{name='%s', fileExtension='%s', indexExtension='%s'}", + name, fileExtension, indexExtension); } } @@ -135,7 +135,6 @@ public interface Indexing { * @return Unbounded pointer to the first record, in chunk format. */ public SAMFileSpan getFilePointerSpanningReads(); - } public SAMFileHeader getFileHeader(); @@ -153,7 +152,7 @@ public interface Indexing { /** * @return true if this source can be queried by interval, regardless of whether it has an index */ - default public boolean isQueryable() { + public default boolean isQueryable() { return this.hasIndex(); } @@ -306,7 +305,6 @@ default public boolean isQueryable() { */ public SAMRecordIterator queryContained(final QueryInterval[] intervals); - public SAMRecordIterator queryUnmapped(); /** @@ -454,7 +452,8 @@ public SAMRecord queryMate(final SAMRecord rec) { final SAMRecord next = it.next(); if (!next.getReadPairedFlag()) { if (rec.getReadName().equals(next.getReadName())) { - throw new SAMFormatException("Paired and unpaired reads with same name: " + rec.getReadName()); + throw new SAMFormatException( + "Paired and unpaired reads with same name: " + rec.getReadName()); } continue; } @@ -465,8 +464,8 @@ public SAMRecord queryMate(final SAMRecord rec) { } if (rec.getReadName().equals(next.getReadName())) { if (mateRec != null) { - throw new SAMFormatException("Multiple SAMRecord with read name " + rec.getReadName() + - " for " + (firstOfPair ? "second" : "first") + " end."); + throw new SAMFormatException("Multiple SAMRecord with read name " + rec.getReadName() + + " for " + (firstOfPair ? "second" : "first") + " end."); } mateRec = next; } @@ -552,7 +551,9 @@ public SAMRecordIterator query(final QueryInterval[] intervals, final boolean co @Override public SAMRecordIterator query(final String sequence, final int start, final int end, final boolean contained) { - return query(new QueryInterval[]{new QueryInterval(getFileHeader().getSequenceIndex(sequence), start, end)}, contained); + return query( + new QueryInterval[] {new QueryInterval(getFileHeader().getSequenceIndex(sequence), start, end)}, + contained); } @Override @@ -564,7 +565,6 @@ public SAMRecordIterator queryUnmapped() { public SAMRecordIterator queryAlignmentStart(final String sequence, final int start) { return AssertingIterator.of(p.queryAlignmentStart(sequence, start)); } - } static class AssertingIterator implements SAMRecordIterator { @@ -594,21 +594,26 @@ public SAMRecord next() { if (!checker.isSorted(result)) { throw new IllegalStateException(String.format( "Record %s should come after %s when sorting with %s ordering.", - previous.getSAMString(), - result.getSAMString(), checker.getSortOrder())); + previous.getSAMString(), result.getSAMString(), checker.getSortOrder())); } } return result; } @Override - public void close() { wrappedIterator.close(); } + public void close() { + wrappedIterator.close(); + } @Override - public boolean hasNext() { return wrappedIterator.hasNext(); } + public boolean hasNext() { + return wrappedIterator.hasNext(); + } @Override - public void remove() { wrappedIterator.remove(); } + public void remove() { + wrappedIterator.remove(); + } } /** diff --git a/src/main/java/htsjdk/samtools/SamReaderFactory.java b/src/main/java/htsjdk/samtools/SamReaderFactory.java index e93a2cd392..ed2b3fb19b 100644 --- a/src/main/java/htsjdk/samtools/SamReaderFactory.java +++ b/src/main/java/htsjdk/samtools/SamReaderFactory.java @@ -30,7 +30,6 @@ import htsjdk.samtools.sra.SRAAccession; import htsjdk.samtools.util.*; import htsjdk.samtools.util.zip.InflaterFactory; - import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -79,7 +78,7 @@ public abstract class SamReaderFactory { private static ValidationStringency defaultValidationStringency = ValidationStringency.DEFAULT_STRINGENCY; - abstract public SamReader open(final File file); + public abstract SamReader open(final File file); /** * Open the specified path (without using any wrappers). @@ -97,78 +96,83 @@ public SamReader open(final Path path) { * @param dataWrapper the wrapper for the data (or null for none) * @param indexWrapper the wrapper for the index (or null for none) */ - public SamReader open(final Path path, + public SamReader open( + final Path path, Function dataWrapper, Function indexWrapper) { - final SamInputResource r = dataWrapper == null - ? SamInputResource.of(path) - : SamInputResource.of(path, dataWrapper); + final SamInputResource r = + dataWrapper == null ? SamInputResource.of(path) : SamInputResource.of(path, dataWrapper); final Path indexMaybe = SamFiles.findIndex(path); if (indexMaybe != null) r.index(indexMaybe, indexWrapper); return open(r); } - abstract public SamReader open(final SamInputResource resource); + public abstract SamReader open(final SamInputResource resource); - abstract public ValidationStringency validationStringency(); + public abstract ValidationStringency validationStringency(); - abstract public CRAMReferenceSource referenceSource(); + public abstract CRAMReferenceSource referenceSource(); /** Set this factory's {@link htsjdk.samtools.SAMRecordFactory} to the provided one, then returns itself. */ - abstract public SamReaderFactory samRecordFactory(final SAMRecordFactory samRecordFactory); + public abstract SamReaderFactory samRecordFactory(final SAMRecordFactory samRecordFactory); /** * Set this factory's {@link htsjdk.samtools.util.zip.InflaterFactory} to the provided one, then returns itself. * Note: The inflaterFactory provided here is only used for BAM decompression implemented with {@link BAMFileReader}, * it is not used for CRAM or other formats like a gzipped SAM file. */ - abstract public SamReaderFactory inflaterFactory(final InflaterFactory inflaterFactory); + public abstract SamReaderFactory inflaterFactory(final InflaterFactory inflaterFactory); /** Enables the provided {@link Option}s, then returns itself. */ - abstract public SamReaderFactory enable(final Option... options); + public abstract SamReaderFactory enable(final Option... options); /** Disables the provided {@link Option}s, then returns itself. */ - abstract public SamReaderFactory disable(final Option... options); + public abstract SamReaderFactory disable(final Option... options); /** Sets a specific Option to a boolean value. * */ - abstract public SamReaderFactory setOption(final Option option, boolean value); + public abstract SamReaderFactory setOption(final Option option, boolean value); /** Sets the specified reference sequence * */ - abstract public SamReaderFactory referenceSequence(File referenceSequence); + public abstract SamReaderFactory referenceSequence(File referenceSequence); /** Sets the specified reference sequence. */ - abstract public SamReaderFactory referenceSequence(Path referenceSequence); + public abstract SamReaderFactory referenceSequence(Path referenceSequence); /** Sets the specified reference sequence * */ - abstract public SamReaderFactory referenceSource(CRAMReferenceSource referenceSequence); + public abstract SamReaderFactory referenceSource(CRAMReferenceSource referenceSequence); /** Utility method to open the file get the header and close the file */ - abstract public SAMFileHeader getFileHeader(File samFile); + public abstract SAMFileHeader getFileHeader(File samFile); /** Utility method to open the file get the header and close the file */ - abstract public SAMFileHeader getFileHeader(Path samFile); + public abstract SAMFileHeader getFileHeader(Path samFile); /** Reapplies any changed options to the reader * */ - abstract public void reapplyOptions(SamReader reader); + public abstract void reapplyOptions(SamReader reader); /** Set this factory's {@link ValidationStringency} to the provided one, then returns itself. */ - abstract public SamReaderFactory validationStringency(final ValidationStringency validationStringency); + public abstract SamReaderFactory validationStringency(final ValidationStringency validationStringency); /** Set whether readers created by this factory will use asynchronous IO. * If this methods is not called, this flag will default to the value of {@link Defaults#USE_ASYNC_IO_READ_FOR_SAMTOOLS}. * Note that this option may not be applicable to all readers returned from this factory. * Returns the factory itself. */ - abstract public SamReaderFactory setUseAsyncIo(final boolean asynchronousIO); + public abstract SamReaderFactory setUseAsyncIo(final boolean asynchronousIO); - private static SamReaderFactoryImpl DEFAULT = - new SamReaderFactoryImpl(Option.DEFAULTS, defaultValidationStringency, - DefaultSAMRecordFactory.getInstance(), BlockGunzipper.getDefaultInflaterFactory()); + private static SamReaderFactoryImpl DEFAULT = new SamReaderFactoryImpl( + Option.DEFAULTS, + defaultValidationStringency, + DefaultSAMRecordFactory.getInstance(), + BlockGunzipper.getDefaultInflaterFactory()); public static void setDefaultValidationStringency(final ValidationStringency defaultValidationStringency) { SamReaderFactory.defaultValidationStringency = defaultValidationStringency; // The default may have changed, so reset the default SamReader - DEFAULT = new SamReaderFactoryImpl(Option.DEFAULTS, defaultValidationStringency, - DefaultSAMRecordFactory.getInstance(), BlockGunzipper.getDefaultInflaterFactory()); + DEFAULT = new SamReaderFactoryImpl( + Option.DEFAULTS, + defaultValidationStringency, + DefaultSAMRecordFactory.getInstance(), + BlockGunzipper.getDefaultInflaterFactory()); } /** Creates a copy of the default {@link SamReaderFactory}. */ @@ -181,12 +185,15 @@ public static SamReaderFactory makeDefault() { * no path wrapper, and {@link htsjdk.samtools.DefaultSAMRecordFactory}. */ public static SamReaderFactory make() { - return new SamReaderFactoryImpl(EnumSet.noneOf(Option.class), ValidationStringency.DEFAULT_STRINGENCY, - DefaultSAMRecordFactory.getInstance(), BlockGunzipper.getDefaultInflaterFactory()); + return new SamReaderFactoryImpl( + EnumSet.noneOf(Option.class), + ValidationStringency.DEFAULT_STRINGENCY, + DefaultSAMRecordFactory.getInstance(), + BlockGunzipper.getDefaultInflaterFactory()); } private static class SamReaderFactoryImpl extends SamReaderFactory { - private final static Log LOG = Log.getInstance(SamReaderFactory.class); + private static final Log LOG = Log.getInstance(SamReaderFactory.class); private final EnumSet