*/
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);
}
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
/**
+ * 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
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) {
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
import javax.servlet.ServletContext;
if (context.getLogEffectiveWebXml()) {
log.info("web.xml:\n" + mergedWebXml);
}
+
+ processResourceJARs(orderedFragments);
} else {
// Apply unmerged web.xml to Context
webXml.configureContext(context);
/**
+ * 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.
*/
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>
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;
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) {
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
* @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));
}
/**
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));
}
*/
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) {
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));
}
/**
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);
File file = file(name);
if (file == null)
- throw new NamingException
- (sm.getString("resources.notFound", name));
-
+ return null;
+
return new NamingContextBindingsEnumeration(list(file).iterator(),
this);
File file = file(name);
if (file == null)
- throw new NamingException
- (sm.getString("resources.notFound", name));
+ return null;
return new FileResourceAttributes(file);
/**
- * 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;
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);
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);
}
else
entry = treeLookup(name);
if (entry == null)
- throw new NamingException
- (sm.getString("resources.notFound", name));
+ return null;
ZipEntry zipEntry = entry.getEntry();
/**
* Entries structure.
*/
- protected class Entry implements Comparable<Object> {
+ protected static class Entry implements Comparable<Object> {
// -------------------------------------------------------- Constructor