Skip to content

Commit

Permalink
Issue #5129 - Reverting Resource.fromReferences()
Browse files Browse the repository at this point in the history
+ Will migrate to jetty-10.0.x

Signed-off-by: Joakim Erdfelt <joakim.erdfelt@gmail.com>
  • Loading branch information
joakime committed Aug 11, 2020
1 parent 5b8c343 commit 150dc22
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 153 deletions.
105 changes: 0 additions & 105 deletions jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java
Expand Up @@ -32,13 +32,11 @@
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;
Expand Down Expand Up @@ -996,107 +994,4 @@ public static URL toURL(File file) throws MalformedURLException
{
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 IOException,
* 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;
}

/**
* 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, Resource::newResource);
}

/**
* 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;
}
}
Expand Up @@ -234,23 +234,7 @@ public void addClassPath(Resource 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.toString());
}
}

Expand All @@ -266,9 +250,53 @@ public void addClassPath(String classPath)
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);
}
}
}
}

Expand All @@ -291,29 +319,37 @@ public void addJars(Resource lib)
{
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);
}
}
}
Expand Down
Expand Up @@ -29,8 +29,8 @@
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;
Expand Down Expand Up @@ -943,10 +943,55 @@ protected List<Resource> findExtraClasspathJars(WebAppContext context)
if (context == null || context.getExtraClasspath() == null)
return null;

return Resource.fromReferences(context.getExtraClasspath())
.stream()
.filter(WebInfConfiguration::isFileSupported)
.collect(Collectors.toList());
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[] 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;
}

/**
Expand Down Expand Up @@ -988,13 +1033,53 @@ protected List<Resource> findExtraClasspathDirs(WebAppContext context)
if (context == null || context.getExtraClasspath() == null)
return null;

return Resource.fromReferences(context.getExtraClasspath())
.stream()
.filter(Resource::isDirectory)
.collect(Collectors.toList());
List<Resource> 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 boolean isGlobReference(String token)
{
return token.endsWith("/*") || token.endsWith("\\*");
}

private static boolean isFileSupported(Resource resource)
private boolean isFileSupported(Resource resource)
{
String filenameLowercase = resource.getName().toLowerCase(Locale.ENGLISH);
int dot = filenameLowercase.lastIndexOf('.');
Expand Down

0 comments on commit 150dc22

Please sign in to comment.