diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java
index 5939d58cfd3..34bbbfc23e7 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java
@@ -32,13 +32,11 @@ 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;
@@ -996,107 +994,4 @@ 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.
- *
- * This is different then {@link ResourceFactory} in that
- * it must return a {@link Resource} or throw an IOException,
- * never null.
- *
- *
- * @param reference the string reference.
- * @return the Resource instance
- * @throws IOException if unable to create a Resource reference
- */
- Resource newResource(String reference) throws IOException;
- }
-
- /**
- * Parse a delimited String of resource references and
- * return the List of Resources instances it represents.
- *
- * 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.
- *
- *
- * @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 fromReferences(String delimitedReferences) throws IOException
- {
- return fromReferences(delimitedReferences, Resource::newResource);
- }
-
- /**
- * Parse a delimited String of resource references and
- * return the List of Resources instances it represents.
- *
- * 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.
- *
- *
- * @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 fromReferences(String delimitedReferences, Resource.Factory resourceFactory) throws IOException
- {
- if (StringUtil.isBlank(delimitedReferences))
- {
- return Collections.emptyList();
- }
-
- List 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;
- }
}
diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppClassLoader.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppClassLoader.java
index 72cfea85210..8d9e5137384 100644
--- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppClassLoader.java
+++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppClassLoader.java
@@ -234,23 +234,7 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
}
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.toString());
}
}
@@ -266,9 +250,53 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
if (classPath == null)
return;
- for (Resource resource : Resource.fromReferences(classPath, _context::newResource))
+ StringTokenizer tokenizer = new StringTokenizer(classPath, ",;");
+ while (tokenizer.hasMoreTokens())
{
- addClassPath(resource);
+ 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);
+ }
+ }
}
}
@@ -291,29 +319,37 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
{
if (lib.exists() && lib.isDirectory())
{
- String[] files = lib.list();
- if (files != null)
+ String[] entries = lib.list();
+ if (entries != null)
{
- Arrays.sort(files);
- }
- for (int f = 0; files != null && f < files.length; f++)
- {
- try
+ Arrays.sort(entries);
+
+ for (String entry : entries)
{
- Resource fn = lib.addPath(files[f]);
- if (LOG.isDebugEnabled())
- LOG.debug("addJar - {}", fn);
- String fnlc = fn.getName().toLowerCase(Locale.ENGLISH);
- // don't check if this is a directory (prevents use of symlinks), see Bug 353165
- if (isFileSupported(fnlc))
+ try
{
- String jar = URIUtil.encodeSpecific(fn.toString(), ",;");
- addClassPath(jar);
+ Resource resource = lib.addPath(entry);
+ if (LOG.isDebugEnabled())
+ LOG.debug("addJar - {}", resource);
+ if (resource.isDirectory())
+ {
+ addURL(resource.getURI().toURL());
+ }
+ else
+ {
+ String fnlc = resource.getName().toLowerCase(Locale.ENGLISH);
+ // don't check if this is a directory (prevents use of symlinks), see Bug 353165
+ if (isFileSupported(fnlc))
+ {
+ String jar = URIUtil.encodeSpecific(resource.toString(), ",;");
+ addClassPath(jar);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LOG.warn(Log.EXCEPTION, ex);
}
- }
- catch (Exception ex)
- {
- LOG.warn(Log.EXCEPTION, ex);
}
}
}
diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java
index 7d016c55429..ad8aabab01b 100644
--- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java
+++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java
@@ -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,10 +943,55 @@ public class WebInfConfiguration extends AbstractConfiguration
if (context == null || context.getExtraClasspath() == null)
return null;
- return Resource.fromReferences(context.getExtraClasspath())
- .stream()
- .filter(WebInfConfiguration::isFileSupported)
- .collect(Collectors.toList());
+ List 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[] entries = dirResource.list();
+ if (entries != null)
+ {
+ Arrays.sort(entries);
+ for (String entry : entries)
+ {
+ try
+ {
+ Resource fileResource = dirResource.addPath(entry);
+ 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;
}
/**
@@ -988,13 +1033,53 @@ public class WebInfConfiguration extends AbstractConfiguration
if (context == null || context.getExtraClasspath() == null)
return null;
- return Resource.fromReferences(context.getExtraClasspath())
- .stream()
- .filter(Resource::isDirectory)
- .collect(Collectors.toList());
+ List dirResources = new ArrayList<>();
+ StringTokenizer tokenizer = new StringTokenizer(context.getExtraClasspath(), ",;");
+ while (tokenizer.hasMoreTokens())
+ {
+ String token = tokenizer.nextToken().trim();
+ 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[] entries = dirResource.list();
+ if (entries != null)
+ {
+ Arrays.sort(entries);
+ for (String entry : entries)
+ {
+ Resource resource = dirResource.addPath(entry);
+ if (resource.isDirectory())
+ {
+ dirResources.add(resource);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ Resource resource = context.newResource(token);
+ if (resource.exists() && resource.isDirectory())
+ {
+ dirResources.add(resource);
+ }
+ }
+ }
+
+ return dirResources;
}
- private static boolean isFileSupported(Resource resource)
+ private boolean isGlobReference(String token)
+ {
+ return token.endsWith("/*") || token.endsWith("\\*");
+ }
+
+ private boolean isFileSupported(Resource resource)
{
String filenameLowercase = resource.getName().toLowerCase(Locale.ENGLISH);
int dot = filenameLowercase.lastIndexOf('.');