by Steven J. Owens (unless otherwise attributed)
I just spent a few hours talking a friend through troubleshooting a broken servlet app installed on a Tomcat server. This friend is a competent system administrator, but an absolute beginner with Tomcat and servlets. It struck me that -- although of course it's better to truly understand what a server application is about -- from the point of view of a sysadmin who mostly dealing with apps like Tomcat from the outside there are a set of key details that tend to be buried in, and spread out across various docs.
To solve this, I wrote up a cheatsheet, available at:
Below, I further discuss the sections of the cheatsheet. You can think of the cheatsheet as a summary of the details of this discussion.
Note: I'm assuming you're setting up tomcat to run a specific, particular webapp.
I started the cheatsheet off with a step-by-step list of the big-picture tasks, the major steps in the process. That was mainly to give you a roadmap of the overall process, but this is not a step-by-step tutorial on installing tomcat. There are plenty of existing step-by-step tutorials already on on the web. This is more of a short summary covering the details in the cheatsheet.
Tomcat is part of the Apache project, specifically the Jarkarta sub-project of the Apache project. However, in this document I'm going to refer to the Apache HTTPD server as "apache" and tomcat as "tomcat", because that's the common usage. I'm going to refer to your webapp as webappname, and in general I'm going to try to use blatant placeholders for any values you should supply (like "yourusername").
Tomcat serves web applications; in the java world, "web application" has a specific meaning -- literally a specified meaning, specified in the Sun servlet specification. A java web application is a bundle of JSP page files, java classes (java servlet classes and also java business logic classes, etc), config files, libraries and static files (image files, even static HTML files) that, together, implement a highly dynamic application with a web-based user interface.
Tomcat is a java program, which means you need Java (and probably the full JDK) to run it.
Tomcat runs as a separate process, but can run multiple webapps under that single process. However, it is quite common for hosts to deploy each tomcat webapp in its own tomcat process.
Tomcat has a full HTTP implementation and can run stand-alone, and in fact should be run stand-alone for best scalability. Historically it has often been run with Apache as a front-end proxy, but doing that halves the scalability of tomcat (see the benchmarks in Tomcat: The Definitive Guide, 2nd Edition to learn why). When tomcat -- despite all the benchmarks -- is run with an apache front-end, apache receives requests and relays them to tomcat, and relays the responses back to the web browser, via the AJP protocol, implemented in mod_proxy_ajp.
The webapps are kept in the tomcat installation's webapps directory, analogous to Apache's htdocs directory. Where apache would have an htdocs for each domain it serves pages for, Tomcat has a subdirectory under webapps for each webapp it serves.
The files that comprise a webapp are in a specified directory layout, and that directory layout and the files inside it are usually bundled up (with some extra config files) in a binary format very similar to a tar file or jar file, called WAR file (Web Application Archive). The WAR file is copied into the webapps directory either manually, or uploaded via a web form in the manager app that comes installed by default in tomcat, or more recently by using a separate tomcat deployment program.
For more discussion of WAR files, see the Webapp Deployment section below.
For more discussion of web apps, servlets, JSP pages, etc, refer to the Webapp Concepts section at the end.
You can download Java and Tomcat in tar.gz or RPM format. For Java, download from:
For Tomcat, download from:
You can also download a tomcat RPM created by Jason Brittain (author of Tomcat: The Definitive Guide) which provides a few extra system-specific tools (init scripts, etc) from:
However, in the past few years Java has been more successful in working with the open source world, so now, you can install more automatically using yum on centos or apt on debian or ubuntu. (Tomcat has been available in packaged form for an even longer time, as it started in the open source world.).
Note: Jason Brittain warns that there are some problems in the init scripts in the older packaged tomcat installations, which will cause unreliable restarts (which then lead to "a rash of problems"). At the time of this writing (late Feb, 2010) Jason has sent in fixed init scripts for the debian and ubuntu tomcat6 packages, but they aren't yet in the stable release. Ubuntu 10.04 Lucid Lynx will have the fixed init script. Until then, you may want to avoid using the init scripts in the packaged versions, and instead use Jason's RPM. See the note in the Standard HTTP/HTTPS Ports and Root Permissions section for a link to Jason's blog post with more info.
Typically both the Java installation and the Tomcat installation are (each) a single directory hierarchy full of files. Apache mod_proxy_ajp, (assuming you don't care about scalability) is part of the Apache installation. Packaged installs tend to put files in multiple places, according to the linux distribution's standards (e.g. config data in /etc, binaries in /var/lib, writable data like webapps in /var/share).
For more info on the ubuntu packaged release:https://help.ubuntu.com/8.10/serverguide/C/tomcat.html
As of this writing, the most current version of tomcat is 6.0.24. There are several critical fixes in 6.0.24, so don't set up a new installation of tomcat using anything older than 6.0.24.
In terms of visible functionality, i.e. not bug-fixing and general performance improvements, there are only minor functional differences between versions, and good support for downward compatibility. The big exception is the jump from Tomcat 4 to Tomcat 5, which had some important and, unfortunately, not downward-compatible changes in configuration files. However, this is not the case for Tomcat 5 to Tomcat 6. If you upgrade from 5 to 6 it should be pretty painless, and you'll get significant improvements in performance and reliability.
Note: Jason Brittain warns that there are some problems in the init scripts in the older packaged tomcat installations. For more details, see the note in Downloading, above.
I will generally just call the top-level directory "tomcat". This is not exactly normal; convention is to refer to it as CATALINA_HOME (see next section), but I find that too awkward. I'll trust you to to keep track of where you installed it.
If you installed tomcat with the debian or ubuntu package management system, you can do the following to figure out where it was installed:
To get the exact package name:
$ sudo dpkg -l | fgrep -i tomcat
To see what files and where:
$ sudo dpkg -L tomcat6
If you installed tomcat using Jason Brittain's RPM:
$ rpm -ql tomcat
If you installed tomcat using some other RPM:
$ rpm -ql tomcat6
You're almost certainly going to need the JDK (Java Developer's Kit) not the more limited JRE (Java Runtime Environment) because the JSP compiler that is bundled with the Tomcat distribution compiles the JSP to java source and then invokes the JDK's javac to compile that to java bytecodes.
It is possible to pre-compile JSPs, and if you're solely using an application that is distributed with pre-compiled JSPs, then the JRE alone may be sufficient. However, that's not done very often, and I personally haven't ever bothered to mess with it, since installing the full JDK is quite easy.
Mostly tomcat is controlled by configuration files. There's one environment variable you need to set at this point to get things running, JAVA_HOME. The others, you'll see mentioned a lot in log files, script responses and other documentation, so I'll describe them here as well.
Tomcat, like most java programs, depends on the environment variable JAVA_HOME, which should point to the top level directory of the JDK installation.
If you installed java and tomcat using a package management tool, it's likely that the system scripts and configuration changes were included to automatically set this variable and start up tomcat.
See the Scripts section below, and specifically the script version.sh, for help in troubleshooting your environment variables.
In documentation, etc, the top directory of a Tomcat installation is usually called CATALINA_HOME, because that's the name of the environment variable that has to be set so Tomcat knows where to find its bits. The name comes from an early Tomcat project, code-named Catalina.
You usually won't have to set CATALINA_HOME yourself. Tomcat's startup.sh script will set it for you, based on the script file's location. Normally the startup.sh script will assume that its current working directory (e.g. the directory where you find the startup.sh file) is in "CATALINA_HOME/bin".
There's also a CATALINA_BASE environment variable, but 99.999% of the time that should be identical to CATALINA_HOME. Or rather CATALINA_HOME should be identical to CATALINA_BASE.
CATALINA_BASE comes in handy when you want to have multiple separate running instances of Tomcat. You can have each instance use a different CATALINA_HOME, but all use the same set of Tomcat binaries from a single CATALINA_BASE. That's advanced stuff, however; I'm only mentioning it so you won't see CATALINA_BASE somewhere and wonder what's going on.
Note: You probably don't want to tweak these settings right away. The actual values you want to use depend on your webapp, usage pattern and server resources. Hit google and you'll find all sorts of advice and discussions about these settings. About the only thing you can say for certain is that the default java settings for memory usage are surprisingly low, especially if you're running a multi-user server app. I recommend coming back to this section after you get everything up and running and get a sense of what values you need. However, I'll describe them here so all of the environment stuff is in one spot.
The one environment variable you may want to tweak is the JAVA_OPTS variable, to add settings for java memory usage, -Xmx and -Xms. These settings control the JVM's maximum and initial memory allocation. For example to set both values to 512 megabytes:
First, check the current environment to see if that variable is already set:
$ echo $JAVA_OPTS
$ export JAVA_OPTS = "-Xmx512m -Xms512m"
One tip: It's very common for application servers to use the same setting for both maximum and initial memory allocation. The argument is that for servers, you want to allocate all of your memory at once, so it's less fragmented, and you can always count on the server having all of the memory you want it to, and you get the overhead of memory allocation out of way at startup time. For more info, google.
Another tip: JAVA_OPTS is for all java applications running under that environment. If you grovel through catalina.sh you'll also see CATALINA_OPTS, which you can set to make sure that you only affect tomcat and not any other java programs. I've never bothered, because I always set all of these things in a script file to invoke tomcat, and I've never had a separate java program running under the same environment.
This may be going a bit over the top, but there's a nifty tool for monitoring tomcat's memory usage, Lambda Probe:
This quickly gets outside the scope of this article, but you should be aware that there are also a variety of other settings you can set to tweak memory handling, garbage collection, JVM behavior, etc. See the JDK docs for more info.
Another setting you may want to check on is the system ulimit setting. The ulimit setting controls the limit on how many file handles a single process can have open. Since the unix philosophy is to treat nearly everything as a file, this is trickier than it seems. Running out of file handles can be reported as an OutOfMemory error, which may take a while to figure out. Most flavors of unix have a reasonably high default ulimit these days, but just in case, check.
The right way to set the ulimit value varies from one flavor of unix to another (on some it's a kernel setting), but most linuxes will display the ulimit value if you enter the command:
By default a single Tomcat uses four ports:
These are configured in the tomcat/conf/server.xml file, in the Server/Service/Connector tags.
Jason Brittain recommends disabling the shutdown port and using "kill -15 jvmprocessid" to ask Java to shut itself down (which will, in turn, ask Tomcat to shut itself down first). You still need the shutdown service on Windows, when Tomcat is running as a Windows service, but on a modern OS, just use kill. Disable the shutdown port by editing tomcat/conf/server.xml and editing the Server tag, setting the port attribute to "-1".
A common gotcha is that you start tomcat and it appears to start, then goes away. One of the most likely causes is that something else is already bound to a port it wants. Sometimes this is another web server, sometimes it's something random.
Sometimes it's tomcat conflicting with itself; although servlet engines can run multiple webapps at once on a single instance of Tomcat (or any servlet engine) it is not uncommon to find things set up so each webapp has its own tomcat instance (e.g. a separate JVM process running tomcat). In that case, each tomcat process will take up four ports, and each tomcat instance will have to have its port settings adjusted so they don't conflict.
If this happens, when you look in tomcat/logs/catalina.out you'll probably find an error like this:
java.net.BindException: Cannot assign requested address at java.net.PlainSocketImpl.socketBind(Native Method) at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:336) at java.net.ServerSocket.bind(ServerSocket.java:336) at java.net.ServerSocket.
(ServerSocket.java:202) at org.apache.catalina.core.StandardServer.await(StandardServer.java:373) at org.apache.catalina.startup.Catalina.await(Catalina.java:647) at org.apache.catalina.startup.Catalina.start(Catalina.java:607) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:616) at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288) at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)
To fix this, first check "netstat -nlp" to see what's on that port, then either change that app's ports or edit tomcat/conf/server.xml to change the port settings.
Tomcat is perfectly capable of acting as its own web server, on ports 80 and 443, but by default it is not configured to use those ports.
You can change the configuration if you want, in which case you'll need to start tomcat with root perms so it can bind to low-numbered (1024 and below) ports. This means tomcat ends up running with root perms, which is not a good idea.
Instead, you can use various system tools like ip tables, ip chains, ip filters, etc, to forward port 80 directly to 8080 without having Apache in between. Tomcat includes a tool, jsvc, that was used in the past to do this, basically you start jscv with root perms, it binds to port 80 and then starts a new, non-root process to run tomcat. But Jason Brittain recommends against using it, and just using normal port forwarding tools:
Note that it's preferable to use kernel-space port forwarding (i.e. ip tables) rather than user-space port forwarding (i.e. portfwd or rdir4a). User-space port forwarding will make it look like all requests came from localhost. Kernel-space port forwarding will be invisible to tomcat and the logs will have the original IP addresses for each request.
Tomcat keeps several handy scripts (.sh and .bat, for linux and windows) in tomcat/bin.
The ones you're most worried about are startup.sh and shutdown.sh. Actually, catalina.sh does all of the heavy lifting for startup.sh and shutdown.sh. The startup.sh script invokes catalina.sh to start tomcat, by running the JVM binary with certain command-line arguments. The shutdown.sh script invokes catalina.sh to open a TCP/IP connection to the Tomcat shutdown port. Jason recommends disabling the shutdown port and using kill -15 instead (see the section on ports, above, for more info).
Jason Brittain recommends just using catalina.sh directly. Me, I got in the habit of using startup.sh and shutdown.sh, but that's all it is, a habit. Those two scripts do some minor stuff to figure out environment variables and links and etc, before invoking catalina.sh. But arguably you might be better off setting that stuff directly and explicitly, and invoking catalina.sh yourself.
Also, as mentioned above in Environment Variables, there are several environment variables described in the comments in catalina.sh that you can set to control important aspects of tomcat, but most of that's advanced stuff that you probably don't want to muck with at this stage.
The version.sh script is a handy way to get a dump of the environment variables that will be set up if you run startup.sh. Note that version.sh reports the JRE_HOME, but it will pull the value from your JAVA_HOME environment variable, if set.
When you have tomcat set up and working properly, you'll then "deploy" a webapp into tomcat/webapps.
Or, more properly speaking, you may deploy a single, bundled-up file, called a WAR file (Web Application Archive) into tomcat via either the tomcat manager web interface, or by copying the WAR file into tomcat/webapps and restarting tomcat.
A WAR file is much like a tar file or a jar file, but it contains a set of files in the specified webapp layout, and some additional configuration files.
It's also possible to simply construct the set of subdirectories and files inside tomcat/webapps, and this is in fact how webapps are developed, and you can deploy them this way, too. Personally, I've been developing servlets since before the webapp was added to the servlet spec, and I don't like WAR files. I prefer to unpack my webapps myself in the tomcat/webapps directory. I thought I was just being a curmudgeon, but it appears I'm not the only one, so I may get back to this section and add some ranting about it.
A lot of the java web application world considers manually unpacking webapps in production tomcat installations to be bad form. I've never heard a good concrete reason for this, probably it just sounds like fingernails on a chalkboard to your typical corporate IT admin. Then again, they're the ones who get called at 3am when things go wrong, so I try to work with them, despite my opinions.
Copying the WAR file into tomcat/webapps only works if you have tomcat configured to enable that. By default both deployOnStartup and autoDeploy default to false. See the config file section for more info.
Most of tomcat's logs go in tomcat/logs. You will find a log file for each webapp (with the same name as the webapp), and a catalina.out log file that contains the general tomcat STDOUT log. Each time you restart tomcat, it will increment the log files. So you should see a directory listing something like this:
tomcat/logs/catalina.2010-08-21.log tomcat/logs/catalina.2010-08-22.log tomcat/logs/catalina.out tomcat/logs/host-manager.2010-08-21.log tomcat/logs/host-manager.2010-08-22.log tomcat/logs/host-manager.log tomcat/logs/localhost.2010-08-21.log tomcat/logs/localhost.2010-08-22.log tomcat/logs/localhost.log tomcat/logs/manager.2010-08-21.log tomcat/logs/manager.2010-08-22.log tomcat/logs/manager.log tomcat/logs/myspiffywebapp.2010-08-21.log tomcat/logs/myspiffywebapp.2010-08-22.log tomcat/logs/myspiffywebapp.log
In this example, you have the default manager and host-manager webapps, and the default "localhost" webapp, and for whatever reason a second webapp with the name myspiffywebapp. The server was restarted twice, so you see two datestamped old logs and the current logs.
Note: Some distros rearrange where tomcat keeps its log files. For example, debian and debian-derived distros (like Ubuntu) put the tomcat logs under /var/logs, with all the other log files for those distros.
Generally speaking, tomcat config files will be reloaded when the server is restarted. If a webapp is configured to enable automatic reloading when classes are changed, changes to web.xml will cause reloading also.
Tomcat configuration files are in tomcat/conf.
Specifically, there are some tomcat-wide config files (tomcat/conf/server.xml, tomcat/conf/tomcat-users.xml, catalina.properties, catalina.policy, logging.properties) and a set of config files that will be used for default values for webapps in tomcat (web.xml, context.xml).
The tomcat/conf/web.xml file contains default values for the webapp's internal configuration. It's overidden by tomcat/webapps/webappname/WEB-INF/web.xml. I'll discuss some of the details of web.xml further down, in the Webapp Details section. Mostly these should be defined by the web developer and will pull any necessary external configuration settings from the webapp's context config. Note, the web.xml is also often referred to as the webapp deployment descriptor.
Generally speaking, besides the tomcat-wide config files, each webapp has both its own internal web.xml config file and a server-level config file, called the context.xml. In fact, "context" is the tomcat term for a webapp. The context.xml defines stuff that the webapp will need and the servlet container should provide, for example the database configs for your app (see Database Config and Connection Pool, below).
These days it's almost never actually named "context.xml", so be careful not to confuse that with the default values kept in tomcat/conf/context.xml. I'll try to make sure I always refer to the default config as "default context.xml."
In earlier versions, the context XML tags were kept inside the tomcat server.xml (and in fact that still works) but these days they're kept in tomcat/conf/Catalina/localhost/webappname.xml. Strictly speaking, "Catalina" in that path is variable; it can be the name of any servlet engine, but I don't know of any other servlet engine for tomcat.
The context XML tags can also be kept in tomcat/webapps/webappname/META-INF/context.xml, and in fact in the initial tomcat installation, you'll notice that tomcat/conf/Catalina doesn't exist yet. When you start up tomcat, it will copy the webappname/META-INF/context.xml file into tomcat/conf/Catalina/localhost/webappname.xml. If there's no context.xml there to start, Tomcat will create one using default values.
Deploying a WAR file by copying it into tomcat/webapps only works if the Host tag in tomcat/conf/server.xml Server/Service/Engine/Host has an attribute deployOnStartup="true". You could also add autoDeploy="true" to the same Host tag to get Tomcat to automatically deploy new WAR files without restarting.
One of the more common configuration details that involves the webapp's context.xml is database configs and connection pooling. Rather than the webapp itself having database configs (database name, username, password, etc) you enter them in the webap context.xml and name them. Then in the webapp web.xml, a matching config entry imports that resource by name via JNDI (see JNDI, below).
Besides configuring the database credentials, you also have to configure a connection pool. Tomcat supports a pluggable connection pool, but it comes with a default connection pool implementation, named DBCP (DataBase Connection Pool). You should be able to find tons of docs and examples on how to configure a connection pool using DBCP, starting at your very own tomcat installation:
If you install tomcat using a managed package, it very likely will include the JDBC driver jar for your database. In Ubuntu, for example, there's a libmysql-java package. Otherwise, it's up to you to find the right JDBC driver jar for your database and download it and put it in Tomcat's lib directory. Again, there are tons of docs and examples out there, so I'll leave that to you to look up. I suggest you start here:
One key point: there are several different places that jar files can go in tomcat. Tomcat/lib is where jar files that need to be used all over tomcat go. You might assume that it should go in tomcat/webapps/webappname/WEB-INF/lib, to be used by the webapp, but in fact it has to go in tomcat/lib because tomcat needs to use it internally to set up the connection pool.
This can be confusing. To understand why it works this way, you should read Ted Neward's "Understanding Class.forName()" paper. This is extra credit work, but especially useful if you end up sorting out JAR dependencies in your tomcat installation. Tomcat and the servlet spec make heavy use of classloader delegation, and understanding what's going on with that will make understanding the servlet spec and JAR dependencies a lot easier.
As a side point here, JNDI stands for Java Naming and Directory Interface. It's the java API for doing LDAP-like things, e.g. looking something up in a directory. Unlike a normal LDAP server, JNDI can return any sort of java object, so it's also used a lot internally by various Java technologies to do things like looking up database connection resources.
JNDI is part of the Java Enterprise Edition spec, and is a bit outside the scope of Tomcat's mandate. However, some sort of JNDI support is essential, so rather than requiring you to find, install and configure a separate JNDI server, Tomcat includes a limited JNDI implementation in the distribution.
Note: "Limited" JNDI as in "just good enough to get by", so don't count on it solving all of your JNDI problems, if you start using other Java technologies that require a JNDI server.
Tomcat comes with five web applications pre-installed:
ROOT is the default web app. It's what you get if you pull up http://localhost:8080/ in your web browser after installing tomcat. You can use this to experiment or quickly test stuff.
The examples webapp is a bunch of example code to look at. Unless you're setting up tomcat as a development environment, you probably want to just remove tomcat/webapps/examples before you start tomcat.
The tomcat manager app is for deploying webapps. You log into the web UI and use an HTML form upload to upload the WAR file, and Tomcat unpacks it into the right spot.
Tomcat ships with no manager users defined, to avoid the classic "default admin password was left enabled" security problem. You'll need to edit the config files first, to add a user tag with the manager role. All you need to do is edit tomcat/conf/tomcat-users.xml and insert a tag like the example below, at the very end of the file.
<user name="yourmanageruser" password="yoursecretpassword" roles="standard,manager" />
Note: Some older tutorials instruct you to also insert a role tag to define a manager role. You don't have to do that any more. I'm not sure if doing it anyway might cause problems, let's just try it the right way instead, hm?
A tip for those not from the XML-happy java world: the default tomcat-users.xml file consists almost entirely of comments. Be careful not to insert your new user tag inside the comment tags. (It's easier than you think. :-).
For more info on the manager webapp:
The host-manager webapp provides a web UI for managing virtual hosts with tomcat. This doesn't seem to be used very often, and I don't find much in the way of docs. The ubuntu server guide (don't let the 8.10 worry you; even though the main ubuntu release version is now 9.10, 8.10 is the long-term supported server release version) says you enable it roughly same as you do the manager, except you create a user with the role "admin" instead of "manager".
Discussing the host-manager on #tomcat, Jason Britain commented: "The host manager only configures the in-memory (currently running) container system to know about the new host. It doesn't persist that configuration anywhere." [17:37-02/11]
This just serves a copy of the tomcat docs. You can remove this from a production install before starting tomcat, but you'll probably like to have it around in a development install.
Jason Brittain's blog is a good source to keep up on important changes to tomcat:
Also, mulesoft has some useful general advice about tomcat:
Here are links to several other tomcat FAQ pages that you may find useful:
You may also find these useful for security purposes:
Ted Neward's "Understanding Class.forName()":
You can find Ted Neward's other papers here:
The webapp file hierarchy pretty much consists of the following:
webappname/ webappname/index.jsp webappname/logo.jpg webappname/docs.html webappname/WEB-INF/ webappname/WEB-INF/web.xml webappname/WEB-INF/lib/ webappname/WEB-INF/classes/
I'm going to try not to go into much detail here, as you're a sysadmin, not a developer. You may find some more detailed discussion useful here:Java Web Application Tutorials
As mentioned above, in the Database Config and Connection Pools section, the webapp web.xml, also sometimes referred to as the webapp deployment descriptor, should contain an entry to pull the database connection pool details from a JNDI resource defined in the webapp context xml file.
Besides context parameters, other webapp-specific config details live here also, mainly servlet declarations and servlet mappings. In the servlet spec, the mapping from URL to file or code is highly, highly configurable. It's probably a good idea to be aware of it as a sysadmin, so you don't end up chasing your tail, trying to figure out what file some URL is actually hitting.
Note: I find that most developers have little to no grasp of this, or rather the implications of it for app development, which is why we see people reinventing the wheel with schemes where you submit requests to a general servlet, including a parameter identifying which action the servlet should take, instead of simply using a mapping to define it each action.
Another detail is that everything under tomcat/webapp/webappname is, by default, served like a normal web file, except for everything in WEB-INF and below (also for META-INF, though that only comes up with ebapps that are packaged into WAR files). WEB-INF is where the guts of the application code are kept. You can also configure security settings, in WEB-INF/web.xml, to prevent other files outside WEB-INF from being served by tomcat's HTTP component.
This is a gotcha that the webapp developer should really have taken care of, but since when it does come up, it tends to bite the sysadmin who ends up answering the phone call from the confused user, I'll describe it here.
Form-based authentication uses an in-web-page HTML form for the login process, which allows the developer to present something more compatible with the look and feel of their webapp than the BASIC auth browser pop-up (e.g. the kind of pop-up you get if you're using apache .htaccess to control access to a web page).
Unfortunately, there's also a gotcha with the way the spec defines it. You're not supposed to bookmark the login page. If you do, then pull up the page by the bookmark and log in, you'll get a scary looking error, which is why you're getting confused user phone calls.
Here's what's going on:
Java Enterprise Edition has a formal spec for form-based authentication implemented at the container level. In in this instance that means the fundamental mechanism is implemented in tomcat and configured in the webapp. This facilitates plugging the application server into external enterprise-level tools like LDAP servers for managing authentication and access privileges across a large corporation full of users. For example, Sun's OpenSSO Policy Agent:
Now, the idea is that the login page is part of the container, not part of the app. The container displays the login page when an unauthenticated user requests a protected resource, just like with BASIC auth popups. Your users are supposed to bookmark the main page of the app, then go to that, get their browser redirected to the login page, log in, then get their browser redirected back to the main page.
The problem is that users tend to bookmark the login page, and then the tomcat code that does the redirect doesn't have a valid page to send them to. This is the spec behavior, and although I consider it broken, I can understand why the Tomcat team would rather not depart from the spec, since tomcat is the reference implementation. However, it still causes confused users and is a general pain.
Various frameworks and add-ons provide alternatives. I prefer SecurityFilter, which re-implements Java Enterprise Edition security realms but allows you to specify a default redirect destination. There was some talk that tomcat was going to change its implementation to use a forward -- that is, a server-side redirect to the login page, instead of a client-side redirect -- to prevent users from bookmarking the login page, but this apparently didn't happen.
There are a number of workarounds to this problem, but implementing them is somewhat out of scope for this doc. It's theoretically out of scope for your job as a sysadmin, but some of the workarounds might be doable even with a packaged webapp:https://issues.apache.org/bugzilla/show_bug.cgi?id=3839
This section is just to give you a rough idea of what this tomcat and web application stuff is all about. There are a ton of good (and bad, sigh...) tutorials and books out there, for further reading.
A servlet is a java class that Tomcat will automatically load and instantiate when its URL is requested. Unlike most other web application platforms, the servlet stays loaded and running, and further requests are routed to the same running code. Servlets are multithreaded, so they can process multiple requests simultaneously.
A JSP is, in theory, something like a PHP page. Take an HMTL file foo.html, put in a tomcat webapps directory, rename it to foo.jsp, and congrats, you've written your first JSP.
However, under the hood, JSPs are implemented very differently than PHP pages. A PHP page is a script that is loaded and executed from scratch for every page request. A JSP is compiled, converting the JSP tags to brute force java servlet source code that prints out the HTML.
The compilation is done automatically, so you can change the JSP file and it will be automatically recompiled and reloaded on the next request -- if you enable dynamic JSP compilation. See:
Bear in mind that JSPs ultimately get converted to java servlet source - a JSP is just another way to write a servlet - so ultimately, JSPs can do anything a servlet can do. There are scores of tag libraries ("taglibs" for short) out there for JSP, and you can write an entire app using nothing but JSP tags, and people, in fact, do.
That's not what JSPs were originally intended though, and I happen to think it's not a good idea. Nothing can make you write good code, however, and thus we have the world today.
The original recommended approach was for the JSP to do only "shallow" programming tasks, mainly inserting the data output from a servlet into the HTML it prints. Generally the idea was for web forms to submit their parameters to a servlet. Servlets are generally traffic cops; they shouldn't have a lot of state or do a lot of work directly, they should instantiate and invoke other java classes to do the work.
The servlet should then take the results, usually in the form of a data-oriented java class called a javabean (sometimes referred to as a databean), and forward them off to a JSP. The JSP pulls the individual elements out of the databean and inserts them into HTML text output, which is sent back to the uer's browser to be displayed.
Most java web applications today use an additional layer of tools, called a framework, that gets between the servlet API and the developer and is intended to make it easier to develop a sound web application. Whether the resulting app actually is better is another question...
For a cheatsheet of the key details from above, see: