Chapter 2. Tomcat Installation

Table of Contents

Distributions
Tomcat Instances
Install
Setting up Multiple Instances
Configuration
Shared Jar Files
HTTPD-to-Tomcat Plugins
Tomcat-side Plugin Configuration
httpd-server-side Plugin Configuration
Webapp Staging Directory

Distributions

Before you do anything, you need to decide what version of Tomcat you want to run. Consider the following factorys.

  • Conformance levels of Servlet spec, JSP spec, JDK version support, etc.
  • Stability. In my experience, the 5.0 series is most stable.
  • Generally stay current. If you are running a version that many other people run, it's easier to get Internet support for Tomcat itself as well as third party products with Tomcat, and third party libraries are more likely to work more likely to work right
  • Requirements of your organization.
  • Availability of pre-configured distributions. I.e., software distributions, perhaps customized, by your organization or your operating system vendor.

Note

This guide covers only major versions 5.0.x and 5.5.x. I have no desire to use 4.x versions-- they suck. I look forward to using 6.x, but have had no opportunity to yet.

If your OS distribution comes with a Tomcat distro of a version that you're satisfied with (or if your organization provides one), then you could simplify your life by using that... or not. Otherwise, go to http://jakarta.apache.org and download the latest stable (non-alpha and non-beta) core binary of desired major version. Just get the one Core file in the file format that you want (For UNIX users, I recommend using that tar.gz format intead of the zip. Otherwise you will need to make the script files executable). For version 5.0.x, get just the core download, which contains the Manager and Admin web apps, and documentation. For version 5.5.x, get the core download, which contains the Manager web app and docs; plus the Admin download if you want to run the Admin web app; and the JDK 1.4 Compat download if you plan to use Java version 1.4. (If you don't run the Admin web app, you will need to edit the server.xml file manually for every configuration change to the Tomcat server).

