updating tribble to support path wrappers #796
Merged
Commits
Jump to file or symbol
Failed to load files and symbols.
| @@ -27,6 +27,8 @@ | ||
| import java.io.File; | ||
| import java.io.IOException; | ||
| import java.net.URL; | ||
| +import java.nio.channels.SeekableByteChannel; | ||
| +import java.util.function.Function; | ||
| /** | ||
| * Singleton class for getting {@link SeekableStream}s from URL/paths | ||
| @@ -65,11 +67,27 @@ public static boolean isFilePath(final String path) { | ||
| private static class DefaultSeekableStreamFactory implements ISeekableStreamFactory { | ||
| + @Override | ||
| public SeekableStream getStreamFor(final URL url) throws IOException { | ||
| return getStreamFor(url.toExternalForm()); | ||
| } | ||
| + @Override | ||
| public SeekableStream getStreamFor(final String path) throws IOException { | ||
| + return getStreamFor(path, null); | ||
| + } | ||
| + | ||
| + /** | ||
| + * The wrapper will only be applied to the stream if the stream is treated as a {@link java.nio.file.Path} | ||
| + * | ||
| + * This currently means any uri with a scheme that is not http, https, ftp, or file will have the wrapper applied to it | ||
| + * | ||
| + * @param path a uri like String representing a resource to open | ||
| + * @param wrapper a wrapper to apply to the stream allowing direct transformations on the byte stream to be applied | ||
| + */ | ||
| + @Override | ||
| + public SeekableStream getStreamFor(final String path, | ||
| + Function<SeekableByteChannel, SeekableByteChannel> wrapper) throws IOException { | ||
| // todo -- add support for SeekableBlockInputStream | ||
| if (path.startsWith("http:") || path.startsWith("https:")) { | ||
| @@ -80,16 +98,18 @@ public SeekableStream getStreamFor(final String path) throws IOException { | ||
| } else if (path.startsWith("file:")) { | ||
| return new SeekableFileStream(new File(new URL(path).getPath())); | ||
| } else if (IOUtil.hasScheme(path)) { | ||
droazen
Contributor
|
||
| - return new SeekablePathStream(IOUtil.getPath(path)); | ||
| + return new SeekablePathStream(IOUtil.getPath(path), wrapper); | ||
| } else { | ||
| return new SeekableFileStream(new File(path)); | ||
| } | ||
| } | ||
| + @Override | ||
| public SeekableStream getBufferedStream(SeekableStream stream){ | ||
| return getBufferedStream(stream, SeekableBufferedStream.DEFAULT_BUFFER_SIZE); | ||
| } | ||
| + @Override | ||
| public SeekableStream getBufferedStream(SeekableStream stream, int bufferSize){ | ||
| if (bufferSize == 0) return stream; | ||
| else return new SeekableBufferedStream(stream, bufferSize); | ||
| @@ -25,11 +25,13 @@ | ||
| import java.io.File; | ||
| import java.io.IOException; | ||
| import java.net.URI; | ||
| +import java.nio.channels.SeekableByteChannel; | ||
| import java.util.Arrays; | ||
| import java.util.Collections; | ||
| import java.util.HashSet; | ||
| import java.util.Iterator; | ||
| import java.util.Set; | ||
| +import java.util.function.Function; | ||
| /** | ||
| * jrobinso | ||
| @@ -43,6 +45,11 @@ | ||
| // the path to underlying data source | ||
| String path; | ||
| + // a wrapper to apply to the raw stream of the Feature file to allow features like prefetching and caching to be injected | ||
| + final Function<SeekableByteChannel, SeekableByteChannel> wrapper; | ||
| + // a wrapper to apply to the raw stream of the index file | ||
| + final Function<SeekableByteChannel, SeekableByteChannel> indexWrapper; | ||
| + | ||
| // the query source, codec, and header | ||
| // protected final QuerySource querySource; | ||
| protected final FeatureCodec<T, SOURCE> codec; | ||
| @@ -60,38 +67,51 @@ | ||
| } | ||
| /** | ||
| - * {@link #getFeatureReader(String, String, FeatureCodec, boolean)} with {@code null} for indexResource | ||
| + * {@link #getFeatureReader(String, String, FeatureCodec, boolean, Function, Function)} with {@code null} for indexResource, wrapper, and indexWrapper | ||
| * @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); | ||
| + return getFeatureReader(featureResource, null, codec, requireIndex, null, null); | ||
| + } | ||
| + | ||
| + | ||
| + /** | ||
| + * {@link #getFeatureReader(String, String, FeatureCodec, boolean, Function, Function)} with {@code null} for wrapper, and indexWrapper | ||
| + * @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 { | ||
| + return getFeatureReader(featureResource, indexResource, codec, requireIndex, null, null); | ||
| } | ||
| /** | ||
| * | ||
| * @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 codec the codec to use to decode the individual features | ||
| * @param requireIndex whether an index is required for this file | ||
| - * @return | ||
| + * @param wrapper a wrapper to apply to the byte stream from the featureResource allowing injecting features | ||
| + * like caching and prefetching of the stream, may be null, will only be applied if featureResource | ||
| + * is a uri representing a {@link java.nio.file.Path} | ||
| + * @param indexWrapper a wrapper to apply to the byte stream from the indexResource, may be null, will only be | ||
| + * applied if indexResource is a uri representing a {@link java.nio.file.Path} | ||
| + * | ||
| * @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 { | ||
| - | ||
| + public static <FEATURE extends Feature, SOURCE> AbstractFeatureReader<FEATURE, SOURCE> getFeatureReader(final String featureResource, String indexResource, final FeatureCodec<FEATURE, SOURCE> codec, final boolean requireIndex, Function<SeekableByteChannel, SeekableByteChannel> wrapper, Function<SeekableByteChannel, SeekableByteChannel> indexWrapper) 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); | ||
| + return new TabixFeatureReader<>(featureResource, indexResource, (AsciiFeatureCodec) codec, wrapper, indexWrapper); | ||
| } | ||
| // Not tabix => tribble index file (might be gzipped, but not block gzipped) | ||
| else { | ||
| - return new TribbleIndexedFeatureReader<FEATURE, SOURCE>(featureResource, indexResource, codec, requireIndex); | ||
| + return new TribbleIndexedFeatureReader<>(featureResource, indexResource, codec, requireIndex, wrapper, indexWrapper); | ||
| } | ||
| - } catch (IOException e) { | ||
| + } catch (final IOException e) { | ||
| throw new TribbleException.MalformedFeatureFile("Unable to create BasicFeatureReader using feature file ", featureResource, e); | ||
| - } catch (TribbleException e) { | ||
| + } catch (final TribbleException e) { | ||
| e.setSource(featureResource); | ||
| throw e; | ||
| } | ||
| @@ -108,16 +128,24 @@ | ||
| */ | ||
| 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) { | ||
| + return new TribbleIndexedFeatureReader<>(featureResource, codec, index); | ||
| + } catch (final 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, codec, null, null); | ||
| + } | ||
| + | ||
| + protected AbstractFeatureReader(final String path, final FeatureCodec<T, SOURCE> codec, | ||
| + final Function<SeekableByteChannel, SeekableByteChannel> wrapper, | ||
| + final Function<SeekableByteChannel, SeekableByteChannel> indexWrapper) { | ||
| this.path = path; | ||
| this.codec = codec; | ||
| + this.wrapper = wrapper; | ||
| + this.indexWrapper = indexWrapper; | ||
| } | ||
| /** | ||
| @@ -169,25 +197,30 @@ public static boolean hasBlockCompressedExtension (final URI uri) { | ||
| * | ||
| * @return the header object we've read-in | ||
| */ | ||
| + @Override | ||
| 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 Iterator<T> iterator() { return this; } | ||
| + @Override public boolean hasNext() { return false; } | ||
| + @Override public T next() { return null; } | ||
| + @Override public void remove() { } | ||
| @Override public void close() { } | ||
| } | ||
| + public static 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); | ||
| + } | ||
| + | ||
| public static class ComponentMethods{ | ||
droazen
Contributor
|
||
| 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); | ||
| + return AbstractFeatureReader.isTabix(resourcePath, indexPath); | ||
| } | ||
| } | ||
| } | ||
Oops, something went wrong.
this isn't used anywhere so I removed it