/* * Copyright (c) 2012 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.variant.variantcontext.writer; import htsjdk.samtools.Defaults; import htsjdk.samtools.SAMSequenceDictionary; import htsjdk.samtools.util.BlockCompressedOutputStream; import htsjdk.samtools.util.IOUtil; import htsjdk.tribble.AbstractFeatureReader; import htsjdk.tribble.index.IndexCreator; import htsjdk.tribble.index.tabix.TabixFormat; import htsjdk.tribble.index.tabix.TabixIndexCreator; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.OutputStream; import java.util.EnumSet; /** * Factory methods to create VariantContext writers * * @author depristo * @since 5/12 * * @deprecated Replaced by {@link VariantContextWriterBuilder} */ @Deprecated public class VariantContextWriterFactory { public static final EnumSet<Options> DEFAULT_OPTIONS = EnumSet.of(Options.INDEX_ON_THE_FLY); public static final EnumSet<Options> NO_OPTIONS = EnumSet.noneOf(Options.class); static { if (Defaults.USE_ASYNC_IO) { DEFAULT_OPTIONS.add(Options.USE_ASYNC_IO); } } private VariantContextWriterFactory() {} public static VariantContextWriter create(final File location, final SAMSequenceDictionary refDict) { return create(location, openOutputStream(location), refDict, DEFAULT_OPTIONS); } public static VariantContextWriter create(final File location, final SAMSequenceDictionary refDict, final EnumSet<Options> options) { return create(location, openOutputStream(location), refDict, options); } /** * @param output If buffered writing is desired, caller must provide some kind of buffered OutputStream. */ public static VariantContextWriter create(final File location, final OutputStream output, final SAMSequenceDictionary refDict) { return create(location, output, refDict, DEFAULT_OPTIONS); } /** * @param output If buffered writing is desired, caller must provide some kind of buffered OutputStream. */ public static VariantContextWriter create(final OutputStream output, final SAMSequenceDictionary refDict, final EnumSet<Options> options) { return create(null, output, refDict, options); } /** * @param location Note that this parameter is used to producing intelligent log messages, and for naming the index, * but does not control where the file is written * @param output This is where the BCF is actually written. If buffered writing is desired, caller must provide * some kind of buffered OutputStream. */ public static VariantContextWriter createBcf2(final File location, final OutputStream output, final SAMSequenceDictionary refDict, final EnumSet<Options> options) { return maybeWrapWithAsyncWriter(new BCF2Writer(location, output, refDict, options.contains(Options.INDEX_ON_THE_FLY), options.contains(Options.DO_NOT_WRITE_GENOTYPES)), options); } /** * @param location Note that this parameter is used to producing intelligent log messages, and for naming the index, * but does not control where the file is written * @param output This is where the BCF is actually written. If buffered writing is desired, caller must provide * some kind of buffered OutputStream. */ public static VariantContextWriter createBcf2(final File location, final OutputStream output, final SAMSequenceDictionary refDict, final IndexCreator indexCreator, final EnumSet<Options> options) { return maybeWrapWithAsyncWriter(new BCF2Writer(location, output, refDict, indexCreator, options.contains(Options.INDEX_ON_THE_FLY), options.contains(Options.DO_NOT_WRITE_GENOTYPES)), options); } /** * @param location Note that this parameter is used to producing intelligent log messages, and for naming the index, * but does not control where the file is written * @param output This is where the VCF is actually written. If buffered writing is desired, caller must provide * some kind of buffered OutputStream. */ public static VariantContextWriter createVcf(final File location, final OutputStream output, final SAMSequenceDictionary refDict, final EnumSet<Options> options) { return maybeWrapWithAsyncWriter(new VCFWriter(location, output, refDict, options.contains(Options.INDEX_ON_THE_FLY), options.contains(Options.DO_NOT_WRITE_GENOTYPES), options.contains(Options.ALLOW_MISSING_FIELDS_IN_HEADER), options.contains(Options.WRITE_FULL_FORMAT_FIELD)), options); } /** * @param location Note that this parameter is used to producing intelligent log messages, and for naming the index, * but does not control where the file is written * @param output This is where the VCF is actually written. If buffered writing is desired, caller must provide * some kind of buffered OutputStream. */ public static VariantContextWriter createVcf(final File location, final OutputStream output, final SAMSequenceDictionary refDict, final IndexCreator indexCreator, final EnumSet<Options> options) { return maybeWrapWithAsyncWriter(new VCFWriter(location, output, refDict, indexCreator, options.contains(Options.INDEX_ON_THE_FLY), options.contains(Options.DO_NOT_WRITE_GENOTYPES), options.contains(Options.ALLOW_MISSING_FIELDS_IN_HEADER), options.contains(Options.WRITE_FULL_FORMAT_FIELD)), options); } /** * @param location Note that this parameter is used to producing intelligent log messages, * but does not control where the file is written * @param output This is where the VCF is actually written. If buffered writing is desired, caller must provide * some kind of buffered OutputStream. */ public static VariantContextWriter createBlockCompressedVcf(final File location, final OutputStream output, final SAMSequenceDictionary refDict, final EnumSet<Options> options) { final TabixIndexCreator indexCreator; if (options.contains(Options.INDEX_ON_THE_FLY)) { indexCreator = new TabixIndexCreator(refDict, TabixFormat.VCF); } else { indexCreator = null; } return maybeWrapWithAsyncWriter(new VCFWriter(location, BlockCompressedOutputStream.maybeBgzfWrapOutputStream(location, output), refDict, indexCreator, options.contains(Options.INDEX_ON_THE_FLY), options.contains(Options.DO_NOT_WRITE_GENOTYPES), options.contains(Options.ALLOW_MISSING_FIELDS_IN_HEADER), options.contains(Options.WRITE_FULL_FORMAT_FIELD)), options); } /** * @param location Note that this parameter is used to producing intelligent log messages, * but does not control where the file is written * @param output This is where the VCF is actually written. If buffered writing is desired, caller must provide * some kind of buffered OutputStream. */ public static VariantContextWriter createBlockCompressedVcf(final File location, final OutputStream output, final SAMSequenceDictionary refDict, final IndexCreator indexCreator, final EnumSet<Options> options) { return maybeWrapWithAsyncWriter(new VCFWriter(location, BlockCompressedOutputStream.maybeBgzfWrapOutputStream(location, output), refDict, indexCreator, options.contains(Options.INDEX_ON_THE_FLY), options.contains(Options.DO_NOT_WRITE_GENOTYPES), options.contains(Options.ALLOW_MISSING_FIELDS_IN_HEADER), options.contains(Options.WRITE_FULL_FORMAT_FIELD)), options); } public static VariantContextWriter create(final File location, final OutputStream output, final SAMSequenceDictionary refDict, final EnumSet<Options> options) { if (isBCFOutput(location, options)) { return createBcf2(location, output, refDict, options); } else if (isCompressedVcf(location)) { return createBlockCompressedVcf(location, output, refDict, options); } else { return createVcf(location, output, refDict, options); } } /** * @param output If buffered writing is desired, caller must provide some kind of buffered OutputStream. */ public static VariantContextWriter create(final File location, final OutputStream output, final SAMSequenceDictionary refDict, final IndexCreator indexCreator, final EnumSet<Options> options) { if (isBCFOutput(location, options)) { return createBcf2(location, output, refDict, indexCreator, options); } else if (isCompressedVcf(location)) { return createBlockCompressedVcf(location, output, refDict, indexCreator, options); } else { return createVcf(location, output, refDict, indexCreator, options); } } private static VariantContextWriter maybeWrapWithAsyncWriter(final VariantContextWriter writer, final EnumSet<Options> options) { if (options.contains(Options.USE_ASYNC_IO)) { return new AsyncVariantContextWriter(writer, AsyncVariantContextWriter.DEFAULT_QUEUE_SIZE); } else return writer; } /** * Should we output a BCF file based solely on the name of the file at location? * * @param location * @return */ public static boolean isBCFOutput(final File location) { return isBCFOutput(location, EnumSet.noneOf(Options.class)); } public static boolean isBCFOutput(final File location, final EnumSet<Options> options) { return options.contains(Options.FORCE_BCF) || (location != null && location.getName().contains(".bcf")); } public static boolean isCompressedVcf(final File location) { if (location == null) return false; return AbstractFeatureReader.hasBlockCompressedExtension(location); } public static VariantContextWriter sortOnTheFly(final VariantContextWriter innerWriter, final int maxCachingStartDistance) { return sortOnTheFly(innerWriter, maxCachingStartDistance, false); } public static VariantContextWriter sortOnTheFly(final VariantContextWriter innerWriter, final int maxCachingStartDistance, final boolean takeOwnershipOfInner) { return new SortingVariantContextWriter(innerWriter, maxCachingStartDistance, takeOwnershipOfInner); } /** * Returns a output stream writing to location, or throws an exception if this fails * @param location * @return */ protected static OutputStream openOutputStream(final File location) { try { return IOUtil.maybeBufferOutputStream(new FileOutputStream(location)); } catch (final FileNotFoundException e) { throw new RuntimeException(location + ": Unable to create VCF writer", e); } } }