Author: markt Date: Thu Apr 22 08:13:08 2010 New Revision: 936646 URL: http://svn.apache.org/viewvc?rev=936646&view=rev Log: Add support for loading static resources from /META-INF/resources inside JARs bundled with a web application
Modified: tomcat/trunk/java/org/apache/catalina/Context.java tomcat/trunk/java/org/apache/catalina/core/LocalStrings.properties tomcat/trunk/java/org/apache/catalina/core/StandardContext.java tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java tomcat/trunk/java/org/apache/catalina/startup/LocalStrings.properties tomcat/trunk/java/org/apache/naming/resources/BaseDirContext.java tomcat/trunk/java/org/apache/naming/resources/FileDirContext.java tomcat/trunk/java/org/apache/naming/resources/WARDirContext.java Modified: tomcat/trunk/java/org/apache/catalina/Context.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/Context.java?rev=936646&r1=936645&r2=936646&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/Context.java (original) +++ tomcat/trunk/java/org/apache/catalina/Context.java Thu Apr 22 08:13:08 2010 @@ -1183,5 +1183,11 @@ public interface Context extends Contain */ public JspConfigDescriptor getJspConfigDescriptor(); + /** + * Add a URL for a JAR that contains static resources in a + * META-INF/resources directory that should be included in the static + * resources for this context. + */ + public void addResourceJarUrl(URL url); } Modified: tomcat/trunk/java/org/apache/catalina/core/LocalStrings.properties URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/LocalStrings.properties?rev=936646&r1=936645&r2=936646&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/core/LocalStrings.properties (original) +++ tomcat/trunk/java/org/apache/catalina/core/LocalStrings.properties Thu Apr 22 08:13:08 2010 @@ -115,6 +115,7 @@ standardContext.loginConfig.loginPage=Fo standardContext.loginConfig.loginWarning=WARNING: Form login page {0} must start with a ''/'' in Servlet 2.4 standardContext.loginConfig.required=LoginConfig cannot be null standardContext.mappingError=MAPPING configuration error for relative URI {0} +standardContext.noResourceJar=Resource JARs are not supported. The JAR found at [{0}] will no be used to provide static content for context with path [{1}] standardContext.notFound=The requested resource ({0}) is not available. standardContext.notReloadable=Reloading is disabled on this Context standardContext.notStarted=Context has not yet been started Modified: tomcat/trunk/java/org/apache/catalina/core/StandardContext.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/StandardContext.java?rev=936646&r1=936645&r2=936646&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/core/StandardContext.java (original) +++ tomcat/trunk/java/org/apache/catalina/core/StandardContext.java Thu Apr 22 08:13:08 2010 @@ -962,6 +962,21 @@ public class StandardContext /** + * Add a URL for a JAR that contains static resources in a + * META-INF/resources directory that should be included in the static + * resources for this context. + */ + public void addResourceJarUrl(URL url) { + if (webappResources instanceof BaseDirContext) { + ((BaseDirContext) webappResources).addResourcesJar(url); + } else { + log.error(sm.getString("standardContext.noResourceJar", url, + getPath())); + } + } + + + /** * Set the current alias configuration. The list of aliases should be of the * form "/aliasPath1=docBase1,/aliasPath2=docBase2" where aliasPathN must * include a leading '/' and docBaseN must be an absolute path to either a @@ -2122,11 +2137,13 @@ public class StandardContext return; if (resources instanceof BaseDirContext) { + // Caching ((BaseDirContext) resources).setCached(isCachingAllowed()); ((BaseDirContext) resources).setCacheTTL(getCacheTTL()); ((BaseDirContext) resources).setCacheMaxSize(getCacheMaxSize()); ((BaseDirContext) resources).setCacheObjectMaxSize( getCacheObjectMaxSize()); + // Alias support ((BaseDirContext) resources).setAliases(getAliases()); } if (resources instanceof FileDirContext) { Modified: tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java?rev=936646&r1=936645&r2=936646&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java (original) +++ tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java Thu Apr 22 08:13:08 2010 @@ -38,6 +38,7 @@ import java.util.Properties; import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; +import java.util.zip.ZipEntry; import javax.servlet.ServletContext; @@ -1237,6 +1238,8 @@ public class ContextConfig if (context.getLogEffectiveWebXml()) { log.info("web.xml:\n" + mergedWebXml); } + + processResourceJARs(orderedFragments); } else { // Apply unmerged web.xml to Context webXml.configureContext(context); @@ -1245,6 +1248,40 @@ public class ContextConfig /** + * Scan JARs that contain web-fragment.xml files that will be used to + * configure this application to see if they also contain static resources. + * If static resources are found, add them to the context. Resources are + * added in web-fragment.xml priority order. + */ + protected void processResourceJARs(Set<WebXml> fragments) { + for (WebXml fragment : fragments) { + URL jarUrl = fragment.getURL(); + JarFile jarFile = null; + try { + JarURLConnection conn = + (JarURLConnection) jarUrl.openConnection(); + jarFile = conn.getJarFile(); + ZipEntry entry = jarFile.getEntry("META-INF/resources/"); + if (entry != null) { + context.addResourceJarUrl(jarUrl); + } + } catch (IOException ioe) { + log.error(sm.getString("contextConfig.resourceJarFail", jarUrl, + context.getPath())); + } finally { + if (jarFile != null) { + try { + jarFile.close(); + } catch (IOException e) { + // Ignore + } + } + } + } + } + + + /** * Identify the default web.xml to be used and obtain an input source for * it. */ Modified: tomcat/trunk/java/org/apache/catalina/startup/LocalStrings.properties URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/LocalStrings.properties?rev=936646&r1=936645&r2=936646&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/startup/LocalStrings.properties (original) +++ tomcat/trunk/java/org/apache/catalina/startup/LocalStrings.properties Thu Apr 22 08:13:08 2010 @@ -46,6 +46,7 @@ contextConfig.jar=Unable to process reso contextConfig.jndiUrl=Unable to process JNDI URL [{0}] for annotations contextConfig.jndiUrlNotDirContextConn=The connection created for URL [{0}] was not a DirContextURLConnection contextConfig.missingRealm=No Realm has been configured to authenticate against +contextConfig.resourceJarFail=Failed to processes JAR found at URL [{0}] for static resources to be included in context with path [{0}] contextConfig.role.auth=WARNING: Security role name {0} used in an <auth-constraint> without being defined in a <security-role> contextConfig.role.link=WARNING: Security role name {0} used in a <role-link> without being defined in a <security-role> contextConfig.role.runas=WARNING: Security role name {0} used in a <run-as> without being defined in a <security-role> Modified: tomcat/trunk/java/org/apache/naming/resources/BaseDirContext.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/naming/resources/BaseDirContext.java?rev=936646&r1=936645&r2=936646&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/naming/resources/BaseDirContext.java (original) +++ tomcat/trunk/java/org/apache/naming/resources/BaseDirContext.java Thu Apr 22 08:13:08 2010 @@ -19,11 +19,18 @@ package org.apache.naming.resources; import java.io.File; +import java.io.IOException; +import java.net.JarURLConnection; +import java.net.URL; +import java.util.ArrayList; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.jar.JarFile; +import java.util.zip.ZipEntry; import javax.naming.Binding; import javax.naming.Context; @@ -131,10 +138,39 @@ public abstract class BaseDirContext imp new HashMap<String,BaseDirContext>(); + /** + * Alternate / backup DirContexts for static resources. These will be + * searched in the order they are added if the requested resource cannot be + * found in the primary DirContext. + */ + protected List<DirContext> altDirContexts = new ArrayList<DirContext>(); + + // ------------------------------------------------------------- Properties /** + * Add a resources JAR. The contents of /META-INF/resources/ will be used if + * a requested resource can not be found in the main context. + */ + public void addResourcesJar(URL url) { + try { + JarURLConnection conn = (JarURLConnection) url.openConnection(); + JarFile jarFile = conn.getJarFile(); + ZipEntry entry = jarFile.getEntry("/"); + WARDirContext warDirContext = new WARDirContext(jarFile, + new WARDirContext.Entry("/", entry)); + warDirContext.loadEntries(); + altDirContexts.add(warDirContext); + } catch (IOException ioe) { + // TODO: Log failure + } finally { + // TODO: Clean up + } + } + + + /** * Add an alias. */ public void addAlias(String path, BaseDirContext dirContext) { @@ -350,7 +386,25 @@ public abstract class BaseDirContext imp return result.dirContext.doGetRealPath(result.aliasName); } } - return doGetRealPath(name); + + // Next do a standard getRealPath() + String path = doGetRealPath(name); + + if (path != null) + return path; + + // Check the alternate locations + for (DirContext altDirContext : altDirContexts) { + if (altDirContext instanceof BaseDirContext){ + path = ((BaseDirContext) altDirContext).getRealPath( + "META-INF/resources/" + name); + if (path != null) + return path; + } + } + + // Really not found + return null; } // -------------------------------------------------------- Context Methods @@ -380,13 +434,29 @@ public abstract class BaseDirContext imp * @exception NamingException if a naming exception is encountered */ public final Object lookup(String name) throws NamingException { + // First check for aliases if (!aliases.isEmpty()) { AliasResult result = findAlias(name); if (result.dirContext != null) { return result.dirContext.lookup(result.aliasName); } } - return doLookup(name); + + // Next do a standard lookup + Object obj = doLookup(name); + + if (obj != null) + return obj; + + // Check the alternate locations + for (DirContext altDirContext : altDirContexts) { + obj = altDirContext.lookup("META-INF/resources/" + name); + if (obj != null) + return obj; + } + + // Really not found + throw new NamingException(sm.getString("resources.notFound", name)); } /** @@ -589,7 +659,31 @@ public abstract class BaseDirContext imp return result.dirContext.listBindings(result.aliasName); } } - return doListBindings(name); + + // Next do a standard lookup + NamingEnumeration<Binding> bindings = doListBindings(name); + + if (bindings != null) + return bindings; + + // Check the alternate locations + for (DirContext altDirContext : altDirContexts) { + if (altDirContext instanceof BaseDirContext) + bindings = ((BaseDirContext) altDirContext).doListBindings( + "META-INF/resources/" + name); + else { + try { + bindings = altDirContext.listBindings(name); + } catch (NamingException ne) { + // Ignore + } + } + if (bindings != null) + return bindings; + } + + // Really not found + throw new NamingException(sm.getString("resources.notFound", name)); } @@ -912,6 +1006,8 @@ public abstract class BaseDirContext imp */ public final Attributes getAttributes(String name, String[] attrIds) throws NamingException { + + // First check for aliases if (!aliases.isEmpty()) { AliasResult result = findAlias(name); if (result.dirContext != null) { @@ -919,7 +1015,31 @@ public abstract class BaseDirContext imp result.aliasName, attrIds); } } - return doGetAttributes(name, attrIds); + + // Next do a standard lookup + Attributes attrs = doGetAttributes(name, attrIds); + + if (attrs != null) + return attrs; + + // Check the alternate locations + for (DirContext altDirContext : altDirContexts) { + if (altDirContext instanceof BaseDirContext) + attrs = ((BaseDirContext) altDirContext).doGetAttributes( + "META-INF/resources/" + name, attrIds); + else { + try { + attrs = altDirContext.getAttributes(name, attrIds); + } catch (NamingException ne) { + // Ignore + } + } + if (attrs != null) + return attrs; + } + + // Really not found + throw new NamingException(sm.getString("resources.notFound", name)); } /** Modified: tomcat/trunk/java/org/apache/naming/resources/FileDirContext.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/naming/resources/FileDirContext.java?rev=936646&r1=936645&r2=936646&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/naming/resources/FileDirContext.java (original) +++ tomcat/trunk/java/org/apache/naming/resources/FileDirContext.java Thu Apr 22 08:13:08 2010 @@ -202,8 +202,7 @@ public class FileDirContext extends Base File file = file(name); if (file == null) - throw new NamingException - (sm.getString("resources.notFound", name)); + return null; if (file.isDirectory()) { FileDirContext tempContext = new FileDirContext(env); @@ -326,9 +325,8 @@ public class FileDirContext extends Base File file = file(name); if (file == null) - throw new NamingException - (sm.getString("resources.notFound", name)); - + return null; + return new NamingContextBindingsEnumeration(list(file).iterator(), this); @@ -432,8 +430,7 @@ public class FileDirContext extends Base File file = file(name); if (file == null) - throw new NamingException - (sm.getString("resources.notFound", name)); + return null; return new FileResourceAttributes(file); Modified: tomcat/trunk/java/org/apache/naming/resources/WARDirContext.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/naming/resources/WARDirContext.java?rev=936646&r1=936645&r2=936646&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/naming/resources/WARDirContext.java (original) +++ tomcat/trunk/java/org/apache/naming/resources/WARDirContext.java Thu Apr 22 08:13:08 2010 @@ -79,7 +79,8 @@ public class WARDirContext extends BaseD /** - * Constructor used for returning fake subcontexts. + * Constructor used for returning fake sub-contexts or for accessing + * META-INF/resources locations in bundled JAR files. */ protected WARDirContext(ZipFile base, Entry entries) { this.base = base; @@ -201,8 +202,8 @@ public class WARDirContext extends BaseD return this; Entry entry = treeLookup(name); if (entry == null) - throw new NamingException - (sm.getString("resources.notFound", name)); + return null; + ZipEntry zipEntry = entry.getEntry(); if (zipEntry.isDirectory()) return new WARDirContext(base, entry); @@ -320,8 +321,8 @@ public class WARDirContext extends BaseD this); Entry entry = treeLookup(name); if (entry == null) - throw new NamingException - (sm.getString("resources.notFound", name)); + return null; + return new NamingContextBindingsEnumeration(list(entry).iterator(), this); } @@ -441,8 +442,7 @@ public class WARDirContext extends BaseD else entry = treeLookup(name); if (entry == null) - throw new NamingException - (sm.getString("resources.notFound", name)); + return null; ZipEntry zipEntry = entry.getEntry(); @@ -841,7 +841,7 @@ public class WARDirContext extends BaseD /** * Entries structure. */ - protected class Entry implements Comparable<Object> { + protected static class Entry implements Comparable<Object> { // -------------------------------------------------------- Constructor --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org