From 473afb57bc4ba212fad5d798e5270d5b9d8d099a Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Tue, 14 Nov 2023 10:20:59 +1100 Subject: [PATCH 1/7] Reduce resources kept open by MetaInfConfiguration --- .../ee10/webapp/MetaInfConfiguration.java | 52 +++++++------- .../ee9/webapp/MetaInfConfiguration.java | 67 +++++++++---------- 2 files changed, 60 insertions(+), 59 deletions(-) diff --git a/jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/MetaInfConfiguration.java b/jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/MetaInfConfiguration.java index 436127ed58c4..24a4091f6bb1 100644 --- a/jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/MetaInfConfiguration.java +++ b/jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/MetaInfConfiguration.java @@ -406,11 +406,16 @@ else if (LOG.isDebugEnabled()) else { // Resource represents a packed jar - URI uri = target.getURI(); - resourcesDir = resourceFactory.newResource(URIUtil.uriJarPrefix(uri, "!/META-INF/resources")); + Resource jarFileResource = resourceFactory.newJarFileResource(target.getURI()); + resourcesDir = jarFileResource.resolve("META-INF/resources"); } - if (Resources.isReadableDirectory(resourcesDir) && (cache != null)) + if (isEmptyResource(resourcesDir)) + { + return; + } + + if (cache != null) { Resource old = cache.putIfAbsent(target, resourcesDir); if (old != null) @@ -418,11 +423,6 @@ else if (LOG.isDebugEnabled()) else if (LOG.isDebugEnabled()) LOG.debug("{} META-INF/resources cache updated", target); } - - if (isEmptyResource(resourcesDir)) - { - return; - } } //add it to the meta inf resources for this context @@ -474,15 +474,17 @@ else if (LOG.isDebugEnabled()) LOG.debug("{} META-INF/web-fragment.xml checked", jar); if (jar.isDirectory()) { - webFrag = resourceFactory.newResource(jar.getPath().resolve("META-INF/web-fragment.xml")); + webFrag = jar.resolve("META-INF/web-fragment.xml"); } else { - URI uri = jar.getURI(); - webFrag = resourceFactory.newResource(URIUtil.uriJarPrefix(uri, "!/META-INF/web-fragment.xml")); + webFrag = resourceFactory.newJarFileResource(jar.getURI()).resolve("META-INF/web-fragment.xml"); } - if (Resources.isReadable(webFrag) && (cache != null)) + if (isEmptyFragment(webFrag)) + return; + + if (cache != null) { //web-fragment.xml doesn't exist: put token in cache to signal we've seen the jar Resource old = cache.putIfAbsent(jar, webFrag); @@ -491,9 +493,6 @@ else if (LOG.isDebugEnabled()) else if (LOG.isDebugEnabled()) LOG.debug("{} META-INF/web-fragment.xml cache updated", jar); } - - if (isEmptyFragment(webFrag)) - return; } Map fragments = (Map)context.getAttribute(METAINF_FRAGMENTS); @@ -627,20 +626,23 @@ private Collection getTlds(Path dir) throws IOException private Collection getTlds(WebAppContext context, URI uri) throws IOException { HashSet tlds = new HashSet<>(); - Resource r = ResourceFactory.of(context).newResource(URIUtil.uriJarPrefix(uri, "!/")); - try (Stream stream = Files.walk(r.getPath())) + try (ResourceFactory.Closeable closeableResourceFactory = ResourceFactory.closeable()) { - Iterator it = stream - .filter(Files::isRegularFile) - .filter(FileID::isTld) - .iterator(); - while (it.hasNext()) + Resource closeableResource = closeableResourceFactory.newJarFileResource(uri); + try (Stream stream = Files.walk(closeableResource.getPath())) { - Path entry = it.next(); - tlds.add(entry.toUri().toURL()); + Iterator it = stream + .filter(Files::isRegularFile) + .filter(FileID::isTld) + .iterator(); + while (it.hasNext()) + { + Path entry = it.next(); + tlds.add(entry.toUri().toURL()); + } } + return tlds; } - return tlds; } protected List findClassDirs(WebAppContext context) diff --git a/jetty-ee9/jetty-ee9-webapp/src/main/java/org/eclipse/jetty/ee9/webapp/MetaInfConfiguration.java b/jetty-ee9/jetty-ee9-webapp/src/main/java/org/eclipse/jetty/ee9/webapp/MetaInfConfiguration.java index e09e6d8e445c..1367e42886aa 100644 --- a/jetty-ee9/jetty-ee9-webapp/src/main/java/org/eclipse/jetty/ee9/webapp/MetaInfConfiguration.java +++ b/jetty-ee9/jetty-ee9-webapp/src/main/java/org/eclipse/jetty/ee9/webapp/MetaInfConfiguration.java @@ -88,8 +88,6 @@ public class MetaInfConfiguration extends AbstractConfiguration */ public static final String RESOURCE_DIRS = "org.eclipse.jetty.resources"; - private ResourceFactory.Closeable _resourceFactory; - public MetaInfConfiguration() { addDependencies(WebXmlConfiguration.class); @@ -98,8 +96,6 @@ public MetaInfConfiguration() @Override public void preConfigure(final WebAppContext context) throws Exception { - _resourceFactory = ResourceFactory.closeable(); - //find container jars/modules and select which ones to scan findAndFilterContainerPaths(context); @@ -115,8 +111,6 @@ public void preConfigure(final WebAppContext context) throws Exception @Override public void deconfigure(WebAppContext context) throws Exception { - IO.close(_resourceFactory); - _resourceFactory = null; super.deconfigure(context); } @@ -143,12 +137,14 @@ public void findAndFilterContainerPaths(final WebAppContext context) throws Exce if (StringUtil.isBlank(pattern)) return; // TODO review if this short cut will allow later code simplifications + ResourceFactory resourceFactory = ResourceFactory.of(context); + // Apply an initial name filter to the jars to select which will be eventually // scanned for META-INF info and annotations. The filter is based on inclusion patterns. UriPatternPredicate uriPatternPredicate = new UriPatternPredicate(pattern, false); Consumer addContainerResource = (uri) -> { - Resource resource = _resourceFactory.newResource(uri); + Resource resource = resourceFactory.newResource(uri); if (Resources.missing(resource)) { if (LOG.isDebugEnabled()) @@ -197,14 +193,14 @@ public void findAndFilterContainerPaths(final WebAppContext context) throws Exce { for (Path listEntry: listing.toList()) { - Resource resource = _resourceFactory.newResource(listEntry); + Resource resource = resourceFactory.newResource(listEntry); context.getMetaData().addContainerResource(resource); } } } else { - Resource resource = _resourceFactory.newResource(path); + Resource resource = resourceFactory.newResource(path); context.getMetaData().addContainerResource(resource); } } @@ -390,6 +386,8 @@ public void scanForResources(WebAppContext context, Resource target, ConcurrentH if (target == null) return; + ResourceFactory resourceFactory = ResourceFactory.of(context); + Resource resourcesDir = null; if (cache != null && cache.containsKey(target)) { @@ -416,11 +414,15 @@ else if (LOG.isDebugEnabled()) else { // Resource represents a packed jar - URI uri = target.getURI(); - resourcesDir = _resourceFactory.newResource(URIUtil.uriJarPrefix(uri, "!/META-INF/resources")); + resourcesDir = resourceFactory.newJarFileResource(target.getURI()).resolve("META-INF/resources"); } - if (Resources.isReadableDirectory(resourcesDir) && (cache != null)) + if (isEmptyResource(resourcesDir)) + { + return; + } + + if (cache != null) { Resource old = cache.putIfAbsent(target, resourcesDir); if (old != null) @@ -428,11 +430,6 @@ else if (LOG.isDebugEnabled()) else if (LOG.isDebugEnabled()) LOG.debug("{} META-INF/resources cache updated", target); } - - if (isEmptyResource(resourcesDir)) - { - return; - } } //add it to the meta inf resources for this context @@ -463,6 +460,7 @@ private static boolean isEmptyResource(Resource resourcesDir) public void scanForFragment(WebAppContext context, Resource jar, ConcurrentHashMap cache) { Resource webFrag = null; + ResourceFactory resourceFactory = ResourceFactory.of(context); if (cache != null && cache.containsKey(jar)) { webFrag = cache.get(jar); @@ -482,26 +480,24 @@ else if (LOG.isDebugEnabled()) LOG.debug("{} META-INF/web-fragment.xml checked", jar); if (jar.isDirectory()) { - webFrag = _resourceFactory.newResource(jar.getPath().resolve("META-INF/web-fragment.xml")); + webFrag = jar.resolve("META-INF/web-fragment.xml"); } else { - URI uri = jar.getURI(); - webFrag = _resourceFactory.newResource(URIUtil.uriJarPrefix(uri, "!/META-INF/web-fragment.xml")); + webFrag = resourceFactory.newJarFileResource(jar.getURI()).resolve("META-INF/web-fragment.xml"); } - if ((webFrag != null) && (cache != null)) + if (isEmptyFragment(webFrag)) + return; + + if (cache != null) { - //web-fragment.xml doesn't exist: put token in cache to signal we've seen the jar Resource old = cache.putIfAbsent(jar, webFrag); if (old != null) webFrag = old; else if (LOG.isDebugEnabled()) LOG.debug("{} META-INF/web-fragment.xml cache updated", jar); } - - if (isEmptyFragment(webFrag)) - return; } Map fragments = (Map)context.getAttribute(METAINF_FRAGMENTS); @@ -635,17 +631,20 @@ public Collection getTlds(Path dir) throws IOException public Collection getTlds(URI uri) throws IOException { HashSet tlds = new HashSet<>(); - Resource r = _resourceFactory.newResource(URIUtil.uriJarPrefix(uri, "!/")); - try (Stream stream = Files.walk(r.getPath())) + try (ResourceFactory.Closeable factory = ResourceFactory.closeable()) { - Iterator it = stream - .filter(Files::isRegularFile) - .filter(FileID::isTld) - .iterator(); - while (it.hasNext()) + Resource r = factory.newJarFileResource(uri); + try (Stream stream = Files.walk(r.getPath())) { - Path entry = it.next(); - tlds.add(entry.toUri().toURL()); + Iterator it = stream + .filter(Files::isRegularFile) + .filter(FileID::isTld) + .iterator(); + while (it.hasNext()) + { + Path entry = it.next(); + tlds.add(entry.toUri().toURL()); + } } } return tlds; From 2aa8f34b02df9861c40195edfcd02849e6f70aca Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Tue, 14 Nov 2023 16:55:55 +1100 Subject: [PATCH 2/7] Use better ResourceFactory regime to reduce references --- .../ee10/webapp/MetaInfConfiguration.java | 269 +++++++++-------- .../ee9/webapp/MetaInfConfiguration.java | 271 +++++++++--------- 2 files changed, 258 insertions(+), 282 deletions(-) diff --git a/jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/MetaInfConfiguration.java b/jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/MetaInfConfiguration.java index 24a4091f6bb1..1b93ebca78d4 100644 --- a/jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/MetaInfConfiguration.java +++ b/jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/MetaInfConfiguration.java @@ -378,64 +378,70 @@ public void scanForResources(WebAppContext context, Resource target, ConcurrentH // Resource target does not exist if (Resources.missing(target)) return; - ResourceFactory resourceFactory = ResourceFactory.of(context); - Resource resourcesDir; - if (cache != null && cache.containsKey(target)) - { - resourcesDir = cache.get(target); - if (isEmptyResource(resourcesDir)) - { - if (LOG.isDebugEnabled()) - LOG.debug("{} cached as containing no META-INF/resources", target); - return; - } - else if (LOG.isDebugEnabled()) - LOG.debug("{} META-INF/resources found in cache ", target); - } - else - { - //not using caches or not in the cache so check for the resources dir - if (LOG.isDebugEnabled()) - LOG.debug("{} META-INF/resources checked", target); - if (target.isDirectory()) - { - //TODO think how to handle an unpacked jar file (eg for osgi) - resourcesDir = target.resolve("/META-INF/resources"); - } - else - { - // Resource represents a packed jar - Resource jarFileResource = resourceFactory.newJarFileResource(target.getURI()); - resourcesDir = jarFileResource.resolve("META-INF/resources"); - } - - if (isEmptyResource(resourcesDir)) - { - return; - } - - if (cache != null) - { - Resource old = cache.putIfAbsent(target, resourcesDir); - if (old != null) - resourcesDir = old; - else if (LOG.isDebugEnabled()) - LOG.debug("{} META-INF/resources cache updated", target); - } - } - - //add it to the meta inf resources for this context - Set dirs = (Set)context.getAttribute(METAINF_RESOURCES); - if (dirs == null) - { - dirs = new HashSet<>(); - context.setAttribute(METAINF_RESOURCES, dirs); - } - if (LOG.isDebugEnabled()) - LOG.debug("{} added to context", resourcesDir); - - dirs.add(resourcesDir); + try (ResourceFactory.Closeable closeable = ResourceFactory.closeable()) + { + Resource resourcesDir; + if (cache != null && cache.containsKey(target)) + { + resourcesDir = cache.get(target); + if (isEmptyResource(resourcesDir)) + { + if (LOG.isDebugEnabled()) + LOG.debug("{} cached as containing no META-INF/resources", target); + return; + } + else if (LOG.isDebugEnabled()) + LOG.debug("{} META-INF/resources found in cache ", target); + } + else + { + //not using caches or not in the cache so check for the resources dir + if (LOG.isDebugEnabled()) + LOG.debug("{} META-INF/resources checked", target); + if (target.isDirectory()) + { + //TODO think how to handle an unpacked jar file (eg for osgi) + resourcesDir = target.resolve("/META-INF/resources"); + } + else + { + // Resource represents a packed jar + Resource jarFileResource = closeable.newJarFileResource(target.getURI()); + resourcesDir = jarFileResource.resolve("META-INF/resources"); + } + + if (isEmptyResource(resourcesDir)) + { + return; + } + + //convert our Resource reference to something associated with the context + //because it's lifecycle is the same as the context + resourcesDir = context.getResourceFactory().newResource(resourcesDir.getURI()); + + if (cache != null) + { + Resource old = cache.putIfAbsent(target, resourcesDir); + if (old != null) + resourcesDir = old; + else if (LOG.isDebugEnabled()) + LOG.debug("{} META-INF/resources cache updated", target); + } + } + + //add it to the meta inf resources for this context + Set dirs = (Set)context.getAttribute(METAINF_RESOURCES); + if (dirs == null) + { + dirs = new HashSet<>(); + context.setAttribute(METAINF_RESOURCES, dirs); + } + if (LOG.isDebugEnabled()) + LOG.debug("{} added to context", resourcesDir); + + dirs.add(resourcesDir); + } } private static boolean isEmptyResource(Resource resourcesDir) @@ -452,58 +458,64 @@ private static boolean isEmptyResource(Resource resourcesDir) */ public void scanForFragment(WebAppContext context, Resource jar, ConcurrentHashMap cache) { - ResourceFactory resourceFactory = ResourceFactory.of(context); - - Resource webFrag; - if (cache != null && cache.containsKey(jar)) + try (ResourceFactory.Closeable closeable = ResourceFactory.closeable()) { - webFrag = cache.get(jar); - if (isEmptyFragment(webFrag)) + Resource webFrag; + if (cache != null && cache.containsKey(jar)) { - if (LOG.isDebugEnabled()) - LOG.debug("{} cached as containing no META-INF/web-fragment.xml", jar); - return; - } - else if (LOG.isDebugEnabled()) - LOG.debug("{} META-INF/web-fragment.xml found in cache ", jar); - } - else - { - //not using caches or not in the cache so check for the web-fragment.xml - if (LOG.isDebugEnabled()) - LOG.debug("{} META-INF/web-fragment.xml checked", jar); - if (jar.isDirectory()) - { - webFrag = jar.resolve("META-INF/web-fragment.xml"); + webFrag = cache.get(jar); + if (isEmptyFragment(webFrag)) + { + if (LOG.isDebugEnabled()) + LOG.debug("{} cached as containing no META-INF/web-fragment.xml", jar); + return; + } + else if (LOG.isDebugEnabled()) + LOG.debug("{} META-INF/web-fragment.xml found in cache ", jar); } else { - webFrag = resourceFactory.newJarFileResource(jar.getURI()).resolve("META-INF/web-fragment.xml"); - } + //not using caches or not in the cache so check for the web-fragment.xml + if (LOG.isDebugEnabled()) + LOG.debug("{} META-INF/web-fragment.xml checked", jar); - if (isEmptyFragment(webFrag)) - return; + Resource tmp; + if (jar.isDirectory()) + { + tmp = jar.resolve("META-INF/web-fragment.xml"); + } + else + { + tmp = closeable.newJarFileResource(jar.getURI()).resolve("META-INF/web-fragment.xml"); + } - if (cache != null) - { - //web-fragment.xml doesn't exist: put token in cache to signal we've seen the jar - Resource old = cache.putIfAbsent(jar, webFrag); - if (old != null) - webFrag = old; - else if (LOG.isDebugEnabled()) - LOG.debug("{} META-INF/web-fragment.xml cache updated", jar); + if (isEmptyFragment(tmp)) + return; + + //convert the ephemeral Resource reference for the fragment into a Resource + //associated with the context lifecycle + webFrag = context.getResourceFactory().newResource(tmp.getURI()); + if (cache != null) + { + //web-fragment.xml doesn't exist: put token in cache to signal we've seen the jar + Resource old = cache.putIfAbsent(jar, webFrag); + if (old != null) + webFrag = old; + else if (LOG.isDebugEnabled()) + LOG.debug("{} META-INF/web-fragment.xml cache updated", jar); + } } - } - Map fragments = (Map)context.getAttribute(METAINF_FRAGMENTS); - if (fragments == null) - { - fragments = new HashMap<>(); - context.setAttribute(METAINF_FRAGMENTS, fragments); + Map fragments = (Map)context.getAttribute(METAINF_FRAGMENTS); + if (fragments == null) + { + fragments = new HashMap<>(); + context.setAttribute(METAINF_FRAGMENTS, fragments); + } + fragments.put(jar, webFrag); + if (LOG.isDebugEnabled()) + LOG.debug("{} added to context", webFrag); } - fragments.put(jar, webFrag); - if (LOG.isDebugEnabled()) - LOG.debug("{} added to context", webFrag); } private static boolean isEmptyFragment(Resource webFrag) @@ -544,15 +556,7 @@ public void scanForTlds(WebAppContext context, Resource jar, ConcurrentHashMap(); - if (jar.isDirectory()) - { - tlds.addAll(getTlds(jar.getPath())); - } - else - { - URI uri = jar.getURI(); - tlds.addAll(getTlds(context, uri)); - } + tlds.addAll(getTlds(context, jar)); if (cache != null) { @@ -588,48 +592,33 @@ public void postConfigure(WebAppContext context) throws Exception context.setAttribute(METAINF_TLDS, null); } - /** - * Find all .tld files in all subdirs of the given dir. - * - * @param dir the directory to scan - * @return the list of tlds found - * @throws IOException if unable to scan the directory - */ - private Collection getTlds(Path dir) throws IOException - { - if (dir == null || !Files.isDirectory(dir)) - return Collections.emptySet(); - - Set tlds = new HashSet<>(); - - try (Stream entries = Files.walk(dir) - .filter(Files::isRegularFile) - .filter(FileID::isTld)) - { - Iterator iter = entries.iterator(); - while (iter.hasNext()) - { - Path entry = iter.next(); - tlds.add(entry.toUri().toURL()); - } - } - return tlds; - } - /** * Find all .tld files in the given jar. * - * @param uri the uri to jar file + * @param resource the jar file * @return the collection of tlds as url references * @throws IOException if unable to scan the jar file */ - private Collection getTlds(WebAppContext context, URI uri) throws IOException + private Collection getTlds(WebAppContext context, Resource resource) throws IOException { HashSet tlds = new HashSet<>(); + Resource resourceDir; + try (ResourceFactory.Closeable closeableResourceFactory = ResourceFactory.closeable()) { - Resource closeableResource = closeableResourceFactory.newJarFileResource(uri); - try (Stream stream = Files.walk(closeableResource.getPath())) + if (!resource.isDirectory()) + { + //turn it into a jar:file + resourceDir = closeableResourceFactory.newJarFileResource(resource.getURI()); + } + else + resourceDir = resource; + + Resource metaInf = resourceDir.resolve("META-INF"); + if (!metaInf.isDirectory()) + return tlds; //no tlds + + try (Stream stream = Files.walk(metaInf.getPath())) { Iterator it = stream .filter(Files::isRegularFile) diff --git a/jetty-ee9/jetty-ee9-webapp/src/main/java/org/eclipse/jetty/ee9/webapp/MetaInfConfiguration.java b/jetty-ee9/jetty-ee9-webapp/src/main/java/org/eclipse/jetty/ee9/webapp/MetaInfConfiguration.java index 1367e42886aa..2fc388861533 100644 --- a/jetty-ee9/jetty-ee9-webapp/src/main/java/org/eclipse/jetty/ee9/webapp/MetaInfConfiguration.java +++ b/jetty-ee9/jetty-ee9-webapp/src/main/java/org/eclipse/jetty/ee9/webapp/MetaInfConfiguration.java @@ -386,63 +386,68 @@ public void scanForResources(WebAppContext context, Resource target, ConcurrentH if (target == null) return; - ResourceFactory resourceFactory = ResourceFactory.of(context); - - Resource resourcesDir = null; - if (cache != null && cache.containsKey(target)) - { - resourcesDir = cache.get(target); - if (isEmptyResource(resourcesDir)) - { - if (LOG.isDebugEnabled()) - LOG.debug("{} cached as containing no META-INF/resources", target); - return; - } - else if (LOG.isDebugEnabled()) - LOG.debug("{} META-INF/resources found in cache ", target); - } - else - { - //not using caches or not in the cache so check for the resources dir - if (LOG.isDebugEnabled()) - LOG.debug("{} META-INF/resources checked", target); - if (target.isDirectory()) - { - //TODO think how to handle an unpacked jar file (eg for osgi) - resourcesDir = target.resolve("/META-INF/resources"); - } - else - { - // Resource represents a packed jar - resourcesDir = resourceFactory.newJarFileResource(target.getURI()).resolve("META-INF/resources"); - } - - if (isEmptyResource(resourcesDir)) - { - return; - } - - if (cache != null) - { - Resource old = cache.putIfAbsent(target, resourcesDir); - if (old != null) - resourcesDir = old; - else if (LOG.isDebugEnabled()) - LOG.debug("{} META-INF/resources cache updated", target); - } - } - - //add it to the meta inf resources for this context - Set dirs = (Set)context.getAttribute(METAINF_RESOURCES); - if (dirs == null) - { - dirs = new HashSet(); - context.setAttribute(METAINF_RESOURCES, dirs); - } - if (LOG.isDebugEnabled()) - LOG.debug("{} added to context", resourcesDir); - - dirs.add(resourcesDir); + try (ResourceFactory.Closeable closeable = ResourceFactory.closeable()) + { + Resource resourcesDir = null; + + if (cache != null && cache.containsKey(target)) + { + resourcesDir = cache.get(target); + if (isEmptyResource(resourcesDir)) + { + if (LOG.isDebugEnabled()) + LOG.debug("{} cached as containing no META-INF/resources", target); + return; + } + else if (LOG.isDebugEnabled()) + LOG.debug("{} META-INF/resources found in cache ", target); + } + else + { + //not using caches or not in the cache so check for the resources dir + if (LOG.isDebugEnabled()) + LOG.debug("{} META-INF/resources checked", target); + if (target.isDirectory()) + { + //TODO think how to handle an unpacked jar file (eg for osgi) + resourcesDir = target.resolve("/META-INF/resources"); + } + else + { + // Resource represents a packed jar + resourcesDir = closeable.newJarFileResource(target.getURI()).resolve("META-INF/resources"); + } + + if (isEmptyResource(resourcesDir)) + { + return; + } + + //convert to a Resource tied to the Context lifecycle + resourcesDir = context.getResourceFactory().newResource(resourcesDir.getURI()); + + if (cache != null) + { + Resource old = cache.putIfAbsent(target, resourcesDir); + if (old != null) + resourcesDir = old; + else if (LOG.isDebugEnabled()) + LOG.debug("{} META-INF/resources cache updated", target); + } + } + + //add it to the meta inf resources for this context + Set dirs = (Set)context.getAttribute(METAINF_RESOURCES); + if (dirs == null) + { + dirs = new HashSet(); + context.setAttribute(METAINF_RESOURCES, dirs); + } + if (LOG.isDebugEnabled()) + LOG.debug("{} added to context", resourcesDir); + + dirs.add(resourcesDir); + } } private static boolean isEmptyResource(Resource resourcesDir) @@ -460,55 +465,60 @@ private static boolean isEmptyResource(Resource resourcesDir) public void scanForFragment(WebAppContext context, Resource jar, ConcurrentHashMap cache) { Resource webFrag = null; - ResourceFactory resourceFactory = ResourceFactory.of(context); - if (cache != null && cache.containsKey(jar)) + try (ResourceFactory.Closeable closeable = ResourceFactory.closeable()) { - webFrag = cache.get(jar); - if (isEmptyFragment(webFrag)) + if (cache != null && cache.containsKey(jar)) { - if (LOG.isDebugEnabled()) - LOG.debug("{} cached as containing no META-INF/web-fragment.xml", jar); - return; - } - else if (LOG.isDebugEnabled()) - LOG.debug("{} META-INF/web-fragment.xml found in cache ", jar); - } - else - { - //not using caches or not in the cache so check for the web-fragment.xml - if (LOG.isDebugEnabled()) - LOG.debug("{} META-INF/web-fragment.xml checked", jar); - if (jar.isDirectory()) - { - webFrag = jar.resolve("META-INF/web-fragment.xml"); + webFrag = cache.get(jar); + if (isEmptyFragment(webFrag)) + { + if (LOG.isDebugEnabled()) + LOG.debug("{} cached as containing no META-INF/web-fragment.xml", jar); + return; + } + else if (LOG.isDebugEnabled()) + LOG.debug("{} META-INF/web-fragment.xml found in cache ", jar); } else { - webFrag = resourceFactory.newJarFileResource(jar.getURI()).resolve("META-INF/web-fragment.xml"); - } + //not using caches or not in the cache so check for the web-fragment.xml + if (LOG.isDebugEnabled()) + LOG.debug("{} META-INF/web-fragment.xml checked", jar); + if (jar.isDirectory()) + { + webFrag = jar.resolve("META-INF/web-fragment.xml"); + } + else + { + webFrag = closeable.newJarFileResource(jar.getURI()).resolve("META-INF/web-fragment.xml"); + } - if (isEmptyFragment(webFrag)) - return; + if (isEmptyFragment(webFrag)) + return; - if (cache != null) - { - Resource old = cache.putIfAbsent(jar, webFrag); - if (old != null) - webFrag = old; - else if (LOG.isDebugEnabled()) - LOG.debug("{} META-INF/web-fragment.xml cache updated", jar); + //convert webFragment Resource to one tied to the Context lifecycle + webFrag = context.getResourceFactory().newResource(webFrag.getURI()); + + if (cache != null) + { + Resource old = cache.putIfAbsent(jar, webFrag); + if (old != null) + webFrag = old; + else if (LOG.isDebugEnabled()) + LOG.debug("{} META-INF/web-fragment.xml cache updated", jar); + } } - } - Map fragments = (Map)context.getAttribute(METAINF_FRAGMENTS); - if (fragments == null) - { - fragments = new HashMap(); - context.setAttribute(METAINF_FRAGMENTS, fragments); + Map fragments = (Map)context.getAttribute(METAINF_FRAGMENTS); + if (fragments == null) + { + fragments = new HashMap(); + context.setAttribute(METAINF_FRAGMENTS, fragments); + } + fragments.put(jar, webFrag); + if (LOG.isDebugEnabled()) + LOG.debug("{} added to context", webFrag); } - fragments.put(jar, webFrag); - if (LOG.isDebugEnabled()) - LOG.debug("{} added to context", webFrag); } private static boolean isEmptyFragment(Resource webFrag) @@ -527,7 +537,7 @@ private static boolean isEmptyFragment(Resource webFrag) public void scanForTlds(WebAppContext context, Resource jar, ConcurrentHashMap> cache) throws Exception { - Collection tlds = null; + Collection tlds; if (cache != null && cache.containsKey(jar)) { @@ -549,21 +559,13 @@ public void scanForTlds(WebAppContext context, Resource jar, ConcurrentHashMap(); - if (jar.isDirectory()) - { - tlds.addAll(getTlds(jar.getPath())); - } - else - { - URI uri = jar.getURI(); - tlds.addAll(getTlds(uri)); - } + tlds.addAll(getTlds(context, jar)); if (cache != null) { if (LOG.isDebugEnabled()) LOG.debug("{} tld cache updated", jar); - Collection old = (Collection)cache.putIfAbsent(jar, tlds); + Collection old = cache.putIfAbsent(jar, tlds); if (old != null) tlds = old; } @@ -575,7 +577,7 @@ public void scanForTlds(WebAppContext context, Resource jar, ConcurrentHashMap metaInfTlds = (Collection)context.getAttribute(METAINF_TLDS); if (metaInfTlds == null) { - metaInfTlds = new HashSet(); + metaInfTlds = new HashSet<>(); context.setAttribute(METAINF_TLDS, metaInfTlds); } metaInfTlds.addAll(tlds); @@ -593,48 +595,33 @@ public void postConfigure(WebAppContext context) throws Exception context.setAttribute(METAINF_TLDS, null); } - /** - * Find all .tld files in all subdirs of the given dir. - * - * @param dir the directory to scan - * @return the list of tlds found - * @throws IOException if unable to scan the directory - */ - public Collection getTlds(Path dir) throws IOException - { - if (dir == null || !Files.isDirectory(dir)) - return Collections.emptySet(); - - Set tlds = new HashSet<>(); - - try (Stream entries = Files.walk(dir) - .filter(Files::isRegularFile) - .filter(FileID::isTld)) - { - Iterator iter = entries.iterator(); - while (iter.hasNext()) - { - Path entry = iter.next(); - tlds.add(entry.toUri().toURL()); - } - } - return tlds; - } - /** * Find all .tld files in the given jar. * - * @param uri the uri to jar file + * @param resource the jar file * @return the collection of tlds as url references * @throws IOException if unable to scan the jar file */ - public Collection getTlds(URI uri) throws IOException + private Collection getTlds(WebAppContext context, Resource resource) throws IOException { HashSet tlds = new HashSet<>(); - try (ResourceFactory.Closeable factory = ResourceFactory.closeable()) + Resource resourceDir; + + try (ResourceFactory.Closeable closeableResourceFactory = ResourceFactory.closeable()) { - Resource r = factory.newJarFileResource(uri); - try (Stream stream = Files.walk(r.getPath())) + if (!resource.isDirectory()) + { + //turn it into a jar:file + resourceDir = closeableResourceFactory.newJarFileResource(resource.getURI()); + } + else + resourceDir = resource; + + Resource metaInf = resourceDir.resolve("META-INF"); + if (!metaInf.isDirectory()) + return tlds; //no tlds + + try (Stream stream = Files.walk(metaInf.getPath())) { Iterator it = stream .filter(Files::isRegularFile) @@ -646,8 +633,8 @@ public Collection getTlds(URI uri) throws IOException tlds.add(entry.toUri().toURL()); } } + return tlds; } - return tlds; } protected List findClassDirs(WebAppContext context) From 4feecd92ddd752b0d79c08f89c02c86bb6bb9e3f Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Wed, 15 Nov 2023 08:22:18 +1100 Subject: [PATCH 3/7] Fix --- .../java/org/eclipse/jetty/ee9/webapp/MetaInfConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jetty-ee9/jetty-ee9-webapp/src/main/java/org/eclipse/jetty/ee9/webapp/MetaInfConfiguration.java b/jetty-ee9/jetty-ee9-webapp/src/main/java/org/eclipse/jetty/ee9/webapp/MetaInfConfiguration.java index 2fc388861533..3c6178fa5dff 100644 --- a/jetty-ee9/jetty-ee9-webapp/src/main/java/org/eclipse/jetty/ee9/webapp/MetaInfConfiguration.java +++ b/jetty-ee9/jetty-ee9-webapp/src/main/java/org/eclipse/jetty/ee9/webapp/MetaInfConfiguration.java @@ -618,7 +618,7 @@ private Collection getTlds(WebAppContext context, Resource resource) throws resourceDir = resource; Resource metaInf = resourceDir.resolve("META-INF"); - if (!metaInf.isDirectory()) + if (isEmptyResource(metaInf)) return tlds; //no tlds try (Stream stream = Files.walk(metaInf.getPath())) From 19ed557c65bf3fde913bd010c54e0e18016700f7 Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Wed, 15 Nov 2023 09:48:03 +1100 Subject: [PATCH 4/7] Fix --- .../ee10/webapp/MetaInfConfiguration.java | 336 +++++++++--------- .../ee9/webapp/MetaInfConfiguration.java | 324 +++++++++-------- 2 files changed, 323 insertions(+), 337 deletions(-) diff --git a/jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/MetaInfConfiguration.java b/jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/MetaInfConfiguration.java index 1b93ebca78d4..1c049c1f12c1 100644 --- a/jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/MetaInfConfiguration.java +++ b/jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/MetaInfConfiguration.java @@ -24,7 +24,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -40,6 +39,7 @@ import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.UriPatternPredicate; +import org.eclipse.jetty.util.resource.MountedPathResource; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.ResourceCollators; import org.eclipse.jetty.util.resource.ResourceFactory; @@ -173,18 +173,18 @@ public void findAndFilterContainerPaths(final WebAppContext context) throws Exce if (modulePath != null) { List matchingBasePaths = - Stream.of(modulePath.split(File.pathSeparator)) - .map(URIUtil::toURI) - .filter(uriPatternPredicate) - .map(Paths::get) - .toList(); - for (Path path: matchingBasePaths) + Stream.of(modulePath.split(File.pathSeparator)) + .map(URIUtil::toURI) + .filter(uriPatternPredicate) + .map(Paths::get) + .toList(); + for (Path path : matchingBasePaths) { if (Files.isDirectory(path)) { try (Stream listing = Files.list(path)) { - for (Path listEntry: listing.toList()) + for (Path listEntry : listing.toList()) { Resource resource = resourceFactory.newResource(listEntry); context.getMetaData().addContainerResource(resource); @@ -354,94 +354,99 @@ public void scanJars(final WebAppContext context, Collection jars, boo //Scan jars for META-INF information if (jars != null) { - for (Resource r : jars) + try (ResourceFactory.Closeable closeable = ResourceFactory.closeable()) { - if (scanTypes.contains(METAINF_RESOURCES)) - scanForResources(context, r, metaInfResourceCache); - if (scanTypes.contains(METAINF_FRAGMENTS)) - scanForFragment(context, r, metaInfFragmentCache); - if (scanTypes.contains(METAINF_TLDS)) - scanForTlds(context, r, metaInfTldCache); + for (Resource r : jars) + { + Resource dir = r; + + try + { + if (!dir.isDirectory()) + dir = closeable.newJarFileResource(dir.getURI()); + } + catch (Exception e) + { + //not an appropriate uri, skip it + continue; + } + + if (isEmptyResource(dir)) + continue; + + if (scanTypes.contains(METAINF_RESOURCES)) + scanForResources(context, dir, metaInfResourceCache); + if (scanTypes.contains(METAINF_FRAGMENTS)) + scanForFragment(context, dir, metaInfFragmentCache); + if (scanTypes.contains(METAINF_TLDS)) + scanForTlds(context, dir, metaInfTldCache); + } } } } /** - * Scan for META-INF/resources dir in the given jar. + * Scan for META-INF/resources dir in the given directory. * * @param context the context for the scan - * @param target the target resource to scan for + * @param dir the target directory to scan * @param cache the resource cache */ - public void scanForResources(WebAppContext context, Resource target, ConcurrentHashMap cache) + public void scanForResources(WebAppContext context, Resource dir, ConcurrentHashMap cache) { // Resource target does not exist - if (Resources.missing(target)) + if (isEmptyResource(dir)) return; - try (ResourceFactory.Closeable closeable = ResourceFactory.closeable()) - { - Resource resourcesDir; - if (cache != null && cache.containsKey(target)) - { - resourcesDir = cache.get(target); - if (isEmptyResource(resourcesDir)) - { - if (LOG.isDebugEnabled()) - LOG.debug("{} cached as containing no META-INF/resources", target); - return; - } - else if (LOG.isDebugEnabled()) - LOG.debug("{} META-INF/resources found in cache ", target); - } - else - { - //not using caches or not in the cache so check for the resources dir - if (LOG.isDebugEnabled()) - LOG.debug("{} META-INF/resources checked", target); - if (target.isDirectory()) - { - //TODO think how to handle an unpacked jar file (eg for osgi) - resourcesDir = target.resolve("/META-INF/resources"); - } - else - { - // Resource represents a packed jar - Resource jarFileResource = closeable.newJarFileResource(target.getURI()); - resourcesDir = jarFileResource.resolve("META-INF/resources"); - } - - if (isEmptyResource(resourcesDir)) - { - return; - } - - //convert our Resource reference to something associated with the context - //because it's lifecycle is the same as the context - resourcesDir = context.getResourceFactory().newResource(resourcesDir.getURI()); - - if (cache != null) - { - Resource old = cache.putIfAbsent(target, resourcesDir); - if (old != null) - resourcesDir = old; - else if (LOG.isDebugEnabled()) - LOG.debug("{} META-INF/resources cache updated", target); - } - } - - //add it to the meta inf resources for this context - Set dirs = (Set)context.getAttribute(METAINF_RESOURCES); - if (dirs == null) - { - dirs = new HashSet<>(); - context.setAttribute(METAINF_RESOURCES, dirs); - } - if (LOG.isDebugEnabled()) - LOG.debug("{} added to context", resourcesDir); - - dirs.add(resourcesDir); - } + Resource resourcesDir = null; + + if (cache != null && cache.containsKey(dir)) + { + resourcesDir = cache.get(dir); + if (isEmptyResource(resourcesDir)) + { + if (LOG.isDebugEnabled()) + LOG.debug("{} cached as containing no META-INF/resources", dir); + return; + } + else if (LOG.isDebugEnabled()) + LOG.debug("{} META-INF/resources found in cache ", dir); + } + else + { + //not using caches or not in the cache so check for the resources dir + if (LOG.isDebugEnabled()) + LOG.debug("{} META-INF/resources checked", dir); + + resourcesDir = dir.resolve("/META-INF/resources"); + + if (isEmptyResource(resourcesDir)) + return; + + //convert to a Resource tied to the Context lifecycle + resourcesDir = context.getResourceFactory().newResource(resourcesDir.getURI()); + + if (cache != null) + { + Resource old = cache.putIfAbsent(dir, resourcesDir); + if (old != null) + resourcesDir = old; + else if (LOG.isDebugEnabled()) + LOG.debug("{} META-INF/resources cache updated", dir); + } + } + + //add it to the meta inf resources for this context + Set dirs = (Set)context.getAttribute(METAINF_RESOURCES); + if (dirs == null) + { + dirs = new HashSet(); + context.setAttribute(METAINF_RESOURCES, dirs); + } + if (LOG.isDebugEnabled()) + LOG.debug("{} added to context", resourcesDir); + + dirs.add(resourcesDir); } private static boolean isEmptyResource(Resource resourcesDir) @@ -450,72 +455,71 @@ private static boolean isEmptyResource(Resource resourcesDir) } /** - * Scan for META-INF/web-fragment.xml file in the given jar. + * Scan for META-INF/web-fragment.xml file in the given directory. * * @param context the context for the scan - * @param jar the jar resource to scan for fragments in + * @param dir the dir to scan for fragments * @param cache the resource cache */ - public void scanForFragment(WebAppContext context, Resource jar, ConcurrentHashMap cache) + public void scanForFragment(WebAppContext context, Resource dir, ConcurrentHashMap cache) { - try (ResourceFactory.Closeable closeable = ResourceFactory.closeable()) + Resource webFrag = null; + if (cache != null && cache.containsKey(dir)) { - Resource webFrag; - if (cache != null && cache.containsKey(jar)) + webFrag = cache.get(dir); + if (isEmptyFragment(webFrag)) { - webFrag = cache.get(jar); - if (isEmptyFragment(webFrag)) - { - if (LOG.isDebugEnabled()) - LOG.debug("{} cached as containing no META-INF/web-fragment.xml", jar); - return; - } - else if (LOG.isDebugEnabled()) - LOG.debug("{} META-INF/web-fragment.xml found in cache ", jar); - } - else - { - //not using caches or not in the cache so check for the web-fragment.xml if (LOG.isDebugEnabled()) - LOG.debug("{} META-INF/web-fragment.xml checked", jar); + LOG.debug("{} cached as containing no META-INF/web-fragment.xml", dir); + return; + } + else if (LOG.isDebugEnabled()) + LOG.debug("{} META-INF/web-fragment.xml found in cache ", dir); + } + else + { + //not using caches or not in the cache so check for the web-fragment.xml + if (LOG.isDebugEnabled()) + LOG.debug("{} META-INF/web-fragment.xml checked", dir); - Resource tmp; - if (jar.isDirectory()) - { - tmp = jar.resolve("META-INF/web-fragment.xml"); - } - else - { - tmp = closeable.newJarFileResource(jar.getURI()).resolve("META-INF/web-fragment.xml"); - } + Resource metaInf = dir.resolve("META-INF"); + if (isEmptyResource(metaInf)) + return; - if (isEmptyFragment(tmp)) - return; + webFrag = metaInf.resolve("web-fragment.xml"); - //convert the ephemeral Resource reference for the fragment into a Resource - //associated with the context lifecycle - webFrag = context.getResourceFactory().newResource(tmp.getURI()); - if (cache != null) - { - //web-fragment.xml doesn't exist: put token in cache to signal we've seen the jar - Resource old = cache.putIfAbsent(jar, webFrag); - if (old != null) - webFrag = old; - else if (LOG.isDebugEnabled()) - LOG.debug("{} META-INF/web-fragment.xml cache updated", jar); - } - } + if (isEmptyFragment(webFrag)) + return; + + //convert webFragment Resource to one tied to the Context lifecycle + webFrag = context.getResourceFactory().newResource(webFrag.getURI()); - Map fragments = (Map)context.getAttribute(METAINF_FRAGMENTS); - if (fragments == null) + if (cache != null) { - fragments = new HashMap<>(); - context.setAttribute(METAINF_FRAGMENTS, fragments); + Resource old = cache.putIfAbsent(dir, webFrag); + if (old != null) + webFrag = old; + else if (LOG.isDebugEnabled()) + LOG.debug("{} META-INF/web-fragment.xml cache updated", dir); } - fragments.put(jar, webFrag); - if (LOG.isDebugEnabled()) - LOG.debug("{} added to context", webFrag); } + + Map fragments = (Map)context.getAttribute(METAINF_FRAGMENTS); + if (fragments == null) + { + fragments = new HashMap(); + context.setAttribute(METAINF_FRAGMENTS, fragments); + } + + if (dir instanceof MountedPathResource) + { + //ensure we get the original .jar rather than jar:file: + dir = context.getResourceFactory().newResource(((MountedPathResource)dir).getContainerPath()); + } + + fragments.put(dir, webFrag); + if (LOG.isDebugEnabled()) + LOG.debug("{} added to context", webFrag); } private static boolean isEmptyFragment(Resource webFrag) @@ -524,45 +528,45 @@ private static boolean isEmptyFragment(Resource webFrag) } /** - * Discover META-INF/*.tld files in the given jar + * Discover META-INF/*.tld files in the given directory * * @param context the context for the scan - * @param jar the jar resources to scan tlds for + * @param dir the directory resource to scan for .tlds * @param cache the resource cache - * @throws Exception if unable to scan for tlds + * @throws Exception if unable to scan for .tlds */ - public void scanForTlds(WebAppContext context, Resource jar, ConcurrentHashMap> cache) + public void scanForTlds(WebAppContext context, Resource dir, ConcurrentHashMap> cache) throws Exception { Collection tlds; - if (cache != null && cache.containsKey(jar)) + if (cache != null && cache.containsKey(dir)) { - Collection tmp = cache.get(jar); + Collection tmp = cache.get(dir); if (tmp.isEmpty()) { if (LOG.isDebugEnabled()) - LOG.debug("{} cached as containing no tlds", jar); + LOG.debug("{} cached as containing no tlds", dir); return; } else { tlds = tmp; if (LOG.isDebugEnabled()) - LOG.debug("{} tlds found in cache ", jar); + LOG.debug("{} tlds found in cache ", dir); } } else { //not using caches or not in the cache so find all tlds tlds = new HashSet<>(); - tlds.addAll(getTlds(context, jar)); + tlds.addAll(getTlds(context, dir)); if (cache != null) { if (LOG.isDebugEnabled()) - LOG.debug("{} tld cache updated", jar); - Collection old = cache.putIfAbsent(jar, tlds); + LOG.debug("{} tld cache updated", dir); + Collection old = cache.putIfAbsent(dir, tlds); if (old != null) tlds = old; } @@ -593,45 +597,33 @@ public void postConfigure(WebAppContext context) throws Exception } /** - * Find all .tld files in the given jar. + * Find all .tld files in the given directory. * - * @param resource the jar file + * @param dir the directory * @return the collection of tlds as url references * @throws IOException if unable to scan the jar file */ - private Collection getTlds(WebAppContext context, Resource resource) throws IOException + private Collection getTlds(WebAppContext context, Resource dir) throws IOException { HashSet tlds = new HashSet<>(); - Resource resourceDir; - try (ResourceFactory.Closeable closeableResourceFactory = ResourceFactory.closeable()) - { - if (!resource.isDirectory()) - { - //turn it into a jar:file - resourceDir = closeableResourceFactory.newJarFileResource(resource.getURI()); - } - else - resourceDir = resource; + Resource metaInf = dir.resolve("META-INF"); + if (isEmptyResource(metaInf)) + return tlds; //no tlds - Resource metaInf = resourceDir.resolve("META-INF"); - if (!metaInf.isDirectory()) - return tlds; //no tlds - - try (Stream stream = Files.walk(metaInf.getPath())) + try (Stream stream = Files.walk(metaInf.getPath())) + { + Iterator it = stream + .filter(Files::isRegularFile) + .filter(FileID::isTld) + .iterator(); + while (it.hasNext()) { - Iterator it = stream - .filter(Files::isRegularFile) - .filter(FileID::isTld) - .iterator(); - while (it.hasNext()) - { - Path entry = it.next(); - tlds.add(entry.toUri().toURL()); - } + Path entry = it.next(); + tlds.add(entry.toUri().toURL()); } - return tlds; } + return tlds; } protected List findClassDirs(WebAppContext context) diff --git a/jetty-ee9/jetty-ee9-webapp/src/main/java/org/eclipse/jetty/ee9/webapp/MetaInfConfiguration.java b/jetty-ee9/jetty-ee9-webapp/src/main/java/org/eclipse/jetty/ee9/webapp/MetaInfConfiguration.java index 3c6178fa5dff..456ca14e5570 100644 --- a/jetty-ee9/jetty-ee9-webapp/src/main/java/org/eclipse/jetty/ee9/webapp/MetaInfConfiguration.java +++ b/jetty-ee9/jetty-ee9-webapp/src/main/java/org/eclipse/jetty/ee9/webapp/MetaInfConfiguration.java @@ -24,7 +24,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -37,10 +36,10 @@ import java.util.stream.Stream; import org.eclipse.jetty.util.FileID; -import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.UriPatternPredicate; +import org.eclipse.jetty.util.resource.MountedPathResource; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.ResourceCollators; import org.eclipse.jetty.util.resource.ResourceFactory; @@ -180,18 +179,18 @@ public void findAndFilterContainerPaths(final WebAppContext context) throws Exce if (modulePath != null) { List matchingBasePaths = - Stream.of(modulePath.split(File.pathSeparator)) - .map(URIUtil::toURI) - .filter(uriPatternPredicate) - .map(Paths::get) - .toList(); - for (Path path: matchingBasePaths) + Stream.of(modulePath.split(File.pathSeparator)) + .map(URIUtil::toURI) + .filter(uriPatternPredicate) + .map(Paths::get) + .toList(); + for (Path path : matchingBasePaths) { if (Files.isDirectory(path)) { try (Stream listing = Files.list(path)) { - for (Path listEntry: listing.toList()) + for (Path listEntry : listing.toList()) { Resource resource = resourceFactory.newResource(listEntry); context.getMetaData().addContainerResource(resource); @@ -361,93 +360,99 @@ public void scanJars(final WebAppContext context, Collection jars, boo //Scan jars for META-INF information if (jars != null) { - for (Resource r : jars) + try (ResourceFactory.Closeable closeable = ResourceFactory.closeable()) { - if (scanTypes.contains(METAINF_RESOURCES)) - scanForResources(context, r, metaInfResourceCache); - if (scanTypes.contains(METAINF_FRAGMENTS)) - scanForFragment(context, r, metaInfFragmentCache); - if (scanTypes.contains(METAINF_TLDS)) - scanForTlds(context, r, metaInfTldCache); + for (Resource r : jars) + { + Resource dir = r; + + try + { + if (!dir.isDirectory()) + dir = closeable.newJarFileResource(dir.getURI()); + } + catch (Exception e) + { + //not an appropriate uri, skip it + continue; + } + + if (isEmptyResource(dir)) + continue; + + if (scanTypes.contains(METAINF_RESOURCES)) + scanForResources(context, dir, metaInfResourceCache); + if (scanTypes.contains(METAINF_FRAGMENTS)) + scanForFragment(context, dir, metaInfFragmentCache); + if (scanTypes.contains(METAINF_TLDS)) + scanForTlds(context, dir, metaInfTldCache); + } } } } /** - * Scan for META-INF/resources dir in the given jar. + * Scan for META-INF/resources dir in the given directory. * * @param context the context for the scan - * @param target the target resource to scan for + * @param dir the target directory to scan * @param cache the resource cache */ - public void scanForResources(WebAppContext context, Resource target, ConcurrentHashMap cache) + public void scanForResources(WebAppContext context, Resource dir, ConcurrentHashMap cache) { // Resource target does not exist - if (target == null) + if (isEmptyResource(dir)) return; - try (ResourceFactory.Closeable closeable = ResourceFactory.closeable()) - { - Resource resourcesDir = null; - - if (cache != null && cache.containsKey(target)) - { - resourcesDir = cache.get(target); - if (isEmptyResource(resourcesDir)) - { - if (LOG.isDebugEnabled()) - LOG.debug("{} cached as containing no META-INF/resources", target); - return; - } - else if (LOG.isDebugEnabled()) - LOG.debug("{} META-INF/resources found in cache ", target); - } - else - { - //not using caches or not in the cache so check for the resources dir - if (LOG.isDebugEnabled()) - LOG.debug("{} META-INF/resources checked", target); - if (target.isDirectory()) - { - //TODO think how to handle an unpacked jar file (eg for osgi) - resourcesDir = target.resolve("/META-INF/resources"); - } - else - { - // Resource represents a packed jar - resourcesDir = closeable.newJarFileResource(target.getURI()).resolve("META-INF/resources"); - } - - if (isEmptyResource(resourcesDir)) - { - return; - } - - //convert to a Resource tied to the Context lifecycle - resourcesDir = context.getResourceFactory().newResource(resourcesDir.getURI()); - - if (cache != null) - { - Resource old = cache.putIfAbsent(target, resourcesDir); - if (old != null) - resourcesDir = old; - else if (LOG.isDebugEnabled()) - LOG.debug("{} META-INF/resources cache updated", target); - } - } - - //add it to the meta inf resources for this context - Set dirs = (Set)context.getAttribute(METAINF_RESOURCES); - if (dirs == null) - { - dirs = new HashSet(); - context.setAttribute(METAINF_RESOURCES, dirs); - } - if (LOG.isDebugEnabled()) - LOG.debug("{} added to context", resourcesDir); - - dirs.add(resourcesDir); - } + Resource resourcesDir = null; + + if (cache != null && cache.containsKey(dir)) + { + resourcesDir = cache.get(dir); + if (isEmptyResource(resourcesDir)) + { + if (LOG.isDebugEnabled()) + LOG.debug("{} cached as containing no META-INF/resources", dir); + return; + } + else if (LOG.isDebugEnabled()) + LOG.debug("{} META-INF/resources found in cache ", dir); + } + else + { + //not using caches or not in the cache so check for the resources dir + if (LOG.isDebugEnabled()) + LOG.debug("{} META-INF/resources checked", dir); + + resourcesDir = dir.resolve("/META-INF/resources"); + + if (isEmptyResource(resourcesDir)) + return; + + //convert to a Resource tied to the Context lifecycle + resourcesDir = context.getResourceFactory().newResource(resourcesDir.getURI()); + + if (cache != null) + { + Resource old = cache.putIfAbsent(dir, resourcesDir); + if (old != null) + resourcesDir = old; + else if (LOG.isDebugEnabled()) + LOG.debug("{} META-INF/resources cache updated", dir); + } + } + + //add it to the meta inf resources for this context + Set dirs = (Set)context.getAttribute(METAINF_RESOURCES); + if (dirs == null) + { + dirs = new HashSet(); + context.setAttribute(METAINF_RESOURCES, dirs); + } + if (LOG.isDebugEnabled()) + LOG.debug("{} added to context", resourcesDir); + + dirs.add(resourcesDir); } private static boolean isEmptyResource(Resource resourcesDir) @@ -459,66 +464,64 @@ private static boolean isEmptyResource(Resource resourcesDir) * Scan for META-INF/web-fragment.xml file in the given jar. * * @param context the context for the scan - * @param jar the jar resource to scan for fragements in + * @param dir the directory to scan for fragments * @param cache the resource cache */ - public void scanForFragment(WebAppContext context, Resource jar, ConcurrentHashMap cache) + public void scanForFragment(WebAppContext context, Resource dir, ConcurrentHashMap cache) { Resource webFrag = null; - try (ResourceFactory.Closeable closeable = ResourceFactory.closeable()) + if (cache != null && cache.containsKey(dir)) { - if (cache != null && cache.containsKey(jar)) - { - webFrag = cache.get(jar); - if (isEmptyFragment(webFrag)) - { - if (LOG.isDebugEnabled()) - LOG.debug("{} cached as containing no META-INF/web-fragment.xml", jar); - return; - } - else if (LOG.isDebugEnabled()) - LOG.debug("{} META-INF/web-fragment.xml found in cache ", jar); - } - else + webFrag = cache.get(dir); + if (isEmptyFragment(webFrag)) { - //not using caches or not in the cache so check for the web-fragment.xml if (LOG.isDebugEnabled()) - LOG.debug("{} META-INF/web-fragment.xml checked", jar); - if (jar.isDirectory()) - { - webFrag = jar.resolve("META-INF/web-fragment.xml"); - } - else - { - webFrag = closeable.newJarFileResource(jar.getURI()).resolve("META-INF/web-fragment.xml"); - } + LOG.debug("{} cached as containing no META-INF/web-fragment.xml", dir); + return; + } + else if (LOG.isDebugEnabled()) + LOG.debug("{} META-INF/web-fragment.xml found in cache ", dir); + } + else + { + //not using caches or not in the cache so check for the web-fragment.xml + if (LOG.isDebugEnabled()) + LOG.debug("{} META-INF/web-fragment.xml checked", dir); - if (isEmptyFragment(webFrag)) - return; + webFrag = dir.resolve("META-INF/web-fragment.xml"); - //convert webFragment Resource to one tied to the Context lifecycle - webFrag = context.getResourceFactory().newResource(webFrag.getURI()); + if (isEmptyFragment(webFrag)) + return; - if (cache != null) - { - Resource old = cache.putIfAbsent(jar, webFrag); - if (old != null) - webFrag = old; - else if (LOG.isDebugEnabled()) - LOG.debug("{} META-INF/web-fragment.xml cache updated", jar); - } - } + //convert webFragment Resource to one tied to the Context lifecycle + webFrag = context.getResourceFactory().newResource(webFrag.getURI()); - Map fragments = (Map)context.getAttribute(METAINF_FRAGMENTS); - if (fragments == null) + if (cache != null) { - fragments = new HashMap(); - context.setAttribute(METAINF_FRAGMENTS, fragments); + Resource old = cache.putIfAbsent(dir, webFrag); + if (old != null) + webFrag = old; + else if (LOG.isDebugEnabled()) + LOG.debug("{} META-INF/web-fragment.xml cache updated", dir); } - fragments.put(jar, webFrag); - if (LOG.isDebugEnabled()) - LOG.debug("{} added to context", webFrag); } + + Map fragments = (Map)context.getAttribute(METAINF_FRAGMENTS); + if (fragments == null) + { + fragments = new HashMap(); + context.setAttribute(METAINF_FRAGMENTS, fragments); + } + + if (dir instanceof MountedPathResource) + { + //ensure we get the original .jar rather than jar:file: + dir = context.getResourceFactory().newResource(((MountedPathResource)dir).getContainerPath()); + } + + fragments.put(dir, webFrag); + if (LOG.isDebugEnabled()) + LOG.debug("{} added to context", webFrag); } private static boolean isEmptyFragment(Resource webFrag) @@ -530,42 +533,45 @@ private static boolean isEmptyFragment(Resource webFrag) * Discover META-INF/*.tld files in the given jar * * @param context the context for the scan - * @param jar the jar resources to scan tlds for + * @param dir the directory to scan for .tlds * @param cache the resource cache - * @throws Exception if unable to scan for tlds + * @throws Exception if unable to scan for .tlds */ - public void scanForTlds(WebAppContext context, Resource jar, ConcurrentHashMap> cache) + public void scanForTlds(WebAppContext context, Resource dir, ConcurrentHashMap> cache) throws Exception { Collection tlds; - if (cache != null && cache.containsKey(jar)) + if (isEmptyResource(dir)) + return; + + if (cache != null && cache.containsKey(dir)) { - Collection tmp = cache.get(jar); + Collection tmp = cache.get(dir); if (tmp.isEmpty()) { if (LOG.isDebugEnabled()) - LOG.debug("{} cached as containing no tlds", jar); + LOG.debug("{} cached as containing no tlds", dir); return; } else { tlds = tmp; if (LOG.isDebugEnabled()) - LOG.debug("{} tlds found in cache ", jar); + LOG.debug("{} tlds found in cache ", dir); } } else { //not using caches or not in the cache so find all tlds tlds = new HashSet<>(); - tlds.addAll(getTlds(context, jar)); + tlds.addAll(getTlds(context, dir)); if (cache != null) { if (LOG.isDebugEnabled()) - LOG.debug("{} tld cache updated", jar); - Collection old = cache.putIfAbsent(jar, tlds); + LOG.debug("{} tld cache updated", dir); + Collection old = cache.putIfAbsent(dir, tlds); if (old != null) tlds = old; } @@ -598,43 +604,31 @@ public void postConfigure(WebAppContext context) throws Exception /** * Find all .tld files in the given jar. * - * @param resource the jar file + * @param dir the dir to check for .tlds * @return the collection of tlds as url references * @throws IOException if unable to scan the jar file */ - private Collection getTlds(WebAppContext context, Resource resource) throws IOException + private Collection getTlds(WebAppContext context, Resource dir) throws IOException { HashSet tlds = new HashSet<>(); - Resource resourceDir; - - try (ResourceFactory.Closeable closeableResourceFactory = ResourceFactory.closeable()) - { - if (!resource.isDirectory()) - { - //turn it into a jar:file - resourceDir = closeableResourceFactory.newJarFileResource(resource.getURI()); - } - else - resourceDir = resource; - Resource metaInf = resourceDir.resolve("META-INF"); - if (isEmptyResource(metaInf)) - return tlds; //no tlds + Resource metaInf = dir.resolve("META-INF"); + if (isEmptyResource(metaInf)) + return tlds; //no tlds - try (Stream stream = Files.walk(metaInf.getPath())) + try (Stream stream = Files.walk(metaInf.getPath())) + { + Iterator it = stream + .filter(Files::isRegularFile) + .filter(FileID::isTld) + .iterator(); + while (it.hasNext()) { - Iterator it = stream - .filter(Files::isRegularFile) - .filter(FileID::isTld) - .iterator(); - while (it.hasNext()) - { - Path entry = it.next(); - tlds.add(entry.toUri().toURL()); - } + Path entry = it.next(); + tlds.add(entry.toUri().toURL()); } - return tlds; } + return tlds; } protected List findClassDirs(WebAppContext context) From 1a51854689cc8f56fd9de56b82ae4240c11dc80a Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Mon, 27 Nov 2023 23:47:26 +0100 Subject: [PATCH 5/7] Update jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/MetaInfConfiguration.java Co-authored-by: Greg Wilkins --- .../org/eclipse/jetty/ee10/webapp/MetaInfConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/MetaInfConfiguration.java b/jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/MetaInfConfiguration.java index 1c049c1f12c1..b99f38012692 100644 --- a/jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/MetaInfConfiguration.java +++ b/jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/MetaInfConfiguration.java @@ -354,7 +354,7 @@ public void scanJars(final WebAppContext context, Collection jars, boo //Scan jars for META-INF information if (jars != null) { - try (ResourceFactory.Closeable closeable = ResourceFactory.closeable()) + try (ResourceFactory.Closeable scanResourceFactory = ResourceFactory.closeable()) { for (Resource r : jars) { From 70afc89ba77e1e4b272f92ee9a0f606dacf7be00 Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Tue, 28 Nov 2023 10:01:36 +1100 Subject: [PATCH 6/7] Changes post review --- .../jetty/ee10/webapp/MetaInfConfiguration.java | 9 +++++---- .../jetty/ee9/webapp/MetaInfConfiguration.java | 11 ++++++----- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/MetaInfConfiguration.java b/jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/MetaInfConfiguration.java index b99f38012692..2e7822b9f1fa 100644 --- a/jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/MetaInfConfiguration.java +++ b/jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/MetaInfConfiguration.java @@ -362,8 +362,9 @@ public void scanJars(final WebAppContext context, Collection jars, boo try { + //If not already a directory, convert by mounting as jar file if (!dir.isDirectory()) - dir = closeable.newJarFileResource(dir.getURI()); + dir = scanResourceFactory.newJarFileResource(dir.getURI()); } catch (Exception e) { @@ -423,7 +424,7 @@ else if (LOG.isDebugEnabled()) if (isEmptyResource(resourcesDir)) return; - //convert to a Resource tied to the Context lifecycle + //convert from an ephemeral Resource to one that is associated with the context's lifecycle resourcesDir = context.getResourceFactory().newResource(resourcesDir.getURI()); if (cache != null) @@ -491,7 +492,7 @@ else if (LOG.isDebugEnabled()) if (isEmptyFragment(webFrag)) return; - //convert webFragment Resource to one tied to the Context lifecycle + //convert ephemeral Resource to one associated with the context's lifecycle ResourceFactory webFrag = context.getResourceFactory().newResource(webFrag.getURI()); if (cache != null) @@ -513,7 +514,7 @@ else if (LOG.isDebugEnabled()) if (dir instanceof MountedPathResource) { - //ensure we get the original .jar rather than jar:file: + //ensure we link from the original .jar rather than jar:file: dir = context.getResourceFactory().newResource(((MountedPathResource)dir).getContainerPath()); } diff --git a/jetty-ee9/jetty-ee9-webapp/src/main/java/org/eclipse/jetty/ee9/webapp/MetaInfConfiguration.java b/jetty-ee9/jetty-ee9-webapp/src/main/java/org/eclipse/jetty/ee9/webapp/MetaInfConfiguration.java index 456ca14e5570..404b8c6c81ad 100644 --- a/jetty-ee9/jetty-ee9-webapp/src/main/java/org/eclipse/jetty/ee9/webapp/MetaInfConfiguration.java +++ b/jetty-ee9/jetty-ee9-webapp/src/main/java/org/eclipse/jetty/ee9/webapp/MetaInfConfiguration.java @@ -360,7 +360,7 @@ public void scanJars(final WebAppContext context, Collection jars, boo //Scan jars for META-INF information if (jars != null) { - try (ResourceFactory.Closeable closeable = ResourceFactory.closeable()) + try (ResourceFactory.Closeable scanResourceFactory = ResourceFactory.closeable()) { for (Resource r : jars) { @@ -368,8 +368,9 @@ public void scanJars(final WebAppContext context, Collection jars, boo try { + //if not already a directory, convert it by mounting as jar file if (!dir.isDirectory()) - dir = closeable.newJarFileResource(dir.getURI()); + dir = scanResourceFactory.newJarFileResource(dir.getURI()); } catch (Exception e) { @@ -429,7 +430,7 @@ else if (LOG.isDebugEnabled()) if (isEmptyResource(resourcesDir)) return; - //convert to a Resource tied to the Context lifecycle + //convert from an ephemeral Resource to one that is associated with the context's lifecycle resourcesDir = context.getResourceFactory().newResource(resourcesDir.getURI()); if (cache != null) @@ -493,7 +494,7 @@ else if (LOG.isDebugEnabled()) if (isEmptyFragment(webFrag)) return; - //convert webFragment Resource to one tied to the Context lifecycle + //convert ephemeral Resource to one associated with the context's lifecycle ResourceFactory webFrag = context.getResourceFactory().newResource(webFrag.getURI()); if (cache != null) @@ -515,7 +516,7 @@ else if (LOG.isDebugEnabled()) if (dir instanceof MountedPathResource) { - //ensure we get the original .jar rather than jar:file: + //ensure we link from the original .jar rather than jar:file: dir = context.getResourceFactory().newResource(((MountedPathResource)dir).getContainerPath()); } From c44c31998fed0e2a69c867878f5d5220366f44b5 Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Wed, 29 Nov 2023 10:14:10 +1100 Subject: [PATCH 7/7] Change post review --- .../org/eclipse/jetty/ee10/webapp/MetaInfConfiguration.java | 4 +--- .../org/eclipse/jetty/ee9/webapp/MetaInfConfiguration.java | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/MetaInfConfiguration.java b/jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/MetaInfConfiguration.java index 2e7822b9f1fa..6c8d99b43896 100644 --- a/jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/MetaInfConfiguration.java +++ b/jetty-ee10/jetty-ee10-webapp/src/main/java/org/eclipse/jetty/ee10/webapp/MetaInfConfiguration.java @@ -356,10 +356,8 @@ public void scanJars(final WebAppContext context, Collection jars, boo { try (ResourceFactory.Closeable scanResourceFactory = ResourceFactory.closeable()) { - for (Resource r : jars) + for (Resource dir : jars) { - Resource dir = r; - try { //If not already a directory, convert by mounting as jar file diff --git a/jetty-ee9/jetty-ee9-webapp/src/main/java/org/eclipse/jetty/ee9/webapp/MetaInfConfiguration.java b/jetty-ee9/jetty-ee9-webapp/src/main/java/org/eclipse/jetty/ee9/webapp/MetaInfConfiguration.java index 404b8c6c81ad..07a316ea584d 100644 --- a/jetty-ee9/jetty-ee9-webapp/src/main/java/org/eclipse/jetty/ee9/webapp/MetaInfConfiguration.java +++ b/jetty-ee9/jetty-ee9-webapp/src/main/java/org/eclipse/jetty/ee9/webapp/MetaInfConfiguration.java @@ -362,10 +362,8 @@ public void scanJars(final WebAppContext context, Collection jars, boo { try (ResourceFactory.Closeable scanResourceFactory = ResourceFactory.closeable()) { - for (Resource r : jars) + for (Resource dir : jars) { - Resource dir = r; - try { //if not already a directory, convert it by mounting as jar file