Issue #8886 - changes to method names + abstract url impl
This commit is contained in:
parent
ee097316bb
commit
43937b1987
|
@ -0,0 +1,234 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.util.resource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Instant;
|
||||
|
||||
import org.eclipse.jetty.util.FileID;
|
||||
|
||||
/**
|
||||
* Abstract ResourceFactory for {@link java.net.URL} based resources.
|
||||
*/
|
||||
public abstract class AbstractUrlResourceFactory implements ResourceFactory
|
||||
{
|
||||
private final String supportedProtocol;
|
||||
private int connectTimeout;
|
||||
private boolean useCaches;
|
||||
|
||||
protected AbstractUrlResourceFactory(String protocol)
|
||||
{
|
||||
this.supportedProtocol = protocol;
|
||||
this.connectTimeout = Integer.parseInt(System.getProperty(this.getClass().getName() + ".connectTimeout", "1000"));
|
||||
this.useCaches = Boolean.parseBoolean(System.getProperty(this.getClass().getName() + ".useCaches", "true"));
|
||||
}
|
||||
|
||||
public int getConnectTimeout()
|
||||
{
|
||||
return connectTimeout;
|
||||
}
|
||||
|
||||
public void setConnectTimeout(int connectTimeout)
|
||||
{
|
||||
this.connectTimeout = connectTimeout;
|
||||
}
|
||||
|
||||
public boolean isUseCaches()
|
||||
{
|
||||
return useCaches;
|
||||
}
|
||||
|
||||
public void setUseCaches(boolean useCaches)
|
||||
{
|
||||
this.useCaches = useCaches;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource newResource(final URI uri)
|
||||
{
|
||||
if (!uri.getScheme().equalsIgnoreCase(supportedProtocol))
|
||||
throw new IllegalArgumentException("Scheme not support: " + uri.getScheme());
|
||||
|
||||
try
|
||||
{
|
||||
return new URLResource(uri, this.connectTimeout, this.useCaches);
|
||||
}
|
||||
catch (MalformedURLException e)
|
||||
{
|
||||
throw new RuntimeException("Bad URI: " + uri, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static class URLResource extends Resource
|
||||
{
|
||||
private final URI uri;
|
||||
private final URL url;
|
||||
private final int connectTimeout;
|
||||
private final boolean useCaches;
|
||||
|
||||
public URLResource(URI uri, int connectTimeout, boolean useCaches) throws MalformedURLException
|
||||
{
|
||||
this.uri = uri;
|
||||
this.url = uri.toURL();
|
||||
this.connectTimeout = connectTimeout;
|
||||
this.useCaches = useCaches;
|
||||
}
|
||||
|
||||
private URLConnection newConnection() throws IOException
|
||||
{
|
||||
URLConnection urlConnection = url.openConnection();
|
||||
urlConnection.setUseCaches(this.useCaches);
|
||||
urlConnection.setConnectTimeout(this.connectTimeout);
|
||||
return urlConnection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPath()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isContainedIn(Resource r)
|
||||
{
|
||||
// compare starting URIs?
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirectory()
|
||||
{
|
||||
return uri.getPath().endsWith("/");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadable()
|
||||
{
|
||||
return exists();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getURI()
|
||||
{
|
||||
return uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
return uri.getPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFileName()
|
||||
{
|
||||
return FileID.getFileName(uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource resolve(String subUriPath)
|
||||
{
|
||||
URI newURI = uri.resolve(subUriPath);
|
||||
try
|
||||
{
|
||||
return new URLResource(newURI, this.connectTimeout, this.useCaches);
|
||||
}
|
||||
catch (MalformedURLException e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists()
|
||||
{
|
||||
try
|
||||
{
|
||||
newConnection();
|
||||
return true;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream newInputStream() throws IOException
|
||||
{
|
||||
URLConnection urlConnection = newConnection();
|
||||
return urlConnection.getInputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instant lastModified()
|
||||
{
|
||||
try
|
||||
{
|
||||
URLConnection urlConnection = newConnection();
|
||||
return Instant.ofEpochMilli(urlConnection.getLastModified());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return Instant.EPOCH;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long length()
|
||||
{
|
||||
try
|
||||
{
|
||||
URLConnection urlConnection = newConnection();
|
||||
return urlConnection.getContentLengthLong();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadableByteChannel newReadableByteChannel()
|
||||
{
|
||||
// not really possible with the URL interface
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAlias()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getRealURI()
|
||||
{
|
||||
return getURI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("URLResource@%X(%s)", this.uri.hashCode(), this.uri.toASCIIString());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -236,11 +236,16 @@ public interface ResourceFactory
|
|||
return newResource(URIUtil.toJarFileUri(uri));
|
||||
}
|
||||
|
||||
static void addResourceFactory(String scheme, ResourceFactory resource)
|
||||
static void registerResourceFactory(String scheme, ResourceFactory resource)
|
||||
{
|
||||
ResourceFactoryInternals.RESOURCE_FACTORIES.put(scheme, resource);
|
||||
}
|
||||
|
||||
static ResourceFactory unregisterResourceFactory(String scheme)
|
||||
{
|
||||
return ResourceFactoryInternals.RESOURCE_FACTORIES.remove(scheme);
|
||||
}
|
||||
|
||||
static ResourceFactory byScheme(String scheme)
|
||||
{
|
||||
return ResourceFactoryInternals.RESOURCE_FACTORIES.get(scheme);
|
||||
|
|
|
@ -19,17 +19,45 @@ import java.nio.file.Path;
|
|||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
public class ResourceFactoryTest
|
||||
{
|
||||
@Test
|
||||
public void testCustomUriScheme()
|
||||
public void testCustomUriSchemeNotRegistered()
|
||||
{
|
||||
ResourceFactory.addResourceFactory("custom", new CustomResourceFactory());
|
||||
// Try this as a normal String input first.
|
||||
// We are subject to the URIUtil.toURI(String) behaviors here.
|
||||
// Since the `ftp` scheme is not registered, it's not recognized as a supported URI.
|
||||
// This will be treated as a relative path instead. (and the '//' will be compacted)
|
||||
Resource resource = ResourceFactory.root().newResource("ftp://webtide.com/favicon.ico");
|
||||
// Should not find this, as it doesn't exist on the filesystem.
|
||||
assertNull(resource);
|
||||
|
||||
// Now try it as a formal URI object as input.
|
||||
URI uri = URI.create("ftp://webtide.com/favicon.ico");
|
||||
// This is an unsupported URI scheme
|
||||
IllegalArgumentException iae = assertThrows(IllegalArgumentException.class, () -> ResourceFactory.root().newResource(uri));
|
||||
assertThat(iae.getMessage(), containsString("URI scheme not supported"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomUriSchemeRegistered()
|
||||
{
|
||||
ResourceFactory.registerResourceFactory("custom", new CustomResourceFactory());
|
||||
// Try as a normal String input
|
||||
Resource resource = ResourceFactory.root().newResource("custom://foo");
|
||||
assertThat(resource.getURI(), is(URI.create("custom://foo")));
|
||||
assertThat(resource.getName(), is("custom-impl"));
|
||||
|
||||
// Try as a formal URI object as input
|
||||
URI uri = URI.create("custom://foo");
|
||||
resource = ResourceFactory.root().newResource(uri);
|
||||
assertThat(resource.getURI(), is(URI.create("custom://foo")));
|
||||
assertThat(resource.getName(), is("custom-impl"));
|
||||
}
|
||||
|
||||
public static class CustomResourceFactory implements ResourceFactory
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.util.resource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Instant;
|
||||
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class UrlResourceFactoryTest
|
||||
{
|
||||
@Test
|
||||
@Tag("external")
|
||||
public void testHttps() throws IOException
|
||||
{
|
||||
ResourceFactory.registerResourceFactory("https", new HttpsResourceFactory());
|
||||
Resource resource = ResourceFactory.root().newResource(URI.create("https://webtide.com/"));
|
||||
assertThat(resource, notNullValue());
|
||||
assertTrue(resource.exists());
|
||||
|
||||
try (InputStream in = resource.newInputStream())
|
||||
{
|
||||
String result = IO.toString(in, StandardCharsets.UTF_8);
|
||||
assertThat(result, containsString("webtide.com"));
|
||||
}
|
||||
|
||||
assertThat(resource.lastModified().toEpochMilli(), not(Instant.EPOCH));
|
||||
assertThat(resource.length(), not(-1));
|
||||
assertTrue(resource.isDirectory());
|
||||
assertThat(resource.getFileName(), is(""));
|
||||
|
||||
Resource blogs = resource.resolve("blogs/");
|
||||
assertThat(blogs, notNullValue());
|
||||
assertTrue(blogs.exists());
|
||||
assertThat(blogs.lastModified().toEpochMilli(), not(Instant.EPOCH));
|
||||
assertThat(blogs.length(), not(-1));
|
||||
assertTrue(blogs.isDirectory());
|
||||
assertThat(blogs.getFileName(), is(""));
|
||||
|
||||
Resource favicon = resource.resolve("favicon.ico");
|
||||
assertThat(favicon, notNullValue());
|
||||
assertTrue(favicon.exists());
|
||||
assertThat(favicon.lastModified().toEpochMilli(), not(Instant.EPOCH));
|
||||
assertThat(favicon.length(), not(-1));
|
||||
assertFalse(favicon.isDirectory());
|
||||
assertThat(favicon.getFileName(), is("favicon.ico"));
|
||||
}
|
||||
|
||||
public static class HttpsResourceFactory extends AbstractUrlResourceFactory
|
||||
{
|
||||
public HttpsResourceFactory()
|
||||
{
|
||||
super("https");
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue