Index: java/org/apache/catalina/core/StandardHost.java =================================================================== --- java/org/apache/catalina/core/StandardHost.java (revision 1030113) +++ java/org/apache/catalina/core/StandardHost.java (working copy) @@ -18,10 +18,13 @@ import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.ListIterator; import java.util.Locale; import java.util.Map; import java.util.WeakHashMap; +import java.util.regex.Pattern; import org.apache.catalina.Container; import org.apache.catalina.Context; @@ -110,6 +113,18 @@ /** + * The ignored deploy paths for this Host. + */ + private String deployIgnorePaths = ""; + + + /** + * The ignored deploy path Patterns for this Host. + */ + private ArrayList deployIgnorePathPatterns = new ArrayList(); + + + /** * The deploy on startup flag for this Host. */ private boolean deployOnStartup = true; @@ -327,6 +342,53 @@ /** + * Return the list of regular expressions for files/directories + * excluded from automatic deployment. + */ + public String getDeployIgnorePaths() { + + return (this.deployIgnorePaths); + + } + + + /** + * Set the list of regular expressions for files/directories + * excluded from automatic deployment. + * + * @param ignorePaths A comma-separated list of regular + * expression strings. + */ + public void setDeployIgnorePaths(String ignorePaths) { + + String oldDeployIgnorePaths = this.deployIgnorePaths; + List newPaths = Arrays.asList(ignorePaths.split("\\s*,\\s*")); + ArrayList newPatterns = new ArrayList(newPaths.size()); + + for (ListIterator i = newPaths.listIterator(); i.hasNext(); ) { + newPatterns.add(Pattern.compile(i.next())); + } + + this.deployIgnorePaths = ignorePaths; + this.deployIgnorePathPatterns = newPatterns; + support.firePropertyChange("deployIgnorePaths", oldDeployIgnorePaths, + this.deployIgnorePaths); + + } + + + /** + * Return the list of Patterns for files/directories excluded from + * automatic deployment. + */ + public ArrayList getDeployIgnorePathPatterns() { + + return (this.deployIgnorePathPatterns); + + } + + + /** * Return the value of the deploy on startup flag. If true, it indicates * that this host's child webapps should be discovered and automatically * deployed at startup time. Index: java/org/apache/catalina/core/mbeans-descriptors.xml =================================================================== --- java/org/apache/catalina/core/mbeans-descriptors.xml (revision 1030113) +++ java/org/apache/catalina/core/mbeans-descriptors.xml (working copy) @@ -1160,6 +1160,10 @@ description="Should we create directories upon startup for appBase and xmlBase? " type="boolean"/> + + Index: java/org/apache/catalina/startup/HostConfig.java =================================================================== --- java/org/apache/catalina/startup/HostConfig.java (revision 1030113) +++ java/org/apache/catalina/startup/HostConfig.java (working copy) @@ -28,13 +28,16 @@ import java.io.OutputStream; import java.net.URL; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; +import java.util.ListIterator; import java.util.Locale; import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; +import java.util.regex.Pattern; import javax.management.ObjectName; @@ -460,17 +463,65 @@ File appBase = appBase(); File configBase = configBase(); + String[] fileList = validAppPaths(appBase.list()); // Deploy XML descriptors from configBase deployDescriptors(configBase, configBase.list()); // Deploy WARs, and loop if additional descriptors are found - deployWARs(appBase, appBase.list()); + deployWARs(appBase, fileList); // Deploy expanded folders - deployDirectories(appBase, appBase.list()); + deployDirectories(appBase, fileList); } /** + * Return the provided array of paths after removing those matching regular + * expressions configured via the Host's deployIgnorePaths. + * + * @param paths The file paths to be checked, presumably those within + * appBase. + * @return A String array containing the path list after excluding ignored + * paths. + */ + protected String[] validAppPaths(String[] paths) { + + if (!(host instanceof StandardHost)) { + return paths; + } + + ArrayList ignorePatterns = ((StandardHost) host).getDeployIgnorePathPatterns(); + + if ((ignorePatterns == null) || (ignorePatterns.size() == 0)) { + return paths; + } + + ArrayList goodPaths = new ArrayList(Arrays.asList(paths)); + + for (ListIterator i = goodPaths.listIterator(); i.hasNext(); ) { + String path = i.next(); + + for (ListIterator j = ignorePatterns.listIterator(); j.hasNext(); ) { + Pattern ignorePattern = j.next(); + + if (ignorePattern.matcher(path).matches()) { + if(log.isDebugEnabled()) { + log.debug("Ignoring application path \"" + + path + "\" (matches pattern \"" + + ignorePattern.pattern() + "\")."); + } + + i.remove(); + break; + } + } + } + + return goodPaths.toArray(new String[0]); + + } + + + /** * Deploy applications for any directories or WAR files that are found * in our "application root" directory. */ Index: webapps/docs/config/host.xml =================================================================== --- webapps/docs/config/host.xml (revision 1030113) +++ webapps/docs/config/host.xml (working copy) @@ -189,6 +189,27 @@ is false, this attribute will have no effect.

+ +

A comma-separated list of regular expressions of paths to + ignore for autoDeploy and + deployOnStartup. This allows you to keep your configuration + in a version control system, for example, and not deploy a .svn or CVS + folder that happens to be in appBase.

+

These regular expressions are relative to appBase. They + are also anchored, meaning the match is performed against the + entire file/directory name. So, foo matches only a file or + directory named foo but not foo.war, + foobar, or myfooapp. To match anything with + "foo", you would use something like .*foo.*.

+

From a performance standpoint, a single regular expression using + alternation will be more efficient than separate regular expressions. + For example, deployIgnorePaths set to + foo\.war|bar has the same effect as + foo\.war,bar, but the former is more efficient.

+

See Automatic Application + Deployment for more information.

+
+

Set to false if you want to disable parsing the context XML descriptor embedded inside the application (located at @@ -337,14 +358,15 @@ ROOT.xml.

  • Any web application archive file within the Host's appBase directory that has not already been deployed as a result of a context - XML descriptor and does not have a corresponding directory of the same - name (without the ".war" extension) will be deployed next. The context - path used will be a slash character ("/") followed by the web - application archive name less the ".war" extension. The one exception to - this rule is that a web application archive named "ROOT.war" will be - deployed with a context path of /. Multi-level contexts may - be defined by using #, e.g. use a WAR named foo#bar.war for - a context path of /foo/bar.
    + XML descriptor, does not have a corresponding directory of the same + name (without the ".war" extension), and is not excluded by + deployIgnorePaths will be deployed next. The context path + used will be a slash character ("/") followed by the web application + archive name less the ".war" extension. The one exception to this rule + is that a web application archive named "ROOT.war" will be deployed with + a context path of /. Multi-level contexts may be defined by + using #, e.g. use a WAR named foo#bar.war for a context + path of /foo/bar.
    If the unpackWARs attribute is true, the web application archive file will be expanded to a directory of the same name (without the ".war" extension".
    @@ -363,11 +385,12 @@
  • Finally, any sub-directory within the Host's appBase that has not already been deployed as a result of a context XML descriptor - will be deployed. The context path used will be a slash character - ("/") followed by the directory name, unless the directory name is ROOT, - in which case the context path will /. Multi-level contexts - may be defined by using #, e.g. use a directory named - foo#bar for a context path of /foo/bar.
    + and is not excluded by deployIgnorePaths will be deployed. + The context path used will be a slash character ("/") followed by the + directory name, unless the directory name is ROOT, in which case the + context path will /. Multi-level contexts may be defined by + using #, e.g. use a directory named foo#bar for a context + path of /foo/bar.
    If copyXml is true (it is false by default), any directory within the Hosts's appBase directory that does not have a corresponding context XML descriptor in @@ -420,15 +443,16 @@

    When using automatic deployment, the docBase defined by an XML Context file should be outside of the - appBase directory. If this is not the case difficulties + appBase directory. If this is not the case, difficulties may be experienced deploying the web application or the application may - be deployed twice.

    + be deployed twice. The deployIgnorePaths attribute can be used + to avoid this situation.

    Finally, note that if you are defining contexts explicitly in server.xml, - you should probably turn off automatic application deployment. Otherwise, - the web applications will each be deployed twice, and that may cause - problems for the applications. -

    + you should probably turn off automatic application deployment or specify + deployIgnorePaths carefully. Otherwise, the web applications + will each be deployed twice, and that may cause problems for the + applications.