Merge branch 'jetty-10.0.x-5133-webappcontext-extraclasspath-cleanup' into jetty-10.0.x
This commit is contained in:
commit
dc6bee5c96
|
@ -27,6 +27,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jetty.quickstart.QuickStartConfiguration;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
|
@ -337,17 +338,8 @@ public class WebAppPropertyConverter
|
|||
* @param resources the resources to convert
|
||||
* @return csv string of resource filenames
|
||||
*/
|
||||
private static String toCSV(Resource[] resources)
|
||||
private static String toCSV(List<Resource> resources)
|
||||
{
|
||||
StringBuilder rb = new StringBuilder();
|
||||
|
||||
for (Resource r : resources)
|
||||
{
|
||||
if (rb.length() > 0)
|
||||
rb.append(",");
|
||||
rb.append(r.toString());
|
||||
}
|
||||
|
||||
return rb.toString();
|
||||
return resources.stream().map(Object::toString).collect(Collectors.joining(","));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.Constants;
|
||||
|
||||
|
@ -145,7 +144,7 @@ public class AnnotationParser extends org.eclipse.jetty.annotations.AnnotationPa
|
|||
}
|
||||
});
|
||||
boolean hasDotPath = false;
|
||||
StringTokenizer tokenizer = new StringTokenizer(bundleClasspath, ",;", false);
|
||||
StringTokenizer tokenizer = new StringTokenizer(bundleClasspath, StringUtil.DEFAULT_DELIMS, false);
|
||||
while (tokenizer.hasMoreTokens())
|
||||
{
|
||||
String token = tokenizer.nextToken().trim();
|
||||
|
|
|
@ -233,7 +233,7 @@ public class ServerInstanceWrapper
|
|||
Thread.currentThread().setContextClassLoader(libExtClassLoader);
|
||||
|
||||
String jettyConfigurationUrls = (String)props.get(OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS);
|
||||
List<URL> jettyConfigurations = jettyConfigurationUrls != null ? Util.fileNamesAsURLs(jettyConfigurationUrls, Util.DEFAULT_DELIMS) : null;
|
||||
List<URL> jettyConfigurations = jettyConfigurationUrls != null ? Util.fileNamesAsURLs(jettyConfigurationUrls, StringUtil.DEFAULT_DELIMS) : null;
|
||||
|
||||
_server = configure(server, jettyConfigurations, props);
|
||||
|
||||
|
@ -418,7 +418,7 @@ public class ServerInstanceWrapper
|
|||
|
||||
List<URL> libURLs = new ArrayList<>();
|
||||
|
||||
StringTokenizer tokenizer = new StringTokenizer(sharedURLs, ",;", false);
|
||||
StringTokenizer tokenizer = new StringTokenizer(sharedURLs, StringUtil.DEFAULT_DELIMS, false);
|
||||
while (tokenizer.hasMoreTokens())
|
||||
{
|
||||
String tok = tokenizer.nextToken();
|
||||
|
|
|
@ -20,15 +20,12 @@ package org.eclipse.jetty.osgi.boot.internal.webapp;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.jar.JarFile;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
|
||||
|
@ -201,22 +198,16 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe
|
|||
@Override
|
||||
public void addClassPath(String classPath) throws IOException
|
||||
{
|
||||
|
||||
StringTokenizer tokenizer = new StringTokenizer(classPath, ",;");
|
||||
while (tokenizer.hasMoreTokens())
|
||||
for (Resource resource : Resource.fromList(classPath, false, (path) -> getContext().newResource(path)))
|
||||
{
|
||||
String path = tokenizer.nextToken();
|
||||
Resource resource = getContext().newResource(path);
|
||||
|
||||
// Resolve file path if possible
|
||||
File file = resource.getFile();
|
||||
if (file != null && isAcceptableLibrary(file, JAR_WITH_SUCH_CLASS_MUST_BE_EXCLUDED))
|
||||
{
|
||||
super.addClassPath(path);
|
||||
super.addClassPath(resource);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.info("Did not add {} to the classloader of the webapp {}", path, getContext());
|
||||
LOG.info("Did not add {} to the classloader of the webapp {}", resource, getContext());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -272,37 +263,4 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static Field _contextField;
|
||||
|
||||
/**
|
||||
* In the case of the generation of a webapp via a jetty context file we
|
||||
* need a proper classloader to setup the app before we have the
|
||||
* WebappContext So we place a fake one there to start with. We replace it
|
||||
* with the actual webapp context with this method. We also apply the
|
||||
* extraclasspath there at the same time.
|
||||
*
|
||||
* @param webappContext the web app context
|
||||
*/
|
||||
public void setWebappContext(WebAppContext webappContext)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_contextField == null)
|
||||
{
|
||||
_contextField = WebAppClassLoader.class.getDeclaredField("_context");
|
||||
_contextField.setAccessible(true);
|
||||
}
|
||||
_contextField.set(this, webappContext);
|
||||
if (webappContext.getExtraClasspath() != null)
|
||||
{
|
||||
addClassPath(webappContext.getExtraClasspath());
|
||||
}
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
// humf that will hurt if it does not work.
|
||||
LOG.warn("Unable to set webappcontext", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,8 +35,6 @@ import org.osgi.framework.InvalidSyntaxException;
|
|||
*/
|
||||
public class Util
|
||||
{
|
||||
public static final String DEFAULT_DELIMS = ",;";
|
||||
|
||||
/**
|
||||
* Create an osgi filter for the given classname and server name.
|
||||
*
|
||||
|
@ -101,7 +99,7 @@ public class Util
|
|||
public static List<URL> fileNamesAsURLs(String val, String delims)
|
||||
throws Exception
|
||||
{
|
||||
String separators = DEFAULT_DELIMS;
|
||||
String separators = StringUtil.DEFAULT_DELIMS;
|
||||
if (delims == null)
|
||||
delims = separators;
|
||||
|
||||
|
|
|
@ -210,7 +210,7 @@ public class CachedContentFactory implements HttpContent.ContentFactory
|
|||
return (len > 0 && (_useFileMappedBuffer || (len < _maxCachedFileSize && len < _maxCacheSize)));
|
||||
}
|
||||
|
||||
private HttpContent load(String pathInContext, Resource resource, int maxBufferSize)
|
||||
private HttpContent load(String pathInContext, Resource resource, int maxBufferSize) throws IOException
|
||||
{
|
||||
if (resource == null || !resource.exists())
|
||||
return null;
|
||||
|
|
|
@ -50,20 +50,26 @@ public class ResourceContentFactory implements ContentFactory
|
|||
}
|
||||
|
||||
@Override
|
||||
public HttpContent getContent(String pathInContext, int maxBufferSize)
|
||||
throws IOException
|
||||
public HttpContent getContent(String pathInContext, int maxBufferSize) throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
// try loading the content from our factory.
|
||||
Resource resource = _factory.getResource(pathInContext);
|
||||
HttpContent loaded = load(pathInContext, resource, maxBufferSize);
|
||||
return loaded;
|
||||
return load(pathInContext, resource, maxBufferSize);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
// Any error has potential to reveal fully qualified path
|
||||
throw (InvalidPathException)new InvalidPathException(pathInContext, "Invalid PathInContext").initCause(t);
|
||||
// There are many potential Exceptions that can reveal a fully qualified path.
|
||||
// See Issue #2560 - Always wrap a Throwable here in an InvalidPathException
|
||||
// that is limited to only the provided pathInContext.
|
||||
// The cause (which might reveal a fully qualified path) is still available,
|
||||
// on the Exception and the logging, but is not reported in normal error page situations.
|
||||
// This specific exception also allows WebApps to specifically hook into a known / reliable
|
||||
// Exception type for ErrorPageErrorHandling logic.
|
||||
InvalidPathException saferException = new InvalidPathException(pathInContext, "Invalid PathInContext");
|
||||
saferException.initCause(t);
|
||||
throw saferException;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -881,6 +881,6 @@ public class ResourceService
|
|||
* @param pathInContext the path of the request
|
||||
* @return The path of the matching welcome file in context or null.
|
||||
*/
|
||||
String getWelcomeFile(String pathInContext);
|
||||
String getWelcomeFile(String pathInContext) throws IOException;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1896,6 +1896,13 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
return Collections.unmodifiableMap(_localeEncodingMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to get a Resource from the Context.
|
||||
*
|
||||
* @param path the path within the resource to attempt to get
|
||||
* @return the resource, or null if not available.
|
||||
* @throws MalformedURLException if unable to form a Resource from the provided path
|
||||
*/
|
||||
public Resource getResource(String path) throws MalformedURLException
|
||||
{
|
||||
if (path == null || !path.startsWith(URIUtil.SLASH))
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
package org.eclipse.jetty.server.handler;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -36,6 +37,7 @@ import org.eclipse.jetty.server.ResourceContentFactory;
|
|||
import org.eclipse.jetty.server.ResourceService;
|
||||
import org.eclipse.jetty.server.ResourceService.WelcomeFactory;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler.Context;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceFactory;
|
||||
|
@ -78,7 +80,7 @@ public class ResourceHandler extends HandlerWrapper implements ResourceFactory,
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getWelcomeFile(String pathInContext)
|
||||
public String getWelcomeFile(String pathInContext) throws IOException
|
||||
{
|
||||
if (_welcomes == null)
|
||||
return null;
|
||||
|
@ -87,7 +89,7 @@ public class ResourceHandler extends HandlerWrapper implements ResourceFactory,
|
|||
{
|
||||
String welcomeInContext = URIUtil.addPaths(pathInContext, _welcomes[i]);
|
||||
Resource welcome = getResource(welcomeInContext);
|
||||
if (welcome != null && welcome.exists())
|
||||
if (welcome.exists())
|
||||
return welcomeInContext;
|
||||
}
|
||||
// not found
|
||||
|
@ -140,44 +142,51 @@ public class ResourceHandler extends HandlerWrapper implements ResourceFactory,
|
|||
}
|
||||
|
||||
@Override
|
||||
public Resource getResource(String path)
|
||||
public Resource getResource(String path) throws IOException
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} getResource({})", _context == null ? _baseResource : _context, path);
|
||||
|
||||
if (path == null || !path.startsWith("/"))
|
||||
return null;
|
||||
|
||||
try
|
||||
if (StringUtil.isBlank(path))
|
||||
{
|
||||
Resource r = null;
|
||||
throw new IllegalArgumentException("Path is blank");
|
||||
}
|
||||
|
||||
if (_baseResource != null)
|
||||
if (!path.startsWith("/"))
|
||||
{
|
||||
throw new IllegalArgumentException("Path reference invalid: " + path);
|
||||
}
|
||||
|
||||
Resource r = null;
|
||||
|
||||
if (_baseResource != null)
|
||||
{
|
||||
path = URIUtil.canonicalPath(path);
|
||||
r = _baseResource.addPath(path);
|
||||
|
||||
if (r.isAlias() && (_context == null || !_context.checkAlias(path, r)))
|
||||
{
|
||||
path = URIUtil.canonicalPath(path);
|
||||
r = _baseResource.addPath(path);
|
||||
|
||||
if (r != null && r.isAlias() && (_context == null || !_context.checkAlias(path, r)))
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("resource={} alias={}", r, r.getAlias());
|
||||
return null;
|
||||
}
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Rejected alias resource={} alias={}", r, r.getAlias());
|
||||
throw new IllegalStateException("Rejected alias reference: " + path);
|
||||
}
|
||||
else if (_context != null)
|
||||
r = _context.getResource(path);
|
||||
|
||||
if ((r == null || !r.exists()) && path.endsWith("/jetty-dir.css"))
|
||||
r = getStylesheet();
|
||||
|
||||
return r;
|
||||
}
|
||||
catch (Exception e)
|
||||
else if (_context != null)
|
||||
{
|
||||
LOG.debug("Unable to get Resource for {}", path, e);
|
||||
r = _context.getResource(path);
|
||||
if (r != null)
|
||||
return r;
|
||||
}
|
||||
|
||||
return null;
|
||||
if ((r == null || !r.exists()) && path.endsWith("/jetty-dir.css"))
|
||||
r = getStylesheet();
|
||||
|
||||
if (r == null)
|
||||
{
|
||||
throw new FileNotFoundException("Resource: " + path);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,6 +26,7 @@ import java.io.OutputStream;
|
|||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.http.CompressedContentFormat;
|
||||
import org.eclipse.jetty.http.HttpContent;
|
||||
|
@ -110,7 +111,7 @@ public class ResourceCacheTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testMutlipleSources1() throws Exception
|
||||
public void testMultipleSources1() throws Exception
|
||||
{
|
||||
Path basePath = createUtilTestResources(workDir.getEmptyPathDir());
|
||||
|
||||
|
@ -119,12 +120,12 @@ public class ResourceCacheTest
|
|||
new PathResource(basePath.resolve("two")),
|
||||
new PathResource(basePath.resolve("three")));
|
||||
|
||||
Resource[] r = rc.getResources();
|
||||
List<Resource> r = rc.getResources();
|
||||
MimeTypes mime = new MimeTypes();
|
||||
|
||||
CachedContentFactory rc3 = new CachedContentFactory(null, r[2], mime, false, false, CompressedContentFormat.NONE);
|
||||
CachedContentFactory rc2 = new CachedContentFactory(rc3, r[1], mime, false, false, CompressedContentFormat.NONE);
|
||||
CachedContentFactory rc1 = new CachedContentFactory(rc2, r[0], mime, false, false, CompressedContentFormat.NONE);
|
||||
CachedContentFactory rc3 = new CachedContentFactory(null, r.get(2), mime, false, false, CompressedContentFormat.NONE);
|
||||
CachedContentFactory rc2 = new CachedContentFactory(rc3, r.get(1), mime, false, false, CompressedContentFormat.NONE);
|
||||
CachedContentFactory rc1 = new CachedContentFactory(rc2, r.get(0), mime, false, false, CompressedContentFormat.NONE);
|
||||
|
||||
assertEquals(getContent(rc1, "1.txt"), "1 - one");
|
||||
assertEquals(getContent(rc1, "2.txt"), "2 - two");
|
||||
|
@ -149,11 +150,11 @@ public class ResourceCacheTest
|
|||
new PathResource(basePath.resolve("two")),
|
||||
new PathResource(basePath.resolve("three")));
|
||||
|
||||
Resource[] r = rc.getResources();
|
||||
List<Resource> r = rc.getResources();
|
||||
MimeTypes mime = new MimeTypes();
|
||||
|
||||
CachedContentFactory rc3 = new CachedContentFactory(null, r[2], mime, false, false, CompressedContentFormat.NONE);
|
||||
CachedContentFactory rc2 = new CachedContentFactory(rc3, r[1], mime, false, false, CompressedContentFormat.NONE)
|
||||
CachedContentFactory rc3 = new CachedContentFactory(null, r.get(2), mime, false, false, CompressedContentFormat.NONE);
|
||||
CachedContentFactory rc2 = new CachedContentFactory(rc3, r.get(1), mime, false, false, CompressedContentFormat.NONE)
|
||||
{
|
||||
@Override
|
||||
public boolean isCacheable(Resource resource)
|
||||
|
@ -162,7 +163,7 @@ public class ResourceCacheTest
|
|||
}
|
||||
};
|
||||
|
||||
CachedContentFactory rc1 = new CachedContentFactory(rc2, r[0], mime, false, false, CompressedContentFormat.NONE);
|
||||
CachedContentFactory rc1 = new CachedContentFactory(rc2, r.get(0), mime, false, false, CompressedContentFormat.NONE);
|
||||
|
||||
assertEquals(getContent(rc1, "1.txt"), "1 - one");
|
||||
assertEquals(getContent(rc1, "2.txt"), "2 - two");
|
||||
|
|
|
@ -37,6 +37,7 @@ public class StringUtil
|
|||
|
||||
public static final String ALL_INTERFACES = "0.0.0.0";
|
||||
public static final String CRLF = "\r\n";
|
||||
public static final String DEFAULT_DELIMS = ",;";
|
||||
|
||||
public static final String __ISO_8859_1 = "iso-8859-1";
|
||||
public static final String __UTF8 = "utf-8";
|
||||
|
|
|
@ -124,6 +124,6 @@ public class EmptyResource extends Resource
|
|||
@Override
|
||||
public Resource addPath(String path) throws IOException, MalformedURLException
|
||||
{
|
||||
return null;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,10 +34,13 @@ import java.nio.file.Paths;
|
|||
import java.nio.file.StandardCopyOption;
|
||||
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;
|
||||
|
@ -412,7 +415,7 @@ public abstract class Resource implements ResourceFactory, Closeable
|
|||
* given name.
|
||||
*
|
||||
* @param path The path segment to add, which is not encoded
|
||||
* @return the Resource for the resolved path within this Resource.
|
||||
* @return the Resource for the resolved path within this Resource, never null
|
||||
* @throws IOException if unable to resolve the path
|
||||
* @throws MalformedURLException if the resolution of the path fails because the input path parameter is malformed.
|
||||
*/
|
||||
|
@ -421,22 +424,11 @@ public abstract class Resource implements ResourceFactory, Closeable
|
|||
|
||||
/**
|
||||
* Get a resource from within this resource.
|
||||
* <p>
|
||||
* This method is essentially an alias for {@link #addPath(String)}, but without checked exceptions.
|
||||
* This method satisfied the {@link ResourceFactory} interface.
|
||||
*/
|
||||
@Override
|
||||
public Resource getResource(String path)
|
||||
public Resource getResource(String path) throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
return addPath(path);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.debug("Unable to addPath", e);
|
||||
return null;
|
||||
}
|
||||
return addPath(path);
|
||||
}
|
||||
|
||||
// FIXME: this appears to not be used
|
||||
|
@ -923,4 +915,97 @@ public abstract class Resource implements ResourceFactory, Closeable
|
|||
{
|
||||
return file.toURI().toURL();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a list of String delimited resources 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 resources the comma {@code ,} or semicolon {@code ;} delimited
|
||||
* String of resource references.
|
||||
* @param globDirs true to return directories in addition to files at the level of the glob
|
||||
* @return the list of resources parsed from input string.
|
||||
*/
|
||||
public static List<Resource> fromList(String resources, boolean globDirs) throws IOException
|
||||
{
|
||||
return fromList(resources, globDirs, 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 resources the comma {@code ,} or semicolon {@code ;} delimited
|
||||
* String of resource references.
|
||||
* @param globDirs true to return directories in addition to files at the level of the glob
|
||||
* @param resourceFactory the ResourceFactory used to create new Resource references
|
||||
* @return the list of resources parsed from input string.
|
||||
*/
|
||||
public static List<Resource> fromList(String resources, boolean globDirs, ResourceFactory resourceFactory) throws IOException
|
||||
{
|
||||
if (StringUtil.isBlank(resources))
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<Resource> returnedResources = new ArrayList<>();
|
||||
|
||||
StringTokenizer tokenizer = new StringTokenizer(resources, StringUtil.DEFAULT_DELIMS);
|
||||
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.getResource(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
|
||||
{
|
||||
Resource resource = dirResource.addPath(entry);
|
||||
if (!resource.isDirectory())
|
||||
{
|
||||
returnedResources.add(resource);
|
||||
}
|
||||
else if (globDirs)
|
||||
{
|
||||
returnedResources.add(resource);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LOG.warn("Bad glob [{}] entry: {}", token, entry, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Simple reference, add as-is
|
||||
returnedResources.add(resourceFactory.getResource(token));
|
||||
}
|
||||
}
|
||||
|
||||
return returnedResources;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,12 +25,12 @@ import java.net.MalformedURLException;
|
|||
import java.net.URI;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
|
||||
/**
|
||||
|
@ -42,7 +42,7 @@ import org.eclipse.jetty.util.URIUtil;
|
|||
*/
|
||||
public class ResourceCollection extends Resource
|
||||
{
|
||||
private Resource[] _resources;
|
||||
private List<Resource> _resources;
|
||||
|
||||
/**
|
||||
* Instantiates an empty resource collection.
|
||||
|
@ -51,7 +51,7 @@ public class ResourceCollection extends Resource
|
|||
*/
|
||||
public ResourceCollection()
|
||||
{
|
||||
_resources = new Resource[0];
|
||||
_resources = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -61,7 +61,7 @@ public class ResourceCollection extends Resource
|
|||
*/
|
||||
public ResourceCollection(Resource... resources)
|
||||
{
|
||||
List<Resource> list = new ArrayList<>();
|
||||
_resources = new ArrayList<>();
|
||||
for (Resource r : resources)
|
||||
{
|
||||
if (r == null)
|
||||
|
@ -70,15 +70,25 @@ public class ResourceCollection extends Resource
|
|||
}
|
||||
if (r instanceof ResourceCollection)
|
||||
{
|
||||
Collections.addAll(list, ((ResourceCollection)r).getResources());
|
||||
_resources.addAll(((ResourceCollection)r).getResources());
|
||||
}
|
||||
else
|
||||
{
|
||||
assertResourceValid(r);
|
||||
list.add(r);
|
||||
_resources.add(r);
|
||||
}
|
||||
}
|
||||
_resources = list.toArray(new Resource[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new resource collection.
|
||||
*
|
||||
* @param resources the resources to be added to collection
|
||||
*/
|
||||
public ResourceCollection(Collection<Resource> resources)
|
||||
{
|
||||
_resources = new ArrayList<>();
|
||||
_resources.addAll(resources);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -88,14 +98,13 @@ public class ResourceCollection extends Resource
|
|||
*/
|
||||
public ResourceCollection(String[] resources)
|
||||
{
|
||||
_resources = new ArrayList<>();
|
||||
|
||||
if (resources == null || resources.length == 0)
|
||||
{
|
||||
_resources = null;
|
||||
return;
|
||||
}
|
||||
|
||||
ArrayList<Resource> res = new ArrayList<>();
|
||||
|
||||
try
|
||||
{
|
||||
for (String strResource : resources)
|
||||
|
@ -106,16 +115,13 @@ public class ResourceCollection extends Resource
|
|||
}
|
||||
Resource resource = Resource.newResource(strResource);
|
||||
assertResourceValid(resource);
|
||||
res.add(resource);
|
||||
_resources.add(resource);
|
||||
}
|
||||
|
||||
if (res.isEmpty())
|
||||
if (_resources.isEmpty())
|
||||
{
|
||||
_resources = null;
|
||||
return;
|
||||
throw new IllegalArgumentException("resources cannot be empty or null");
|
||||
}
|
||||
|
||||
_resources = res.toArray(new Resource[0]);
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
|
@ -131,22 +137,39 @@ public class ResourceCollection extends Resource
|
|||
* Instantiates a new resource collection.
|
||||
*
|
||||
* @param csvResources the string containing comma-separated resource strings
|
||||
* @throws IOException if any listed resource is not valid
|
||||
*/
|
||||
public ResourceCollection(String csvResources)
|
||||
public ResourceCollection(String csvResources) throws IOException
|
||||
{
|
||||
setResourcesAsCSV(csvResources);
|
||||
setResources(csvResources);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the resource collection's resources.
|
||||
*
|
||||
* @return the resource array
|
||||
* @return the resource collection
|
||||
*/
|
||||
public Resource[] getResources()
|
||||
public List<Resource> getResources()
|
||||
{
|
||||
return _resources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the resource collection's resources.
|
||||
*
|
||||
* @param res the resources to set
|
||||
*/
|
||||
public void setResources(List<Resource> res)
|
||||
{
|
||||
_resources = new ArrayList<>();
|
||||
if (res.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_resources.addAll(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the resource collection's resources.
|
||||
*
|
||||
|
@ -167,71 +190,37 @@ public class ResourceCollection extends Resource
|
|||
res.add(resource);
|
||||
}
|
||||
|
||||
if (res.isEmpty())
|
||||
{
|
||||
_resources = null;
|
||||
return;
|
||||
}
|
||||
|
||||
_resources = res.toArray(new Resource[0]);
|
||||
setResources(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the resources as string of comma-separated values.
|
||||
* This method should be used when configuring jetty-maven-plugin.
|
||||
*
|
||||
* @param csvResources the comma-separated string containing
|
||||
* @param resources the comma-separated string containing
|
||||
* one or more resource strings.
|
||||
* @throws IOException if unable resource declared is not valid
|
||||
* @see Resource#fromList(String, boolean)
|
||||
*/
|
||||
public void setResourcesAsCSV(String csvResources)
|
||||
public void setResources(String resources) throws IOException
|
||||
{
|
||||
if (csvResources == null)
|
||||
if (StringUtil.isBlank(resources))
|
||||
{
|
||||
throw new IllegalArgumentException("CSV String is null");
|
||||
throw new IllegalArgumentException("String is blank");
|
||||
}
|
||||
|
||||
StringTokenizer tokenizer = new StringTokenizer(csvResources, ",;");
|
||||
int len = tokenizer.countTokens();
|
||||
if (len == 0)
|
||||
List<Resource> list = Resource.fromList(resources, false);
|
||||
if (list.isEmpty())
|
||||
{
|
||||
throw new IllegalArgumentException("ResourceCollection@setResourcesAsCSV(String) " +
|
||||
" argument must be a string containing one or more comma-separated resource strings.");
|
||||
throw new IllegalArgumentException("String contains no entries");
|
||||
}
|
||||
|
||||
List<Resource> res = new ArrayList<>();
|
||||
|
||||
try
|
||||
List<Resource> ret = new ArrayList<>();
|
||||
for (Resource resource : list)
|
||||
{
|
||||
while (tokenizer.hasMoreTokens())
|
||||
{
|
||||
String token = tokenizer.nextToken().trim();
|
||||
// TODO: If we want to support CSV tokens with spaces then we should not trim here
|
||||
// However, if we decide to to this, then CVS formatting/syntax becomes more strict.
|
||||
if (token.length() == 0)
|
||||
{
|
||||
continue; // skip
|
||||
}
|
||||
Resource resource = Resource.newResource(token);
|
||||
assertResourceValid(resource);
|
||||
res.add(resource);
|
||||
}
|
||||
|
||||
if (res.isEmpty())
|
||||
{
|
||||
_resources = null;
|
||||
return;
|
||||
}
|
||||
|
||||
_resources = res.toArray(new Resource[0]);
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
assertResourceValid(resource);
|
||||
ret.add(resource);
|
||||
}
|
||||
setResources(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -245,7 +234,7 @@ public class ResourceCollection extends Resource
|
|||
|
||||
if (path == null)
|
||||
{
|
||||
throw new MalformedURLException();
|
||||
throw new MalformedURLException("null path");
|
||||
}
|
||||
|
||||
if (path.length() == 0 || URIUtil.SLASH.equals(path))
|
||||
|
@ -253,51 +242,32 @@ public class ResourceCollection extends Resource
|
|||
return this;
|
||||
}
|
||||
|
||||
Resource resource = null;
|
||||
ArrayList<Resource> resources = null;
|
||||
int i = 0;
|
||||
for (; i < _resources.length; i++)
|
||||
|
||||
// Attempt a simple (single) Resource lookup that exists
|
||||
for (Resource res : _resources)
|
||||
{
|
||||
resource = _resources[i].addPath(path);
|
||||
if (resource.exists())
|
||||
Resource r = res.addPath(path);
|
||||
if (!r.isDirectory() && r.exists())
|
||||
{
|
||||
if (resource.isDirectory())
|
||||
{
|
||||
break;
|
||||
}
|
||||
return resource;
|
||||
// Return simple (non-directory) Resource
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
for (i++; i < _resources.length; i++)
|
||||
{
|
||||
Resource r = _resources[i].addPath(path);
|
||||
if (r.exists() && r.isDirectory())
|
||||
if (resources == null)
|
||||
{
|
||||
if (resources == null)
|
||||
{
|
||||
resources = new ArrayList<>();
|
||||
}
|
||||
|
||||
if (resource != null)
|
||||
{
|
||||
resources.add(resource);
|
||||
resource = null;
|
||||
}
|
||||
|
||||
resources.add(r);
|
||||
resources = new ArrayList<>();
|
||||
}
|
||||
|
||||
resources.add(r);
|
||||
}
|
||||
|
||||
if (resource != null)
|
||||
if (resources.size() == 1)
|
||||
{
|
||||
return resource;
|
||||
return resources.get(0);
|
||||
}
|
||||
if (resources != null)
|
||||
{
|
||||
return new ResourceCollection(resources.toArray(new Resource[0]));
|
||||
}
|
||||
return null;
|
||||
|
||||
return new ResourceCollection(resources);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -437,9 +407,8 @@ public class ResourceCollection extends Resource
|
|||
{
|
||||
Collections.addAll(set, r.list());
|
||||
}
|
||||
String[] result = set.toArray(new String[0]);
|
||||
Arrays.sort(result);
|
||||
return result;
|
||||
|
||||
return (String[])set.stream().sorted().toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -465,9 +434,10 @@ public class ResourceCollection extends Resource
|
|||
{
|
||||
assertResourcesSet();
|
||||
|
||||
for (int r = _resources.length; r-- > 0; )
|
||||
// Copy in reverse order
|
||||
for (int r = _resources.size(); r-- > 0; )
|
||||
{
|
||||
_resources[r].copyTo(destination);
|
||||
_resources.get(r).copyTo(destination);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -477,12 +447,12 @@ public class ResourceCollection extends Resource
|
|||
@Override
|
||||
public String toString()
|
||||
{
|
||||
if (_resources == null || _resources.length == 0)
|
||||
if (_resources.isEmpty())
|
||||
{
|
||||
return "[]";
|
||||
}
|
||||
|
||||
return String.valueOf(Arrays.asList(_resources));
|
||||
return String.valueOf(_resources);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -494,7 +464,7 @@ public class ResourceCollection extends Resource
|
|||
|
||||
private void assertResourcesSet()
|
||||
{
|
||||
if (_resources == null || _resources.length == 0)
|
||||
if (_resources == null || _resources.isEmpty())
|
||||
{
|
||||
throw new IllegalStateException("*resources* not set.");
|
||||
}
|
||||
|
|
|
@ -18,17 +18,26 @@
|
|||
|
||||
package org.eclipse.jetty.util.resource;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* ResourceFactory.
|
||||
*/
|
||||
public interface ResourceFactory
|
||||
{
|
||||
|
||||
/**
|
||||
* Get a resource for a path.
|
||||
* Get a Resource from a provided String.
|
||||
* <p>
|
||||
* The behavior here is dependent on the
|
||||
* implementation of ResourceFactory.
|
||||
* The provided path can be resolved
|
||||
* against a known Resource, or can
|
||||
* be a from-scratch Resource.
|
||||
* </p>
|
||||
*
|
||||
* @param path The path to the resource
|
||||
* @return The resource or null
|
||||
* @return The resource, that might not actually exist (yet).
|
||||
* @throws IOException if unable to create Resource
|
||||
*/
|
||||
Resource getResource(String path);
|
||||
Resource getResource(String path) throws IOException;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.net.URISyntaxException;
|
|||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.thread.AutoLock;
|
||||
|
@ -287,10 +288,9 @@ public class URLResource extends Resource
|
|||
*/
|
||||
@Override
|
||||
public Resource addPath(String path)
|
||||
throws IOException, MalformedURLException
|
||||
throws IOException
|
||||
{
|
||||
if (path == null)
|
||||
return null;
|
||||
Objects.requireNonNull(path, "Path may not be null");
|
||||
|
||||
path = URIUtil.canonicalPath(path);
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ public class ResourceCollectionTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testSetResourceNullThrowsISE()
|
||||
public void testSetResourceArrayNullThrowsISE()
|
||||
{
|
||||
// Create a ResourceCollection with one valid entry
|
||||
Path path = MavenTestingUtils.getTargetPath();
|
||||
|
@ -121,7 +121,7 @@ public class ResourceCollectionTest
|
|||
ResourceCollection coll = new ResourceCollection(resource);
|
||||
|
||||
// Reset collection to invalid state
|
||||
coll.setResources(null);
|
||||
coll.setResources((Resource[])null);
|
||||
|
||||
assertThrowIllegalStateException(coll);
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ public class ResourceCollectionTest
|
|||
assertThrows(IllegalStateException.class, () -> coll.setResources(new Resource[]{null, null, null}));
|
||||
|
||||
// Ensure not modified.
|
||||
assertThat(coll.getResources().length, is(1));
|
||||
assertThat(coll.getResources().size(), is(1));
|
||||
}
|
||||
|
||||
private void assertThrowIllegalStateException(ResourceCollection coll)
|
||||
|
|
|
@ -36,13 +36,12 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jetty.util.PatternMatcher;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.resource.EmptyResource;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceCollection;
|
||||
|
@ -802,7 +801,7 @@ public class MetaInfConfiguration extends AbstractConfiguration
|
|||
*
|
||||
* @param context the context to find extra classpath jars in
|
||||
* @return the list of Resources with the extra classpath, or null if not found
|
||||
* @throws Exception if unable to find the extra classpath jars
|
||||
* @throws Exception if unable to resolve the extra classpath jars
|
||||
*/
|
||||
protected List<Resource> findExtraClasspathJars(WebAppContext context)
|
||||
throws Exception
|
||||
|
@ -810,55 +809,10 @@ public class MetaInfConfiguration 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[] 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("Error resolving file {}", entry, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Simple reference, add as-is
|
||||
Resource resource = context.newResource(token);
|
||||
if (isFileSupported(resource))
|
||||
{
|
||||
jarResources.add(resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return jarResources;
|
||||
return context.getExtraClasspath()
|
||||
.stream()
|
||||
.filter(this::isFileSupported)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -892,7 +846,7 @@ public class MetaInfConfiguration extends AbstractConfiguration
|
|||
*
|
||||
* @param context the context to look for extra classpaths in
|
||||
* @return the list of Resources to the extra classpath
|
||||
* @throws Exception if unable to find the extra classpaths
|
||||
* @throws Exception if unable to resolve the extra classpath resources
|
||||
*/
|
||||
protected List<Resource> findExtraClasspathDirs(WebAppContext context)
|
||||
throws Exception
|
||||
|
@ -900,23 +854,10 @@ public class MetaInfConfiguration 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();
|
||||
// ignore glob references, they only refer to lists of jars/zips anyway
|
||||
if (!isGlobReference(token))
|
||||
{
|
||||
Resource resource = context.newResource(token);
|
||||
if (resource.exists() && resource.isDirectory())
|
||||
{
|
||||
dirResources.add(resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dirResources;
|
||||
return context.getExtraClasspath()
|
||||
.stream()
|
||||
.filter(Resource::isDirectory)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private String uriJarPrefix(URI uri, String suffix)
|
||||
|
@ -932,13 +873,23 @@ public class MetaInfConfiguration extends AbstractConfiguration
|
|||
}
|
||||
}
|
||||
|
||||
private boolean isGlobReference(String token)
|
||||
{
|
||||
return token.endsWith("/*") || token.endsWith("\\*");
|
||||
}
|
||||
|
||||
private boolean isFileSupported(Resource resource)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (resource.isDirectory())
|
||||
return false;
|
||||
|
||||
if (resource.getFile() == null)
|
||||
return false;
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Bad Resource reference: {}", resource, t);
|
||||
return false;
|
||||
}
|
||||
|
||||
String filenameLowercase = resource.getName().toLowerCase(Locale.ENGLISH);
|
||||
int dot = filenameLowercase.lastIndexOf('.');
|
||||
String extension = (dot < 0 ? null : filenameLowercase.substring(dot));
|
||||
|
|
|
@ -41,6 +41,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
|||
|
||||
import org.eclipse.jetty.util.ClassVisibilityChecker;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
@ -87,7 +88,6 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
|||
*/
|
||||
public interface Context extends ClassVisibilityChecker
|
||||
{
|
||||
|
||||
/**
|
||||
* Convert a URL or path to a Resource.
|
||||
* The default implementation
|
||||
|
@ -112,7 +112,7 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
|||
*/
|
||||
boolean isParentLoaderPriority();
|
||||
|
||||
String getExtraClasspath();
|
||||
List<Resource> getExtraClasspath();
|
||||
|
||||
boolean isServerResource(String name, URL parentUrl);
|
||||
|
||||
|
@ -185,7 +185,7 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
|||
String extensions = System.getProperty(WebAppClassLoader.class.getName() + ".extensions");
|
||||
if (extensions != null)
|
||||
{
|
||||
StringTokenizer tokenizer = new StringTokenizer(extensions, ",;");
|
||||
StringTokenizer tokenizer = new StringTokenizer(extensions, StringUtil.DEFAULT_DELIMS);
|
||||
while (tokenizer.hasMoreTokens())
|
||||
{
|
||||
_extensions.add(tokenizer.nextToken().trim());
|
||||
|
@ -193,7 +193,12 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
|||
}
|
||||
|
||||
if (context.getExtraClasspath() != null)
|
||||
addClassPath(context.getExtraClasspath());
|
||||
{
|
||||
for (Resource resource : context.getExtraClasspath())
|
||||
{
|
||||
addClassPath(resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -235,7 +240,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -251,53 +272,9 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
|||
if (classPath == null)
|
||||
return;
|
||||
|
||||
StringTokenizer tokenizer = new StringTokenizer(classPath, ",;");
|
||||
while (tokenizer.hasMoreTokens())
|
||||
for (Resource resource : Resource.fromList(classPath, false, _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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ import java.util.Collections;
|
|||
import java.util.EventListener;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -204,7 +205,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
|||
private boolean _persistTmpDir = false;
|
||||
|
||||
private String _war;
|
||||
private String _extraClasspath;
|
||||
private List<Resource> _extraClasspath;
|
||||
private Throwable _unavailableException;
|
||||
|
||||
private Map<String, String> _resourceAliases;
|
||||
|
@ -1248,17 +1249,29 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
|||
*/
|
||||
@Override
|
||||
@ManagedAttribute(value = "extra classpath for context classloader", readonly = true)
|
||||
public String getExtraClasspath()
|
||||
public List<Resource> getExtraClasspath()
|
||||
{
|
||||
return _extraClasspath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Extra ClassPath via delimited String.
|
||||
* <p>
|
||||
* This is a convenience method for {@link #setExtraClasspath(List)}
|
||||
* </p>
|
||||
*
|
||||
* @param extraClasspath Comma or semicolon separated path of filenames or URLs
|
||||
* pointing to directories or jar files. Directories should end
|
||||
* with '/'.
|
||||
* @throws IOException if unable to resolve the resources referenced
|
||||
* @see #setExtraClasspath(List)
|
||||
*/
|
||||
public void setExtraClasspath(String extraClasspath)
|
||||
public void setExtraClasspath(String extraClasspath) throws IOException
|
||||
{
|
||||
setExtraClasspath(Resource.fromList(extraClasspath, false, this::newResource));
|
||||
}
|
||||
|
||||
public void setExtraClasspath(List<Resource> extraClasspath)
|
||||
{
|
||||
_extraClasspath = extraClasspath;
|
||||
}
|
||||
|
@ -1450,11 +1463,12 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
|||
// Should we go to the original war?
|
||||
if (resource.isDirectory() && resource instanceof ResourceCollection && !WebAppContext.this.isExtractWAR())
|
||||
{
|
||||
Resource[] resources = ((ResourceCollection)resource).getResources();
|
||||
for (int i = resources.length; i-- > 0; )
|
||||
List<Resource> resources = ((ResourceCollection)resource).getResources();
|
||||
for (int i = resources.size(); i-- > 0; )
|
||||
{
|
||||
if (resources[i].getName().startsWith("jar:file"))
|
||||
return resources[i].getURI().toURL();
|
||||
Resource r = resources.get(i);
|
||||
if (r.getName().startsWith("jar:file"))
|
||||
return r.getURI().toURL();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue