Issue #5129 - Simplify Resource reference list behavior
+ Introduce new Resource.fromReferences to help with parsing delimited resource reference lists. Signed-off-by: Joakim Erdfelt <joakim.erdfelt@gmail.com>
This commit is contained in:
parent
55f4e4fa63
commit
e8098986e6
|
@ -32,11 +32,13 @@ import java.nio.file.Path;
|
|||
import java.nio.file.Paths;
|
||||
import java.text.DateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.Loader;
|
||||
|
@ -301,7 +303,6 @@ public abstract class Resource implements ResourceFactory, Closeable
|
|||
return r.isContainedIn(containingResource);
|
||||
}
|
||||
|
||||
|
||||
//@checkstyle-disable-check : NoFinalizer
|
||||
@Override
|
||||
protected void finalize()
|
||||
|
@ -995,4 +996,118 @@ public abstract class Resource implements ResourceFactory, Closeable
|
|||
{
|
||||
return file.toURI().toURL();
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory to create new Resource instance from a reference.
|
||||
*/
|
||||
public interface Factory
|
||||
{
|
||||
/**
|
||||
* Create a new Resource from the factory's point of view.
|
||||
* <p>
|
||||
* This is different then {@link ResourceFactory} in that
|
||||
* it must return a {@link Resource} or throw an Exception,
|
||||
* never null.
|
||||
* </p>
|
||||
*
|
||||
* @param reference the string reference.
|
||||
* @return the Resource instance
|
||||
* @throws IOException if unable to create a Resource reference
|
||||
*/
|
||||
Resource newResource(String reference) throws IOException;
|
||||
}
|
||||
|
||||
private static class DefaultFactory implements Factory
|
||||
{
|
||||
public static final Factory INSTANCE = new DefaultFactory();
|
||||
|
||||
@Override
|
||||
public Resource newResource(String reference) throws IOException
|
||||
{
|
||||
return Resource.newResource(reference);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a delimited String of resource references and
|
||||
* return the List of Resources instances it represents.
|
||||
* <p>
|
||||
* Supports glob references that end in {@code /*} or {@code \*}.
|
||||
* Glob references will only iterate through the level specified and will not traverse
|
||||
* found directories within the glob reference.
|
||||
* </p>
|
||||
*
|
||||
* @param delimitedReferences the comma {@code ,} or semicolon {@code ;} delimited
|
||||
* String of resource references.
|
||||
* @return the list of resources parsed from input string.
|
||||
*/
|
||||
public static List<Resource> fromReferences(String delimitedReferences) throws IOException
|
||||
{
|
||||
return fromReferences(delimitedReferences, DefaultFactory.INSTANCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a delimited String of resource references and
|
||||
* return the List of Resources instances it represents.
|
||||
* <p>
|
||||
* Supports glob references that end in {@code /*} or {@code \*}.
|
||||
* Glob references will only iterate through the level specified and will not traverse
|
||||
* found directories within the glob reference.
|
||||
* </p>
|
||||
*
|
||||
* @param delimitedReferences the comma {@code ,} or semicolon {@code ;} delimited
|
||||
* String of resource references.
|
||||
* @param resourceFactory the Resource.Factory used to create new Resource references
|
||||
* @return the list of resources parsed from input string.
|
||||
*/
|
||||
public static List<Resource> fromReferences(String delimitedReferences, Resource.Factory resourceFactory) throws IOException
|
||||
{
|
||||
if (StringUtil.isBlank(delimitedReferences))
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<Resource> resources = new ArrayList<>();
|
||||
|
||||
StringTokenizer tokenizer = new StringTokenizer(delimitedReferences, ",;");
|
||||
while (tokenizer.hasMoreTokens())
|
||||
{
|
||||
String token = tokenizer.nextToken().trim();
|
||||
|
||||
// Is this a glob reference?
|
||||
if (token.endsWith("/*") || token.endsWith("\\*"))
|
||||
{
|
||||
String dir = token.substring(0, token.length() - 2);
|
||||
// Use directory
|
||||
Resource dirResource = resourceFactory.newResource(dir);
|
||||
if (dirResource.exists() && dirResource.isDirectory())
|
||||
{
|
||||
// To obtain the list of entries
|
||||
String[] entries = dirResource.list();
|
||||
if (entries != null)
|
||||
{
|
||||
Arrays.sort(entries);
|
||||
for (String entry : entries)
|
||||
{
|
||||
try
|
||||
{
|
||||
resources.add(dirResource.addPath(entry));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LOG.warn(Log.EXCEPTION, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Simple reference, add as-is
|
||||
resources.add(resourceFactory.newResource(token));
|
||||
}
|
||||
}
|
||||
|
||||
return resources;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -234,7 +234,23 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
|||
}
|
||||
else
|
||||
{
|
||||
addClassPath(resource.toString());
|
||||
// Resolve file path if possible
|
||||
File file = resource.getFile();
|
||||
if (file != null)
|
||||
{
|
||||
URL url = resource.getURI().toURL();
|
||||
addURL(url);
|
||||
}
|
||||
else if (resource.isDirectory())
|
||||
{
|
||||
addURL(resource.getURI().toURL());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Check file exists and is not nested jar: " + resource);
|
||||
throw new IllegalArgumentException("File not resolvable or incompatible with URLClassloader: " + resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -250,53 +266,9 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
|||
if (classPath == null)
|
||||
return;
|
||||
|
||||
StringTokenizer tokenizer = new StringTokenizer(classPath, ",;");
|
||||
while (tokenizer.hasMoreTokens())
|
||||
for (Resource resource : Resource.fromReferences(classPath, _context::newResource))
|
||||
{
|
||||
String token = tokenizer.nextToken().trim();
|
||||
|
||||
if (token.endsWith("*"))
|
||||
{
|
||||
if (token.length() > 1)
|
||||
{
|
||||
token = token.substring(0, token.length() - 1);
|
||||
Resource resource = _context.newResource(token);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Glob Path resource=" + resource);
|
||||
resource = _context.newResource(token);
|
||||
addJars(resource);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Resource resource = _context.newResource(token);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Path resource=" + resource);
|
||||
|
||||
if (resource.isDirectory() && resource instanceof ResourceCollection)
|
||||
{
|
||||
addClassPath(resource);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Resolve file path if possible
|
||||
File file = resource.getFile();
|
||||
if (file != null)
|
||||
{
|
||||
URL url = resource.getURI().toURL();
|
||||
addURL(url);
|
||||
}
|
||||
else if (resource.isDirectory())
|
||||
{
|
||||
addURL(resource.getURI().toURL());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Check file exists and is not nested jar: " + resource);
|
||||
throw new IllegalArgumentException("File not resolvable or incompatible with URLClassloader: " + resource);
|
||||
}
|
||||
}
|
||||
addClassPath(resource);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,8 +29,8 @@ import java.util.Arrays;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.NetworkConnector;
|
||||
|
@ -943,55 +943,10 @@ public class WebInfConfiguration extends AbstractConfiguration
|
|||
if (context == null || context.getExtraClasspath() == null)
|
||||
return null;
|
||||
|
||||
List<Resource> jarResources = new ArrayList<>();
|
||||
StringTokenizer tokenizer = new StringTokenizer(context.getExtraClasspath(), ",;");
|
||||
while (tokenizer.hasMoreTokens())
|
||||
{
|
||||
String token = tokenizer.nextToken().trim();
|
||||
|
||||
// Is this a Glob Reference?
|
||||
if (isGlobReference(token))
|
||||
{
|
||||
String dir = token.substring(0, token.length() - 2);
|
||||
// Use directory
|
||||
Resource dirResource = context.newResource(dir);
|
||||
if (dirResource.exists() && dirResource.isDirectory())
|
||||
{
|
||||
// To obtain the list of files
|
||||
String[] files = dirResource.list();
|
||||
if (files != null)
|
||||
{
|
||||
Arrays.sort(files);
|
||||
for (String file : files)
|
||||
{
|
||||
try
|
||||
{
|
||||
Resource fileResource = dirResource.addPath(file);
|
||||
if (isFileSupported(fileResource))
|
||||
{
|
||||
jarResources.add(fileResource);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LOG.warn(Log.EXCEPTION, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Simple reference, add as-is
|
||||
Resource resource = context.newResource(token);
|
||||
if (isFileSupported(resource))
|
||||
{
|
||||
jarResources.add(resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return jarResources;
|
||||
return Resource.fromReferences(context.getExtraClasspath())
|
||||
.stream()
|
||||
.filter(WebInfConfiguration::isFileSupported)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1033,28 +988,13 @@ public class WebInfConfiguration extends AbstractConfiguration
|
|||
if (context == null || context.getExtraClasspath() == null)
|
||||
return null;
|
||||
|
||||
List<Resource> dirResources = new ArrayList<>();
|
||||
StringTokenizer tokenizer = new StringTokenizer(context.getExtraClasspath(), ",;");
|
||||
while (tokenizer.hasMoreTokens())
|
||||
{
|
||||
String token = tokenizer.nextToken().trim();
|
||||
if (!isGlobReference(token))
|
||||
{
|
||||
Resource resource = context.newResource(token);
|
||||
if (resource.exists() && resource.isDirectory())
|
||||
dirResources.add(resource);
|
||||
}
|
||||
}
|
||||
|
||||
return dirResources;
|
||||
return Resource.fromReferences(context.getExtraClasspath())
|
||||
.stream()
|
||||
.filter(Resource::isDirectory)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private boolean isGlobReference(String token)
|
||||
{
|
||||
return token.endsWith("/*") || token.endsWith("\\*");
|
||||
}
|
||||
|
||||
private boolean isFileSupported(Resource resource)
|
||||
private static boolean isFileSupported(Resource resource)
|
||||
{
|
||||
String filenameLowercase = resource.getName().toLowerCase(Locale.ENGLISH);
|
||||
int dot = filenameLowercase.lastIndexOf('.');
|
||||
|
|
|
@ -133,7 +133,12 @@ public class WebAppContextExtraClasspathTest
|
|||
Path extLibsDir = MavenTestingUtils.getTestResourcePathDir("ext");
|
||||
extLibsDir = extLibsDir.toAbsolutePath();
|
||||
List<Path> expectedPaths = Files.list(extLibsDir)
|
||||
.filter((path) -> path.toString().endsWith(".jar"))
|
||||
.filter((path) ->
|
||||
{
|
||||
if (Files.isDirectory(path))
|
||||
return true;
|
||||
return Files.isRegularFile(path) && path.toString().endsWith(".jar");
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
List<Path> actualPaths = new ArrayList<>();
|
||||
for (URL url : webAppClassLoader.getURLs())
|
||||
|
|
Loading…
Reference in New Issue