Author: markt Date: Mon Nov 4 23:53:26 2013 New Revision: 1538807 URL: http://svn.apache.org/r1538807 Log: First pass at using the new resources implementation to provide resources to the class loader.
Class loader resources are handled by treating JARs in WEB-INF/lib as resource JARs (without the internal META-INF/resources/ prefix) mounted at WEB-INF/claasses (rather than the web app root). This enables reuse of the resource handling plumbing. These resources are marked as class loader only so they are only used in the methods that are explicitly defined to return class loader resources. This prevents calls to getResource("/WEB-INF/classes") returning from one or more of the JAR files. Modified: tomcat/trunk/java/org/apache/catalina/WebResourceRoot.java tomcat/trunk/java/org/apache/catalina/WebResourceSet.java tomcat/trunk/java/org/apache/catalina/webresources/AbstractResourceSet.java tomcat/trunk/java/org/apache/catalina/webresources/Cache.java tomcat/trunk/java/org/apache/catalina/webresources/CachedResource.java tomcat/trunk/java/org/apache/catalina/webresources/StandardRoot.java Modified: tomcat/trunk/java/org/apache/catalina/WebResourceRoot.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/WebResourceRoot.java?rev=1538807&r1=1538806&r2=1538807&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/WebResourceRoot.java (original) +++ tomcat/trunk/java/org/apache/catalina/WebResourceRoot.java Mon Nov 4 23:53:26 2013 @@ -111,6 +111,22 @@ public interface WebResourceRoot extends WebResource[] getResources(String path); /** + * Obtain the object that represents the class loader resource at the given + * path. WEB-INF/classes is always searched prior to searching JAR files in + * WEB-INF/lib. The search order for JAR files will be consistent across + * subsequent calls to this method until the web application is reloaded. No + * guarantee is made as to what the search order for JAR files may be. + * + * @param path The path of the class loader resource of interest relative + * to the the root of class loader resources for this web + * application. + * + * @return The object that represents the class loader resource at the + * given path + */ + WebResource getClassLoaderResource(String path); + + /** * Obtain the list of the names of all of the files and directories located * in the specified directory. * @@ -336,6 +352,7 @@ public interface WebResourceRoot extends public static enum ResourceSetType { PRE, RESOURCE_JAR, - POST + POST, + CLASSES_JAR } } Modified: tomcat/trunk/java/org/apache/catalina/WebResourceSet.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/WebResourceSet.java?rev=1538807&r1=1538806&r2=1538807&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/WebResourceSet.java (original) +++ tomcat/trunk/java/org/apache/catalina/WebResourceSet.java Mon Nov 4 23:53:26 2013 @@ -90,4 +90,16 @@ public interface WebResourceSet extends boolean write(String path, InputStream is, boolean overwrite); void setRoot(WebResourceRoot root); + + /** + * Are resources provided by this resource set only intended for use by + * calls to {@link WebResourceRoot#getClassLoaderResource(String)}. + * + * @return @true if these resources should only be used for calls to + * {@link WebResourceRoot#getClassLoaderResource(String)}, otherwise + * @false + */ + boolean getClassLoaderOnly(); + + void setClassLoaderOnly(boolean classLoaderOnly); } Modified: tomcat/trunk/java/org/apache/catalina/webresources/AbstractResourceSet.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/webresources/AbstractResourceSet.java?rev=1538807&r1=1538806&r2=1538807&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/webresources/AbstractResourceSet.java (original) +++ tomcat/trunk/java/org/apache/catalina/webresources/AbstractResourceSet.java Mon Nov 4 23:53:26 2013 @@ -30,6 +30,7 @@ public abstract class AbstractResourceSe private String base; private String internalPath; private String webAppMount; + private boolean classLoaderOnly; protected static final StringManager sm = @@ -88,6 +89,15 @@ public abstract class AbstractResourceSe return base; } + @Override + public boolean getClassLoaderOnly() { + return classLoaderOnly; + } + + @Override + public void setClassLoaderOnly(boolean classLoaderOnly) { + this.classLoaderOnly = classLoaderOnly; + } //-------------------------------------------------------- Lifecycle methods @Override Modified: tomcat/trunk/java/org/apache/catalina/webresources/Cache.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/webresources/Cache.java?rev=1538807&r1=1538806&r2=1538807&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/webresources/Cache.java (original) +++ tomcat/trunk/java/org/apache/catalina/webresources/Cache.java Mon Nov 4 23:53:26 2013 @@ -55,15 +55,15 @@ public class Cache { this.root = root; } - protected WebResource getResource(String path) { + protected WebResource getResource(String path, boolean useClassLoaderResources) { if (noCache(path)) { - return root.getResourceInternal(path); + return root.getResourceInternal(path, useClassLoaderResources); } CachedResource cacheEntry = resourceCache.get(path); - if (cacheEntry != null && !cacheEntry.validate()) { + if (cacheEntry != null && !cacheEntry.validate(useClassLoaderResources)) { removeCacheEntry(path, true); cacheEntry = null; } @@ -77,7 +77,7 @@ public class Cache { if (cacheEntry == null) { // newCacheEntry was inserted into the cache - validate it cacheEntry = newCacheEntry; - cacheEntry.validate(); + cacheEntry.validate(useClassLoaderResources); if (newCacheEntry.getContentLength() > getMaxSizeBytes()) { // Cache size has not been updated at this point removeCacheEntry(path, false); @@ -110,7 +110,7 @@ public class Cache { } else { // Another thread added the entry to the cache // Make sure it is validated - cacheEntry.validate(); + cacheEntry.validate(useClassLoaderResources); } } @@ -141,6 +141,8 @@ public class Cache { private boolean noCache(String path) { // Don't cache resources used by the class loader (it has its own cache) + // TODO. Review these exclusions once class loader resource handling is + // complete if (path.startsWith("/WEB-INF/classes") || path.startsWith("/WEB-INF/lib")) { return true; Modified: tomcat/trunk/java/org/apache/catalina/webresources/CachedResource.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/webresources/CachedResource.java?rev=1538807&r1=1538806&r2=1538807&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/webresources/CachedResource.java (original) +++ tomcat/trunk/java/org/apache/catalina/webresources/CachedResource.java Mon Nov 4 23:53:26 2013 @@ -53,13 +53,14 @@ public class CachedResource implements W this.ttl = ttl; } - protected boolean validate() { + protected boolean validate(boolean useClassLoaderResources) { long now = System.currentTimeMillis(); if (webResource == null) { synchronized (this) { if (webResource == null) { - webResource = root.getResourceInternal(webAppPath); + webResource = root.getResourceInternal( + webAppPath, useClassLoaderResources); getLastModified(); getContentLength(); nextCheck = ttl + now; @@ -72,8 +73,8 @@ public class CachedResource implements W return true; } - if (!webResource.exists() && - root.getResourceInternal(webAppPath).exists()) { + if (!webResource.exists() && root.getResourceInternal( + webAppPath, useClassLoaderResources).exists()) { return false; } Modified: tomcat/trunk/java/org/apache/catalina/webresources/StandardRoot.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/webresources/StandardRoot.java?rev=1538807&r1=1538806&r2=1538807&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/webresources/StandardRoot.java (original) +++ tomcat/trunk/java/org/apache/catalina/webresources/StandardRoot.java Mon Nov 4 23:53:26 2013 @@ -58,6 +58,7 @@ public class StandardRoot extends Lifecy private boolean allowLinking = false; private ArrayList<WebResourceSet> preResources = new ArrayList<>(); private WebResourceSet main; + private ArrayList<WebResourceSet> classResources = new ArrayList<>(); private ArrayList<WebResourceSet> jarResources = new ArrayList<>(); private ArrayList<WebResourceSet> postResources = new ArrayList<>(); @@ -71,6 +72,7 @@ public class StandardRoot extends Lifecy { allResources.add(preResources); allResources.add(mainResources); + allResources.add(classResources); allResources.add(jarResources); allResources.add(postResources); } @@ -92,15 +94,23 @@ public class StandardRoot extends Lifecy @Override public String[] list(String path) { - checkState(); + return list(path, true); + } + + private String[] list(String path, boolean doStateCheck) { + if (doStateCheck) { + checkState(); + } // Set because we don't want duplicates HashSet<String> result = new HashSet<>(); for (ArrayList<WebResourceSet> list : allResources) { for (WebResourceSet webResourceSet : list) { - String[] entries = webResourceSet.list(path); - for (String entry : entries) { - result.add(entry); + if (!webResourceSet.getClassLoaderOnly()) { + String[] entries = webResourceSet.list(path); + for (String entry : entries) { + result.add(entry); + } } } } @@ -116,7 +126,9 @@ public class StandardRoot extends Lifecy HashSet<String> result = new HashSet<>(); for (ArrayList<WebResourceSet> list : allResources) { for (WebResourceSet webResourceSet : list) { - result.addAll(webResourceSet.listWebAppPaths(path)); + if (!webResourceSet.getClassLoaderOnly()) { + result.addAll(webResourceSet.listWebAppPaths(path)); + } } } if (result.size() == 0) { @@ -159,26 +171,46 @@ public class StandardRoot extends Lifecy @Override public WebResource getResource(String path) { + return getResource(path, true, false); + } + + private WebResource getResource(String path, boolean doStateCheck, + boolean useClassLoaderResources) { + if (doStateCheck) { + checkState(); + } + if (isCachingAllowed()) { - return cache.getResource(path); + return cache.getResource(path, useClassLoaderResources); } else { - return getResourceInternal(path); + return getResourceInternal(path, useClassLoaderResources); } } - protected WebResource getResourceInternal(String path) { - checkState(); + @Override + public WebResource getClassLoaderResource(String path) { + if (path == null || path.length() == 0 || !path.startsWith("/")) { + throw new IllegalArgumentException(); + } + return getResource("/WEB-INF/classes" + path, true, true); + } + + + protected WebResource getResourceInternal(String path, + boolean useClassLoaderResources) { WebResource result = null; WebResource virtual = null; for (ArrayList<WebResourceSet> list : allResources) { for (WebResourceSet webResourceSet : list) { - result = webResourceSet.getResource(path); - if (result.exists()) { - return result; - } - if (virtual == null && result.isVirtual()) { - virtual = result; + if (useClassLoaderResources || !webResourceSet.getClassLoaderOnly()) { + result = webResourceSet.getResource(path); + if (result.exists()) { + return result; + } + if (virtual == null && result.isVirtual()) { + virtual = result; + } } } } @@ -199,9 +231,11 @@ public class StandardRoot extends Lifecy ArrayList<WebResource> result = new ArrayList<>(); for (ArrayList<WebResourceSet> list : allResources) { for (WebResourceSet webResourceSet : list) { - WebResource webResource = webResourceSet.getResource(path); - if (webResource.exists()) { - result.add(webResource); + if (!webResourceSet.getClassLoaderOnly()) { + WebResource webResource = webResourceSet.getResource(path); + if (webResource.exists()) { + result.add(webResource); + } } } } @@ -215,15 +249,21 @@ public class StandardRoot extends Lifecy @Override public WebResource[] listResources(String path) { - checkState(); + return listResources(path, true); + } + + private WebResource[] listResources(String path, boolean doStateCheck) { + if (doStateCheck) { + checkState(); + } - String[] resources = list(path); + String[] resources = list(path, false); WebResource[] result = new WebResource[resources.length]; for (int i = 0; i < resources.length; i++) { if (path.charAt(path.length() - 1) == '/') { - result[i] = getResource(path + resources[i]); + result[i] = getResource(path + resources[i], false, false); } else { - result[i] = getResource(path + '/' + resources[i]); + result[i] = getResource(path + '/' + resources[i], false, false); } } return result; @@ -248,6 +288,9 @@ public class StandardRoot extends Lifecy case PRE: resourceList = preResources; break; + case CLASSES_JAR: + resourceList = classResources; + break; case RESOURCE_JAR: resourceList = jarResources; break; @@ -283,6 +326,10 @@ public class StandardRoot extends Lifecy sm.getString("standardRoot.createInvalidFile", file)); } + if (type.equals(ResourceSetType.CLASSES_JAR)) { + resourceSet.setClassLoaderOnly(true); + } + resourceList.add(resourceSet); } @@ -386,6 +433,28 @@ public class StandardRoot extends Lifecy } } + /* + * Class loader resources are handled by treating JARs in WEB-INF/lib as + * resource JARs (without the internal META-INF/resources/ prefix) mounted + * at WEB-INF/claasses (rather than the web app root). This enables reuse + * of the resource handling plumbing. + * + * These resources are marked as class loader only so they are only used in + * the methods that are explicitly defined to return class loader resources. + * This prevents calls to getResource("/WEB-INF/classes") returning from one + * or more of the JAR files. + */ + private void processWebInfLib() { + WebResource[] possibleJars = listResources("/WEB-INF/lib", false); + + for (WebResource possibleJar : possibleJars) { + if (possibleJar.isFile() && possibleJar.getName().endsWith(".jar")) { + createWebResourceSet(ResourceSetType.CLASSES_JAR, + "/WEB-INF/classes", possibleJar.getURL(), "/"); + } + } + } + /** * For unit testing */ @@ -463,6 +532,14 @@ public class StandardRoot extends Lifecy } } + // This has to be called after the other resources have been started + // else it won't find all the matching resources + processWebInfLib(); + // Need to start the newly found resources + for (WebResourceSet classResource : classResources) { + classResource.start(); + } + setState(LifecycleState.STARTING); } --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org