/* * Copyright (c) 2007-2010 by The Broad Institute, Inc. and the Massachusetts Institute of Technology. * All Rights Reserved. * * This software is licensed under the terms of the GNU Lesser General Public License (LGPL), Version 2.1 which * is available at http://www.opensource.org/licenses/lgpl-2.1.php. * * THE SOFTWARE IS PROVIDED "AS IS." THE BROAD AND MIT MAKE NO REPRESENTATIONS OR WARRANTIES OF * ANY KIND CONCERNING THE SOFTWARE, EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT * OR OTHER DEFECTS, WHETHER OR NOT DISCOVERABLE. IN NO EVENT SHALL THE BROAD OR MIT, OR THEIR * RESPECTIVE TRUSTEES, DIRECTORS, OFFICERS, EMPLOYEES, AND AFFILIATES BE LIABLE FOR ANY DAMAGES OF * ANY KIND, INCLUDING, WITHOUT LIMITATION, INCIDENTAL OR CONSEQUENTIAL DAMAGES, ECONOMIC * DAMAGES OR INJURY TO PROPERTY AND LOST PROFITS, REGARDLESS OF WHETHER THE BROAD OR MIT SHALL * BE ADVISED, SHALL HAVE OTHER REASON TO KNOW, OR IN FACT SHALL KNOW OF THE POSSIBILITY OF THE * FOREGOING. */ package htsjdk.tribble; import htsjdk.tribble.index.Index; import htsjdk.tribble.util.ParsingUtils; import htsjdk.tribble.util.TabixUtils; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.Set; /** * jrobinso * <p/> * the feature reader class, which uses indices and codecs to read in Tribble file formats. */ public abstract class AbstractFeatureReader<T extends Feature, SOURCE> implements FeatureReader<T> { // the logging destination for this source //private final static Logger log = Logger.getLogger("BasicFeatureSource"); // the path to underlying data source String path; // the query source, codec, and header // protected final QuerySource querySource; protected final FeatureCodec<T, SOURCE> codec; protected FeatureCodecHeader header; private static ComponentMethods methods = new ComponentMethods(); public static final Set<String> BLOCK_COMPRESSED_EXTENSIONS = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(".gz", ".gzip", ".bgz", ".bgzf"))); /** * Calls {@link #getFeatureReader(String, FeatureCodec, boolean)} with {@code requireIndex} = true */ public static <FEATURE extends Feature, SOURCE> AbstractFeatureReader<FEATURE, SOURCE> getFeatureReader(final String featureFile, final FeatureCodec<FEATURE, SOURCE> codec) throws TribbleException { return getFeatureReader(featureFile, codec, true); } /** * {@link #getFeatureReader(String, String, FeatureCodec, boolean)} with {@code null} for indexResource * @throws TribbleException */ public static <FEATURE extends Feature, SOURCE> AbstractFeatureReader<FEATURE, SOURCE> getFeatureReader(final String featureResource, final FeatureCodec<FEATURE, SOURCE> codec, final boolean requireIndex) throws TribbleException { return getFeatureReader(featureResource, null, codec, requireIndex); } /** * * @param featureResource the feature file to create from * @param indexResource the index for the feature file. If null, will auto-generate (if necessary) * @param codec * @param requireIndex whether an index is required for this file * @return * @throws TribbleException */ public static <FEATURE extends Feature, SOURCE> AbstractFeatureReader<FEATURE, SOURCE> getFeatureReader(final String featureResource, String indexResource, final FeatureCodec<FEATURE, SOURCE> codec, final boolean requireIndex) throws TribbleException { try { // Test for tabix index if (methods.isTabix(featureResource, indexResource)) { if ( ! (codec instanceof AsciiFeatureCodec) ) throw new TribbleException("Tabix indexed files only work with ASCII codecs, but received non-Ascii codec " + codec.getClass().getSimpleName()); return new TabixFeatureReader<FEATURE, SOURCE>(featureResource, indexResource, (AsciiFeatureCodec) codec); } // Not tabix => tribble index file (might be gzipped, but not block gzipped) else { return new TribbleIndexedFeatureReader<FEATURE, SOURCE>(featureResource, indexResource, codec, requireIndex); } } catch (IOException e) { throw new TribbleException.MalformedFeatureFile("Unable to create BasicFeatureReader using feature file ", featureResource, e); } catch (TribbleException e) { e.setSource(featureResource); throw e; } } /** * Return a reader with a supplied index. * * @param featureResource the path to the source file containing the features * @param codec used to decode the features * @param index index of featureResource * @return a reader for this data * @throws TribbleException */ public static <FEATURE extends Feature, SOURCE> AbstractFeatureReader<FEATURE, SOURCE> getFeatureReader(final String featureResource, final FeatureCodec<FEATURE, SOURCE> codec, final Index index) throws TribbleException { try { return new TribbleIndexedFeatureReader<FEATURE, SOURCE>(featureResource, codec, index); } catch (IOException e) { throw new TribbleException.MalformedFeatureFile("Unable to create AbstractFeatureReader using feature file ", featureResource, e); } } protected AbstractFeatureReader(final String path, final FeatureCodec<T, SOURCE> codec) { this.path = path; this.codec = codec; } /** * Whether the reader has an index or not * Default implementation returns false * @return */ public boolean hasIndex(){ return false; } public static void setComponentMethods(ComponentMethods methods){ AbstractFeatureReader.methods = methods; } /** * Whether a filename ends in one of the BLOCK_COMPRESSED_EXTENSIONS * @param fileName * @return */ public static boolean hasBlockCompressedExtension (final String fileName) { for (final String extension : BLOCK_COMPRESSED_EXTENSIONS) { if (fileName.toLowerCase().endsWith(extension)) return true; } return false; } /** * Whether the name of a file ends in one of the BLOCK_COMPRESSED_EXTENSIONS * @param file * @return */ public static boolean hasBlockCompressedExtension (final File file) { return hasBlockCompressedExtension(file.getName()); } /** * get the header * * @return the header object we've read-in */ public Object getHeader() { return header.getHeaderValue(); } static class EmptyIterator<T extends Feature> implements CloseableTribbleIterator<T> { public Iterator iterator() { return this; } public boolean hasNext() { return false; } public T next() { return null; } public void remove() { } @Override public void close() { } } public static class ComponentMethods{ public boolean isTabix(String resourcePath, String indexPath) throws IOException{ if(indexPath == null){ indexPath = ParsingUtils.appendToPath(resourcePath, TabixUtils.STANDARD_INDEX_EXTENSION); } return hasBlockCompressedExtension(resourcePath) && ParsingUtils.resourceExists(indexPath); } } }