The Deployer download is not needed for a server install. This is not the Manager webapp, but a Java client for the Manager webapp. You install this on a workstation or server where you will run ant to deploy to the remote Tomcat server. (Not that you necessarily want to do that. It's overkill if you will only be deploying locally, and there are other ways to deploy remotely).

If you're using preconfigured packages, install them. Besides the base package, install packages for standalone docs, admin and manager webapps, samples webapp and docs webapp if you want them. It's a hard call whether to use OS-supplied Tomcat packages. The benefit is, upgrades are a snap, and can be automated, and, best of all, if your OS has packages for Apache HTTPD and a Tomcat plugin, 99% of the plugin setup is done for you.

Tomcat Instances

You won't understand much of this document if you don't have a clear understanding of installation and instance.

A Tomcat installation is one set of all the stuff that you extract from a Tomcat distribution (or packages, rpms, etc.). You could very well have multiple installations on the same server, for example, a Tomcat 5.5.9 installation and a Tomcat 5.0.28 installation. There is no good reason to have multiple installations of the exact same Tomcat distribution, since you can run as many Tomcat instances as you want using one Tomcat installation. The env variable CATALINA_HOME identifies the tomcat installation root directory for the current environment.

A tomcast instance is a single Tomcat JVM (and also the set of files specific to this tomcat instance). People often use the word server for the same purpose. I try to use the word instance to avoid any ambiguity with the other uses of server. The env variable CATALINA_BASE identifies the tomcat instance's root directory for the current environment.

The file conf/server.xml for each CATALINA_BASE is where most of your instance-based configurations are persisted, for example what port to run on, where to write log files, etc. The primary goal of the Admin webapp is to manage this file (but most people edit it it manually instead). Because of its importantce, you should take some time to study it. The Tomcat documentation explains about half of it well. The XML tags and attributes are named pretty intuitively. One question that most people have when they look at it is, What are all of those ports for?. There is the main http port that will server your webapps to browsers, SOAP clients, etc. There is the Coyote port that will service plugin clients. The AJP protocol is used between plugins and Tomcat, so you can't use it for any other purpose. There's also the shutdown port. You can telnet to this port on localhost, type SHUTDOWN and hit ENTER to shut down the instance. Then there are SSL versions of these three ports (all of which care commented out by default).

Install

I recommend that you install the distro as the super-user, and leave everything from the distributions writable only to the superuser. After that you copy the small set of read-write files and open up write privileges for this set. This directory branch of instance-specific, writable, files is called the CATALINA_BASE for the instance. This is useful for a single-user system because when Tomcat gets screwed up (as it eventually will), it is very easy to start a new instance up (with its own CATALINA_BASE), or just wipe out your hosed CATALINA_BASE with a new copy from the distro. If you plan to run multiple Tomcat instances (for yourself or to be shared), then you definitely should use CATALINA_BASEs.

If you have superuser privileges, I recommend that you run your Tomcat instance as a dedicated non-privileged user. Unless you already have a tomcat account, create a user and group with name "tomcat".

cd to the parent directory of where you want your Tomcat installation to live (parent directory because the extraction will create one subdirectory which will contain everything). Extraction will create a new subdirectory with name like jakarta-tomcat-5.0.28. If you are installing 5.5.x, extract the Admin distro file from the same place (if you want the Admin web app). After you extract everything, you can shorten the installation root directory name if you like (I get along just fine without the "jakarta-" part). A common practice on UNIX is to make a peer sym-link to the "current" version with no version number in it, like

    mv jakarta-tomcat-5.0.28 tomcat-5.0.28
    ln -s tomcat-5.0.28 tomcat
This directory is your CATALINA_HOME. Just to make the examples below really work, I'll assume that you set the environmental variable CATALINA_HOME to the absolute path of this directory.

Your CATALINA_HOME contains the following subdirectories.

  • bin
  • common
  • conf*
  • logs*
  • server
  • shared
  • temp*
  • webapps*
  • work*
(Each Tomcat instance gets a copy of the starred directories. The remaining directories are shared among all Tomcat instances).

Users installing the 5.5.x JDK 1.4 Compatibility distro should be aware that (at least for the versions I have installed), they use a different root directory name for the Compat bunlde, so you can't just overlay it on top of your core installation (like you can with the Admin distro). You'll need to extract the JDK Compat distro to a temporary location then copy it like so.

    mkdir /tmp/tctemp
    cd /tmp/tctemp
    tar -xzvf /path/to/jakarta-tomcat-5.5.28-admin.tar.gz
    ...
    cd jakarta-tomcat-5.5.28-admin
    cp -a * $CATALINA_HOME
    ...
    cd
    rm -rf /tmp/tctemp
Overwrite all files if prompted by your copy command.

I recommend that you edit the web.xml for the bundled default ROOT web app. to make your site home page editable. If you will always install your own ROOT web app (i.e., a web app with context root of "/"), or will otherwise never use Tomcat's default ROOT web app, just skip this paragraph. Tomcat comes with a great default web app, with a great home page with links to the bundled web apps and documentation. It just makes sense to add your own links to this home page-- at least to the web apps that you install, but also perhaps to application log file or external documentation. Unfortunately, recent versions of Tomcat precompile the home page JSP so that you editing the home page will have no effect. The easy work-around for this is to edit the file CATALINA_HOME/webapps/ROOT/WEB-INF/web.xml and just comment out the <servlet> and <servlet-mapping> stanzas at the bottom. This is a one-time customization. Whenever you set up a CATALINA_BASE from now on (as described below), the home page for the instance will be editable.

As described above, CATALINA_HOME is where you installed the Tomcat distribution to. CATALINA_BASE will be the root directory of your new instance. Now make the CATALINA_BASE for your first (or only) Tomcat instance by making a new CATALINA_BASE directory anywhere. If you anticipate running multiple Tomcat instances, you may want to make a new directory to be the parent to all of the instances, then make the CATALINA_BASE within that. For example .../tomcat-intances/balder1. For the purposes of my examples, I'll assume that you set the variable CATALINA_BASE to the absolute path of this directory. Copy the five starred CATALINA_HOME subdirectories above to there. Then set ownership to your instance owner and group. Assuming that you've set variables CATALINA_HOME and CATALINA_BASE, you can do it like this on UNIX.

    mkdir $CATALINA_BASE
    cd $CATALINA_HOME
    cp -a conf logs temp webapps work $CATALINA_BASE
    chown -R tomcat.tomcat $CATALINA_BASE
Assuming that you've set the same Windows environment variables, and that we're just working with one disk drive, on modern Windows you do it like this.
    mkdir %CATALINA_BASE%
    cd %CATALINA_HOME%
    xcopy /e /i /q conf %CATALINA_BASE%\conf
    xcopy /e /i /q logs %CATALINA_BASE%\logs
    xcopy /e /i /q temp %CATALINA_BASE%\temp
    xcopy /e /i /q webapps %CATALINA_BASE%\webapps
    xcopy /e /i /q work %CATALINA_BASE%\work

Tip

One way to set environmental variables in modern Windows operating systems is by using menus Windows / Start / Control Panel / System, Advanced tab, Environment Variables button, New button under System variables.

One difficulty you will have to live with if you're using Linux Tomcat packages is, the actual instance files are spread out all over the place, with sym-links from the CATALINA_BASE. It's not all that difficult if you leave the default CATALINA_BASE alone to use as a model. For example, on Suse, it sets up a CATALINA_BASE named base with CATALINA_BASE of /srv/www/tomcat5/base. This CATALINA_BASE has sym-links to a config file under /etc, log, temp, and work directories under /var, but a real webapps directory. Duplicate the same exact setup for your own instance, like /srv/www/tomcat5/yourinstance.

Make the webapps directory writable to whoever you want to permit to deploy by copying files into there.

    chown -R deployer $CATALINA_BASE/webapps
    chmod gw+s $CATALINA_BASE/webapps
(Understand that if you use the Manager webapp for remote deploys, the deployed objects, normally wars, will have the user and group of the Tomcat process, not of the remote user, and the final file permissions will depend on how you do the remote deployment.) You may want to change permissions on the files conf/server.xml and or conf/*user* to people who can directly edit the main instance configuration file and the password file used by the bundled management webapps. But, Tomcat rewrites these files sometimes, so don't be surprised if the file attributes get changed on you.

Setting up Multiple Instances

If you followed my advice above, then you just repeat the CATALINA_BASE creation step above for each instance, then edit the server.xml file as described in the following subsection.

The Tomcat documentation says that you must edit the descriptors for the bundled webapps. That documentation is wrong, because the settings use filepaths relative to CATALINA_BASE, which works exactly as needed.

Configuration

Dear reader, please make a detour now and read the introductory and Initial Instance Configuration sections of the Configuring Tomcat chapter. You really need to understand that material before consuming the remainder of this chapter.

Shared Jar Files

Generally, you want to bundle needed jar files in your web app. That will avoid most dependency conflicts with other web apps, and reduces dependencies on things outside of the war file. For example, it won't matter if Tomcat or other web apps have the right version of a lib, because you have it yourself. It also means that your war will be more likely to run as-is on some other application server. The trade off is inefficiency of disk space and memory, when multiple wars bundle equivalent jar files. The inefficiency problems are trivial compared to the alternative.

Exceptions to the general rule are for the mail api and JDBC drivers. In both cases, the exceptions are justified only so that you can manage the mail and data source services as the app server level as shared resources. With Tomcat 5.5.x only, Tomcat doesn't bundle the email libraries because of copyright laws. (Ignore the rest of this paragraph if you're running a version an earlier version, since it will include these two jar files). Therefore, obtain the JavaMail and Activation Framework jars and copy them into CATALINA_HOME/common/lib. These jar files are often named mail.jar or mailapi.jar and activation.jar or jaf.jar correspondingly (or the same with version numbers).

Warning

CATALINA_HOME/shared/classes and jars in CATALINA_HOME/shared/lib are not added to the runtime classpath, at least with Tomcat 5.5.x. I think something broke, because these folders serve no purpose without this behavior. I know it used to be there, but there is no longer an explanation of the purpose of the different Tomcat directories in the 5.5.23 docs. Always use the CATALINA_HOME/common branch for shared resources, not CATALINA_HOME/shared

The other exception is JDBC drivers. In the J2EE world, application servers have the responsibility of managing data sources which apps look up via JNDI. Therefore, if you are going to get your data sources by the traditional J2EE method, you need to put your JDBC driver jar files for your target database servers into CATALINA_HOME/common/lib. If you are not getting your datasources from a JNDI lookup (regardless of whether there is an ORM, Spring, or any other lay in between), then I recommend that you bundle your JDBC libraries with your app (for the reasons given above) and purposefully do not put them in any shared directory.

(If Tomcat is running when you change any files under CATALINA_HOME/common/lib, you will need to restart Tomcat for it to see the changes).

At least with Tomcat 4.x, Tomcat does not recognize zip files in the the global lib directories, only .jar files. This isn't much of an issue nowadays since Oracle, the last holdout, has finally stopped using zip files when they should be using jar files.

HTTPD-to-Tomcat Plugins

I assume you're using an Apache HTTPD server (including branded Apache HTTPD servers, such as those by IBM and Oracle). If you're using some other web server, like IIS, you're on your own. I'm only documenting use of jk. Setup of other plugins is similar, but jk has the widest user base (by far), and is actively supported. The Apache HTTPD server is often just called the Apache server, even though Apache also makes the Tomcat server. To try to avoid this ambiguity without being too verbose, when I say httpd server in this section, I mean the Apache HTTPD server.

Note

You can use the httpd server's mod_proxy module instead of a plugin. This is do-able, but has its own set of quirks, which I don't have time to document. I recommend that you use the most common setup-- the JK plugin-- unless you just can't get it to work. (The only valid reason I've encountered is that you have to support a version of httpd server for which you can't build the JK plugin).

Use pre-packaged binary distributions if at all possible, due to dependency requirements, which are detailed below.

Tomcat calls a network listener which connects clients to the Tomcat engine a Connector. (They probably want to avoid possible confusion with lifecycle listeners, which are defined with <Listener> tags in the server.xml> file).

To get a possible point of confusion out of the way, be aware that all of the modern Tomcat connectors are Coyote connectors. All of the connectors you use will be Coyote connectors. (The SHUTDOWN network listener is not a Connector, since it does not connect to any Tomcat engine). Most significantly, when I speak of an HTTP connector or an AJP connector, I mean the Coyote HTTP or Coyote AJP connector, not some other, deprecated implementation. I point this out because this was apparently not the case in the past, since Tomcat documentation and config file comments imply some significance to "Coyote".

Tomcat-side Plugin Configuration

The only setup for the Tomcat side is to enable the AJP 1.3, Connector, and that will already be enabled unless you deleted or commented it out from your template server.xml file. However, read this section to make sure that it is running, and to find out what network target to have your Apache plugin connect to. If something else is occupying the default AJP 1.3 listener port (perhaps another Tomcat instance), you will need to change the port number (see the Configuring Tomcat chapter for tips about finding available ports).

Take a look at CATALINA_BASE/conf/server.xml. Search for all uncommented <Connector> tags. By default, there will only be two, one HTTP connector and one AJP 1.3 connector: search for "AJP/1.3". Both of the Tomcat-supplied server.xml files have misleading comments about this element, so just ignore them. I will be calling this connector the AJP connector, since we are only concerned with AJP version 1.3, and the connector just serves AJP and doesn't mandate that the client be JK, JK2, or anything else (you can write your own AJP 1.3 client). Note the port number for the AJP connector. I suggest that you remove the voluminous commented examples of SSL connectors-- it clutters the file up with crap that you will never use.

httpd-server-side Plugin Configuration

When I talk about Apache configuration directives, I will give the Apache 2 module variant. See your docs if you are running some other Apache variant. In all cases, you can track down all Apache config files by recursively following the includes from the main httpd.conf file (which latter filepath has a compiled-in default which can be overridden on the httpd command line or use a compiled-in default).

httpd-server-side Plugin Configuration

native shared libarary

This can be the most difficult step of all. The .so binary must compatible with your version of Apache and it must use the same version of AJP as your Tomcat distribution. (If you are following these instructions, the second dependency will be taken care of if you just stick to AJP version 1.3). The shared library will be called something like mod_jk.so. Hopefully, your can get a pre-built binary with your Apache or OS distribution. Otherwise, download the source and build it, according to the very detailed instructions--- good luck. Stick the .so file into the same directory as all of your other native Apache module libraries.

Suse users can find mod_jk.so in the rpm apache2-jakarta-tomcat-connectors or mod_jk-ap20 (in the latter name, the 20 means that it is for Apache version 2.0).

Building is not difficult on Linux if you have a the Apache 2 developer rpm (including apxs version 2) and gcc. It can be incredibly difficult on other UNIXes.

workers.properties

You must set the worker properties. If you are running JK version 1.2.7 or later, you can set them in your httpd server config file (exactly as described in the following section) with JkWorkerProperty directives. All versions may make these settings in a workers.properties file, and that is what I explain here (only because most binary distributions which I encounter are always pre-1.2.7; and for most distributions, you can't even tell the JK version number). If you have version 1.2.7 or later, I recommend you use JkWorkerProperty-- read this section, but forget the workers.properties and make the corresponding JkWorkerProperty as explained in the next section.

Note

SuSE v. 9.3 and 10.0 both have version 4.1.30 of mod_jk-ap20, which contains a beta of JK version 1.2.6. Can you believe that shit? A year and a half old, and they can't even use a production cut.

This file defines the Tomcat server destinations that you can route to from your httpd server instance. You assign each Tomcat server destination a worker name, and you can then use that name to redirect specific request URLs from the httpd server to this Tomcat worker instance (as described in a following step).

Like I said, the workers.properties file just needs to define the Tomcat worker instances which you want to make available to your httpd server instance. If you have a sample file, just wipe it out, because in the great majority of cases, you only need four lines. (Most JK distributions come with a sample file filled with inappropriate settings... you're better off without the sample).

Example 2.1. workers.properties file

    worker.list=tomcatWorker1
    worker.tomcatWorker1.port=8009
    worker.tomcatWorker1.host=localhost
    worker.tomcatWorker1.type=ajp13

You should see that we have defined the destination Tomcat instance tomcatWorker1. All of the worker.WORKERNAME.* settings must match the settings for that Connector in your Tomcat server.xml (which is explained above). If you have a distributed, load-balancing setup, see the docs about additional settings, and the Tomcat docs about the server.xml jvmRoute setting..

Note

Most documentation which I can find instructs to place the workers.properties under CATALINA_BASE. That is a stupid place to put this file, since (a) the file is read by httpd server, not Tomcat, and (b) If you have a distributed setup, this file must accompany your httpd server instances, not any Tomcat instance. The Tomcat JK docs give the false impression that the workers.properties is part of the Tomcat configuration (as definitely proven by the fact that with recent versions, the functionality can be taken over entirely by using httpd server directives).

Apache Runtime Directives

These settings all need to go into httpd server config file(s), either a main httpd.conf, or a file included directly or indirectly. Which file(s) you put them into depends upon whether you want the settings shared by all virtual servers or not, and by the fact that some global settings must appear before site-specific settings. I recommend that put your global settings directly in httpd.conf, and all other settings directly wherever your (virtual) site-specific settings like DocumentRoot are. To get JK working with other virtual hosts, just duplicate the vhost-specific settings you made for your first vhost.

Tip

Attention name-based virtual host users. This has nothing to do with Tomcat specifically, but it is something that is very non-intuitive for standard httpd name-based server setups. The default httpd.conf delivered with many Apache 2 distributions includes a default-server.conf file which works fine, but not if you use name based hosts. The reason is, this file has useful settings for documentRoot, etc, but, since they are not in a virtual host block, they will always be overridden by your first virtual host definition (which default host is determined alphabetically with the default setup). For security alone, you should not send users to a random site accidentally. What a sane person would want to happen is that requests for URLs which match no defined virtual host name should use the settings in the default-server.conf file. You can accomplish this easily and elegantly by defining a default VirtualHost before including your virtual host files. Just insert the following directives after the Include /etc/apache2/default-server.conf and before the Include /etc/apache2/vhosts.d/*.conf.

Example 2.2. Make the default-server config the default virtual host

    NameVirtualHost *:80
    <VirtualHost *:80>
        # Just inherit all the settings in /etc/apache2/default-server.conf
    </VirtualHost>

The critical point here is to insert it at the location specified.

You need to load the JK module with a directive like LoadModule jk_module /usr/lib/apache2/mod_jk.so, specifying the filepath to the native library file. This is a global level setting, since you just load the module one time, regardless of how many virtual sites or Tomcat worker instances you have. (Suse user be aware the Suse has an idiotic system where they rebuild the LoadModule directives dynamically. You set the variable APACHE_MODULES, in the file /etc/sysconfig/apache2, to the base names for all modules, with the assumption that the native library files all reside in the normal directory, and are named according to the supplied module name.

You need to specify the path to the workers.properties file, like JkWorkersFile /etc/apache2/workers.properties. This is a global level setting, since you just need tone workers file for an entire httpd server (because one workers file can define any number of Tomcat worker target instances). If you are not using workers.properties file (see previous step), then, instead of a JkWorkersFile directive, give a JkWorkerProperty directive for each worker property you need (which are described in the previous section--- for example, JkWorkerProperty worker.tomcatWorker1.port=8009.

You need to specify the path to the log file for the httpd-server-side of JK, like JkLogFile /var/log/tomcat5/base/mod_jk.log.

You can specify a logging level of trace, debug, warn, error, if the default level of info doesn't suit you. For example JkLogLevel error.

Tell httpd server to serve all static webapp content directly. The httpd server must have access to the exploded webapp files to serve them directly (i.e., they must reside on the physical httpd server in exploded-- not war file-- state, and must be readable to the httpd server process owner). Most importantly, you must use Directory directives to cover all of the webapp directories, so that httpd can serve them. You need the Directory directives regardless of how you graft onto the URL tree. If you have Tomcat and httpd server running on the same server, then give a JkAutoAlias directive to tell the httpd server to automatically graft all webapp directories into the httpd URL namespace and serve them directly. The JkAutoAlias directive is just an alternative to giving Location and DocumentRoot directives for the different webapp directory branches. If you only want Apache to serve static content from a subset of the Tomcat webapps, then use normal Location and DocumentRoot directives instead of JkAutoAlias. If Tomcat is running on a different physical server, then you will have to explode all of the wars on the httpd server computer and then use one of the two methods above to serve these directories. (The JkAutoAlias just requires that the webapps all reside in one parent directory). You should understand that nothing in this paragraph will cause any interaction with Tomcat, it just tells Apache to serve some stuff in normal non-Tomcat fashion. The next paragraph tells how to forward requests on to Tomcat.

Caution

The JkAutoAlias does not know about the root context web app. Therefore, requests for http://hosthame:port/file.txt will not map to WEBAPPDIR/ROOT/file.txt, which would be the desired thing to do. JkAutoAlias is really useless for a default context webapp. You'll have to use other Apache directives to serve it.

Note

JkAutoAlias is smart enough to never serve information from underneath WEB-INF of your webapps.

Note

If you get an error upon UNIX startup about the command JkUnMount, then you probably have an ancient jk_mod binary. Either live without JkUnMount, or obtain or build a recent JK library.

Tell Apache which URLs to forward to Tomcat with the JkMount and JkUnMount directives. Both take a URL pattern and a Tomcat worker instance name. JkUnMount commands take precedence over JkMount commands, regardless of the sequence in which they appear. Here's an example that shows both commands.

    JkMount /servlet/* tomcatWorker1
    JkUnMount /servlet/*.gif tomcatWorker1
In this case, requests for requests of the form http://hostname:port/servlet/ will not be forwarded to Tomcat, due to the higher precedence of JkUnMount commands.

Note

Some JK distributions put samples of these settings into a file named jk.conf, or similar. In most cases, this discourages effective directive sharing among multiple virtual servers. When running with multiple virtual servers, some directives should be made just once for the entire server, other settings should be duplicated for each virtual server, and others require unique settings for each virtual server. Since we are talking about a total of about four sharable directives, in nearly all cases it's simpler and more effective to just put each directive directly into the desired virtual-site-specific or main httpd.conf file. The actual URL-mapping directives, which comprise 90% of the needed directives, are virtual-server specific and can't be shared at all.

Example 2.3. Typical httpd.conf directives

    # These toward the top in the main httpd.conf file
    LoadModule jk_module /usr/lib/apache2/mod_jk.so
    JkWorkersFile /etc/apache2/workers.properties

    # These in virtual-server specific files, or with other site-specific
    # settings like DocumentRoot and site-specific log file settings.
    JkLogFile /var/log/tomcat5/base/mod_jk.log
    JkLogLevel error
    JkAutoAlias /opt/tomcat/webapps
    # Then specify all URL patterns to pass to Tomcat
    JkMount /servlet/* tomcatWorker1
    JkMount /*.jsp tomcatWorker1
    JkUnMount /*/WEB-INF/* tomcatWorker1

Webapp Staging Directory

Use of a Webapp Staging Directory avoids polling race condition problems if you deploy webapps by manually copying or moving files into the Tomcat webapps directory.

The problem occurs because Tomcat monitors the webapps directory and the first time it sees a new entry, it decides right then whether it will henceforth consider this entry a war file, a web app directory, or ignore it.

If it looks at the directory or war file before it contains the web.xml file (because the copy has not reached that point yet), then it won't attempt to deploy it at all and will ignore the whole thing from this point forward.

If it sees the web.xml, then it will attempt to deploy. If your copy has not finished, it will deploy only a portion of your webapp and will never finish it.

The solution to this problem is to not copy anything into the webapps directory, but to move to there from the same filesystem partition. From Tomcat's perspective, the move is an atomic operation. Before the move completes, it won't see the new item at all. After the move completes, the entire webapp is available for deployment.

The only real requirement for this to work is that you move the webapps/war from another directory in the same filesystem partition. If you work with multiple servers, then I highly recommend that you make a staging directory right under webapps specificaly for this purpose. For purposes of this document, I'll assume it is $CATALINA_BASE/webapps/stage. No matter what server you're on, you'll know that the staging directory is in the same partition as webapps, and it's really convenient to be able to cd to webapps and deploy and undeploy web applications with short commands like

    cd $CATALINA_BASE/webapps
    mv appToUndeploy stage
    mv warToUndeploy stage
    mv stage/appToDeploy