From: markt Date: Fri, 12 Jun 2009 11:38:29 +0000 (+0000) Subject: Implement alias resources. Key features: X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=e2ca78f16a17d28840b776b0a407680055a72b5b;p=tomcat7.0 Implement alias resources. Key features: - configured at the context level in the same way as the other resource related attributes - maps paths to directories or WAR files (single files not supported) Implementation notes: - Correct results for getRealPath() required this to be pushed down to the BaseDirContext as the short-cuts previously used needed to take account of any aliases. This in turn meant an addition to the Context interface - Thanks to Tim F. The configuration format is all his idea git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@784083 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/java/org/apache/catalina/Context.java b/java/org/apache/catalina/Context.java index 0727b7a03..625c7d569 100644 --- a/java/org/apache/catalina/Context.java +++ b/java/org/apache/catalina/Context.java @@ -1073,6 +1073,13 @@ public interface Context extends Container { */ public void setTldNamespaceAware(boolean tldNamespaceAware); + /** + * Return the real path for a given virtual path, if possible; otherwise + * return null. + * + * @param path The path to the desired resource + */ + public String getRealPath(String path); } diff --git a/java/org/apache/catalina/core/ApplicationContext.java b/java/org/apache/catalina/core/ApplicationContext.java index 7a3a07129..42050099f 100644 --- a/java/org/apache/catalina/core/ApplicationContext.java +++ b/java/org/apache/catalina/core/ApplicationContext.java @@ -371,17 +371,7 @@ public class ApplicationContext * @param path The path to the desired resource */ public String getRealPath(String path) { - - if (!context.isFilesystemBased()) - return null; - - if (path == null) { - return null; - } - - File file = new File(basePath, path); - return (file.getAbsolutePath()); - + return context.getRealPath(path); } diff --git a/java/org/apache/catalina/core/StandardContext.java b/java/org/apache/catalina/core/StandardContext.java index a584d43d4..dceb05802 100644 --- a/java/org/apache/catalina/core/StandardContext.java +++ b/java/org/apache/catalina/core/StandardContext.java @@ -670,6 +670,12 @@ public class StandardContext /** + * List of resource aliases. + */ + protected String aliases = null; + + + /** * Non proxied resources. */ private DirContext webappResources = null; @@ -848,6 +854,25 @@ public class StandardContext /** + * Return the list of resource aliases. + */ + public String getAliases() { + return this.aliases; + } + + + /** + * 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 + * .war file or a directory. + */ + public void setAliases(String aliases) { + this.aliases = aliases; + } + + + /** * Return the "follow standard delegation model" flag used to configure * our ClassLoader. */ @@ -1908,6 +1933,7 @@ public class StandardContext ((BaseDirContext) resources).setCacheMaxSize(getCacheMaxSize()); ((BaseDirContext) resources).setCacheObjectMaxSize( getCacheObjectMaxSize()); + ((BaseDirContext) resources).setAliases(getAliases()); } if (resources instanceof FileDirContext) { filesystemBased = true; @@ -3815,6 +3841,19 @@ public class StandardContext } + /** + * Return the real path for a given virtual path, if possible; otherwise + * return null. + * + * @param path The path to the desired resource + */ + public String getRealPath(String path) { + if (webappResources instanceof BaseDirContext) { + return ((BaseDirContext) webappResources).getRealPath(path); + } + return null; + } + // --------------------------------------------------------- Public Methods diff --git a/java/org/apache/catalina/core/mbeans-descriptors.xml b/java/org/apache/catalina/core/mbeans-descriptors.xml index e0c7a5a58..6b81ae979 100644 --- a/java/org/apache/catalina/core/mbeans-descriptors.xml +++ b/java/org/apache/catalina/core/mbeans-descriptors.xml @@ -45,6 +45,10 @@ description="Object that creates and destroys servlets, filters, and listeners. Include dependency injection and postConstruct/preDestory handling" type="org.apache.catalina.instanceManagement.InstanceManager" /> + + diff --git a/java/org/apache/naming/resources/BaseDirContext.java b/java/org/apache/naming/resources/BaseDirContext.java index 788ff5f03..625861898 100644 --- a/java/org/apache/naming/resources/BaseDirContext.java +++ b/java/org/apache/naming/resources/BaseDirContext.java @@ -18,7 +18,12 @@ package org.apache.naming.resources; +import java.io.File; +import java.util.HashMap; import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; import javax.naming.Binding; import javax.naming.Context; @@ -119,10 +124,98 @@ public abstract class BaseDirContext implements DirContext { protected int cacheObjectMaxSize = 512; // 512 K + /** + * Aliases allow content to be included from other locations. + */ + protected Map aliases = + new HashMap(); + + // ------------------------------------------------------------- Properties /** + * Add an alias. + */ + public void addAlias(String path, BaseDirContext dirContext) { + if (!path.startsWith("/")) { + throw new IllegalArgumentException( + sm.getString("resources.invalidAliasPath", path)); + } + aliases.put(path, dirContext); + } + + + /** + * Remove an alias. + */ + public void removeAlias(String path) { + if (!path.startsWith("/")) { + throw new IllegalArgumentException( + sm.getString("resources.invalidAliasPath", path)); + } + aliases.remove(path); + } + + + /** + * Get the current alias configuration in String form. If no aliases are + * configured, an empty string will be returned. + */ + public String getAliases() { + StringBuilder result = new StringBuilder(); + Iterator> iter = + aliases.entrySet().iterator(); + boolean first = true; + while (iter.hasNext()) { + if (first) { + first = false; + } else { + result.append(','); + } + Entry entry = iter.next(); + result.append(entry.getKey()); + result.append('='); + result.append(entry.getValue().getDocBase()); + } + return result.toString(); + } + + + /** + * Set the current alias configuration from a String. The String 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 .war file or a directory. Any call to this method will replace + * the current set of aliases. + */ + public void setAliases(String theAliases) { + // Overwrite whatever is currently set + aliases.clear(); + + if (theAliases == null || theAliases.length() == 0) + return; + + String[] kvps = theAliases.split(","); + for (String kvp : kvps) { + String[] kv = kvp.split("="); + if (kv.length != 2 || kv[0].length() == 0 || kv[1].length() == 0) + throw new IllegalArgumentException( + sm.getString("resources.invalidAliasMapping", kvp)); + + BaseDirContext context; + if (kv[1].endsWith(".war") && !(new File(kv[1]).isDirectory())) { + context = new WARDirContext(); + } else { + context = new FileDirContext(); + } + context.setDocBase(kv[1]); + addAlias(kv[0], context); + } + } + + + /** * Return the document root for this component. */ public String getDocBase() { @@ -235,6 +328,22 @@ public abstract class BaseDirContext implements DirContext { // No action taken by the default implementation } + + /** + * Return the real path for a given virtual path, if possible; otherwise + * return null. + * + * @param path The path to the desired resource + */ + public String getRealPath(String name) { + if (!aliases.isEmpty()) { + AliasResult result = findAlias(name); + if (result.dirContext != null) { + return result.dirContext.doGetRealPath(result.aliasName); + } + } + return doGetRealPath(name); + } // -------------------------------------------------------- Context Methods @@ -262,9 +371,15 @@ public abstract class BaseDirContext implements DirContext { * @return the object bound to name * @exception NamingException if a naming exception is encountered */ - public abstract Object lookup(String name) - throws NamingException; - + public final Object lookup(String name) throws NamingException { + if (!aliases.isEmpty()) { + AliasResult result = findAlias(name); + if (result.dirContext != null) { + return result.dirContext.lookup(result.aliasName); + } + } + return doLookup(name); + } /** * Binds a name to an object. All intermediate contexts and the target @@ -779,9 +894,17 @@ public abstract class BaseDirContext implements DirContext { * indicates that none should be retrieved * @exception NamingException if a naming exception is encountered */ - public abstract Attributes getAttributes(String name, String[] attrIds) - throws NamingException; - + public final Attributes getAttributes(String name, String[] attrIds) + throws NamingException { + if (!aliases.isEmpty()) { + AliasResult result = findAlias(name); + if (result.dirContext != null) { + return result.dirContext.getAttributes( + result.aliasName, attrIds); + } + } + return doGetAttributes(name, attrIds); + } /** * Modifies the attributes associated with a named object. The order of @@ -1229,6 +1352,37 @@ public abstract class BaseDirContext implements DirContext { // ------------------------------------------------------ Protected Methods + protected abstract Attributes doGetAttributes(String name, String[] attrIds) + throws NamingException; + + protected abstract Object doLookup(String name) throws NamingException; + + protected abstract String doGetRealPath(String name); + + // -------------------------------------------------------- Private Methods + private AliasResult findAlias(String name) { + AliasResult result = new AliasResult(); + + String searchName = name; + + result.dirContext = aliases.get(searchName); + while (result.dirContext == null) { + int slash = searchName.lastIndexOf('/'); + if (slash < 0) + break; + searchName = searchName.substring(0, slash); + result.dirContext = aliases.get(searchName); + } + + if (result.dirContext != null) + result.aliasName = name.substring(searchName.length()); + + return result; + } + private static class AliasResult { + BaseDirContext dirContext; + String aliasName; + } } diff --git a/java/org/apache/naming/resources/FileDirContext.java b/java/org/apache/naming/resources/FileDirContext.java index ca03de22d..4e840d1bd 100644 --- a/java/org/apache/naming/resources/FileDirContext.java +++ b/java/org/apache/naming/resources/FileDirContext.java @@ -193,6 +193,17 @@ public class FileDirContext extends BaseDirContext { } + /** + * Return the real path for a given virtual path, if possible; otherwise + * return null. + * + * @param path The path to the desired resource + */ + protected String doGetRealPath(String path) { + File file = new File(getDocBase(), path); + return file.getAbsolutePath(); + } + // -------------------------------------------------------- Context Methods @@ -203,7 +214,7 @@ public class FileDirContext extends BaseDirContext { * @return the object bound to name * @exception NamingException if a naming exception is encountered */ - public Object lookup(String name) + protected Object doLookup(String name) throws NamingException { Object result = null; File file = file(name); @@ -425,7 +436,7 @@ public class FileDirContext extends BaseDirContext { * indicates that none should be retrieved * @exception NamingException if a naming exception is encountered */ - public Attributes getAttributes(String name, String[] attrIds) + protected Attributes doGetAttributes(String name, String[] attrIds) throws NamingException { // Building attribute list diff --git a/java/org/apache/naming/resources/LocalStrings.properties b/java/org/apache/naming/resources/LocalStrings.properties index 020da83f9..51aceeb37 100644 --- a/java/org/apache/naming/resources/LocalStrings.properties +++ b/java/org/apache/naming/resources/LocalStrings.properties @@ -28,6 +28,8 @@ resources.path=Context relative path {0} must start with ''/'' resources.alreadyBound=Name {0} is already bound in this Context resources.bindFailed=Bind failed: {0} resources.unbindFailed=Unbind failed: {0} +resources.invalidAliasPath=The alias path ''{0}'' must start with ''/'' +resources.invalidAliasMapping=The alias mapping ''{0}'' is not valid standardResources.alreadyStarted=Resources has already been started standardResources.directory=File base {0} is not a directory standardResources.exists=File base {0} does not exist diff --git a/java/org/apache/naming/resources/VirtualDirContext.java b/java/org/apache/naming/resources/VirtualDirContext.java index dc21edf2d..6a21769ae 100644 --- a/java/org/apache/naming/resources/VirtualDirContext.java +++ b/java/org/apache/naming/resources/VirtualDirContext.java @@ -160,7 +160,7 @@ public class VirtualDirContext extends FileDirContext { } @Override - public Object lookup(String name) throws NamingException { + protected Object doLookup(String name) throws NamingException { // handle "virtual" tlds if (name.startsWith("/WEB-INF/") && name.endsWith(".tld")) { diff --git a/java/org/apache/naming/resources/WARDirContext.java b/java/org/apache/naming/resources/WARDirContext.java index bed5a186a..5eaa36beb 100644 --- a/java/org/apache/naming/resources/WARDirContext.java +++ b/java/org/apache/naming/resources/WARDirContext.java @@ -167,6 +167,16 @@ public class WARDirContext extends BaseDirContext { } + /** + * Return the real path for a given virtual path, if possible; otherwise + * return null. + * + * @param path The path to the desired resource + */ + protected String doGetRealPath(String path) { + return null; + } + // -------------------------------------------------------- Context Methods @@ -178,7 +188,7 @@ public class WARDirContext extends BaseDirContext { * @return the object bound to name * @exception NamingException if a naming exception is encountered */ - public Object lookup(String name) + protected Object doLookup(String name) throws NamingException { return lookup(new CompositeName(name)); } @@ -423,7 +433,7 @@ public class WARDirContext extends BaseDirContext { * indicates that none should be retrieved * @exception NamingException if a naming exception is encountered */ - public Attributes getAttributes(String name, String[] attrIds) + protected Attributes doGetAttributes(String name, String[] attrIds) throws NamingException { return getAttributes(new CompositeName(name), attrIds); } diff --git a/webapps/docs/config/context.xml b/webapps/docs/config/context.xml index de12d2d60..852f09f24 100644 --- a/webapps/docs/config/context.xml +++ b/webapps/docs/config/context.xml @@ -251,6 +251,16 @@ + +

This attribute provides a list of external locations from which to + load resources for this context. These external locations will not be + emptied if the context is un-deployed. 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 .war file or + a directory.

+
+

If the value of this flag is true, symlinks will be allowed inside the web application, pointing to resources outside the