diff --git a/src/main/java/htsjdk/tribble/util/FTPHelper.java b/src/main/java/htsjdk/tribble/util/FTPHelper.java index c28650ff07..e207cd45e7 100644 --- a/src/main/java/htsjdk/tribble/util/FTPHelper.java +++ b/src/main/java/htsjdk/tribble/util/FTPHelper.java @@ -43,7 +43,6 @@ public InputStream openInputStream() throws IOException { } @Override - @Deprecated public InputStream openInputStreamForRange(long start, long end) throws IOException { throw new UnsupportedOperationException("Cannot perform range operations over FTP"); } diff --git a/src/main/java/htsjdk/tribble/util/HTTPHelper.java b/src/main/java/htsjdk/tribble/util/HTTPHelper.java index cdd6b277e5..801b19c505 100644 --- a/src/main/java/htsjdk/tribble/util/HTTPHelper.java +++ b/src/main/java/htsjdk/tribble/util/HTTPHelper.java @@ -63,7 +63,7 @@ public URL getUrl() { } /** - * @return content length of the resource + * @return content length of the resource, or -1 if not available * @throws IOException */ @Override @@ -88,30 +88,35 @@ public long getContentLength() throws IOException { @Override public InputStream openInputStream() throws IOException { - HttpURLConnection connection = openConnection(); return new WrapperInputStream(connection, connection.getInputStream()); } /** - * Open an input stream for the requested byte range. Its the client's responsibility to close the stream. + * Open an InputStream to stream a slice (range) of the resource. The host server must support + * range byte requests and return a 206 response code (partial response). If it does not an IOException will + * be thrown. + * + * Its the client's responsibility to close the stream. * * @param start start of range in bytes * @param end end of range ni bytes * @return * @throws IOException - * - * @deprecated since 12/10/14 Will be removed in a future release, as is somewhat fragile - * and not used. */ @Override - @Deprecated public InputStream openInputStreamForRange(long start, long end) throws IOException { HttpURLConnection connection = openConnection(); String byteRange = "bytes=" + start + "-" + end; connection.setRequestProperty("Range", byteRange); + + if (connection.getResponseCode() != 206) { + String msg = "Error: range requested, expected response code 206 but found " + connection.getResponseCode(); + throw new IOException(msg); + } + return new WrapperInputStream(connection, connection.getInputStream()); } diff --git a/src/main/java/htsjdk/tribble/util/ParsingUtils.java b/src/main/java/htsjdk/tribble/util/ParsingUtils.java index 0ed9ff2eb9..6b4470a72a 100644 --- a/src/main/java/htsjdk/tribble/util/ParsingUtils.java +++ b/src/main/java/htsjdk/tribble/util/ParsingUtils.java @@ -46,11 +46,10 @@ public class ParsingUtils { public static final Map colorCache = new WeakHashMap<>(100); - // HTML 4.1 color table, + orange and magenta - static Map colorSymbols = new HashMap(); + private static URLHelperFactory urlHelperFactory = RemoteURLHelper::new; - private static final Class defaultUrlHelperClass = RemoteURLHelper.class; - public static Class urlHelperClass = defaultUrlHelperClass; + // HTML 4.1 color table, + orange and magenta + private static Map colorSymbols = new HashMap(); static { colorSymbols.put("white", "FFFFFF"); @@ -423,50 +422,34 @@ public static boolean resourceExists(String resource) throws IOException{ } /** - * Return the registered URLHelper, constructed with the provided URL - * @see #registerHelperClass(Class) + * Return a URLHelper from the current URLHelperFactory + * @see #setURLHelperFactory(URLHelperFactory) + * * @param url * @return */ public static URLHelper getURLHelper(URL url) { - try { - return getURLHelper(urlHelperClass, url); - } catch (Exception e) { - return getURLHelper(defaultUrlHelperClass, url); - } - } - - private static URLHelper getURLHelper(Class helperClass, URL url) { - try { - Constructor constr = helperClass.getConstructor(URL.class); - return (URLHelper) constr.newInstance(url); - } catch (Exception e) { - String errMsg = "Error instantiating url helper for class: " + helperClass; - throw new IllegalStateException(errMsg, e); - } + return urlHelperFactory.getHelper(url); } /** - * Register a {@code URLHelper} class to be used for URL operations. The helper - * may be used for both FTP and HTTP operations, so if any FTP URLs are used - * the {@code URLHelper} must support it. - * - * The default helper class is {@link RemoteURLHelper}, which delegates to FTP/HTTP - * helpers as appropriate. + * Set the factory object for providing URLHelpers. {@see URLHelperFactory}. * - * @see URLHelper - * @param helperClass Class which implements {@link URLHelper}, and have a constructor - * which takes a URL as it's only argument. + * @param factory */ - public static void registerHelperClass(Class helperClass) { - if (!URLHelper.class.isAssignableFrom(helperClass)) { - throw new IllegalArgumentException("helperClass must implement URLHelper"); - //TODO check that it has 1 arg constructor of proper type + public static void setURLHelperFactory(URLHelperFactory factory) { + if(factory == null) { + throw new NullPointerException("Null URLHelperFactory"); } - urlHelperClass = helperClass; + urlHelperFactory = factory; + } + + public static URLHelperFactory getURLHelperFactory() { + return urlHelperFactory; } /** + * * Add the {@code indexExtension} to the {@code filepath}, preserving * query string elements if present. Intended for use where {@code filepath} * is a URL. Will behave correctly on regular file paths (just add the extension diff --git a/src/main/java/htsjdk/tribble/util/RemoteURLHelper.java b/src/main/java/htsjdk/tribble/util/RemoteURLHelper.java index 2493edbdbc..d0a2c08e5c 100644 --- a/src/main/java/htsjdk/tribble/util/RemoteURLHelper.java +++ b/src/main/java/htsjdk/tribble/util/RemoteURLHelper.java @@ -43,7 +43,6 @@ public InputStream openInputStream() throws IOException { } @Override - @Deprecated public InputStream openInputStreamForRange(long start, long end) throws IOException { return this.wrappedHelper.openInputStreamForRange(start, end); } diff --git a/src/main/java/htsjdk/tribble/util/URLHelper.java b/src/main/java/htsjdk/tribble/util/URLHelper.java index 9a4fdcb52a..7e545acb53 100644 --- a/src/main/java/htsjdk/tribble/util/URLHelper.java +++ b/src/main/java/htsjdk/tribble/util/URLHelper.java @@ -23,8 +23,10 @@ import java.net.URL; /** - * Interface defining a helper class for dealing with URL resources. Purpose of this class is to provide the - * flexibility to use either URLConnection or Apache HTTPClient. Also want to delegate to either HTTP or FTP + * Interface defining a helper class for dealing with URL resources. The purpose of this class is to provide the + * flexibility to use alternative http implementations, for example Apache HTTPClient, and secondly to provide + * a hook for clients to inject custom headers, for example oAuth tokens, into the requests. An instance of + * URLHelper is created for a URL (there is a 1-1 relation between a URL and HRLHelper). * * @see HTTPHelper * @see FTPHelper @@ -33,22 +35,34 @@ */ public interface URLHelper { + /** + * @return URL of the associated resource + */ URL getUrl(); + /** + * @return content length of the resource, or -1 if not available + * @throws IOException + */ long getContentLength() throws IOException; + /** + * Open an InputStream to stream the contents of the resource + * @return + * @throws IOException + */ InputStream openInputStream() throws IOException; /** + * Open an InputStream to stream a slice (range) of the resource. + * * May throw an OperationUnsupportedException - * @deprecated Will be removed in a future release, as is somewhat fragile - * and not used. * @param start * @param end * @return * @throws IOException */ - @Deprecated + InputStream openInputStreamForRange(long start, long end) throws IOException; public boolean exists() throws IOException; diff --git a/src/main/java/htsjdk/tribble/util/URLHelperFactory.java b/src/main/java/htsjdk/tribble/util/URLHelperFactory.java new file mode 100644 index 0000000000..98ba8d19ca --- /dev/null +++ b/src/main/java/htsjdk/tribble/util/URLHelperFactory.java @@ -0,0 +1,17 @@ +package htsjdk.tribble.util; + +import java.net.URL; + +/** + * A factory for creating {@link URLHelper} instances. The factory contains a single function + * @see #getHelper(URL) which should return a URLHelper instance for the given URL. + */ +public interface URLHelperFactory { + + /** + * @param url + * @return a {@link URLHelper} object for the given URL + */ + URLHelper getHelper(URL url); + +}