For most users, the typical web interaction can be represented as follows: Joe User enters a Uniform Resource Locator(URL) in the browser's location box to request the resource that is identified by that URL. A URL is composed of a host name, an optional port (which defaults to 80), and the resource being requested.
When a web server receives that request, it first determines whether the resource being requested is static or dynamic in nature.
A static resource is one that is identical no matter how many times, or in what order, that resource is requested. Some examples of these would be a company's logo on a web page, a CSS style sheet, or a typical HTML page.
The web server handles the request for a static resource by simply fetching the identified resource from the appropriate path in which its static content resides (for example, htdocs for Apache), and returning those bytes in the response to the user.
For static resources, a depiction of this request flow is as shown below.
A dynamic resource, on the other hand, indicates a resource that varies its content based on various factors that may include the specific user making the request, the time of day when the request is made, or the presence of additional information in the request that affects how the request is interpreted. Some examples of these would include the current inventory for a specific product in an online store, or the availability of a seat on an airplane.
Most web servers are tuned to deliver blazing fast request handling for static resources. However, they require additional help when dealing with dynamic resources. This help is typically provided by an additional software component that is registered with the web server, called a servlet container on the Java EE platform.
In the IIS world, access to this servlet container is offered by implementing an Internet Server Application Programming Interface (ISAPI) extension, which is a Dynamic Link Library (DLL) that allows you to extend the functionality of IIS. In the Apache world, you access the container using code written in C or C++.
When a request comes in that is directed at a dynamic resource, the web server simply hands off that request to its associated servlet container.
The container then springs into action, invokes the appropriate servlet that represents the requested dynamic resource. This servlet is responsible for generating the response. The generated response is returned by the servlet container to the web server which, in turn, returns it to the requesting user. This interaction is depicted in the following diagram.
A servlet in its most basic form is a Java class that acts as a dynamic web resource. In other words, it can be the target of a client browser's request.
Being a Java class, it can tailor its response according to the payload of the incoming request, the conversation that this request is a part of, as well as other environmental criteria (such as the time of the day or the inventory status from a database).
Note
It is important to note that there is nothing special about this delegation mechanism that restricts it only to dynamic resources. You could configure a web server to also delegate requests for a certain subset of static resources (for example, those within a given URL path) to the servlet container.
The problem with using Java code to generate HTML content is that you end up with a lot of string generation and concatenation to generate the actual HTML content, interspersed with actual program logic written in Java. This is an unholy combination as it tends to make the program logic impervious to the person tasked with maintaining your code. In addition, changes to static content now require you to compile the servlet class.
Applying the 80-20 rule very loosely to dynamic content, you might find that 80% of the content of a page is in reality static content. The JavaServer Pages specification was evolved as the solution to this situation. A JSP (JavaServer Page) is a template made up primarily of static content with very specific (and hopefully, few) invocations of Java code to retrieve the dynamic aspects of the page.
The problem of requiring a compilation step was resolved by making a JSP an artificial construct. The container is responsible for transparently parsing a JSP and converting it into a bona fide servlet, compiling it, and then invoking it in the same manner as the other servlets in the application.
As long as the ratio of static to dynamic content is high, that is, as long as there are more static elements than dynamic elements on a page, even non programmers, such as graphic artists, can find their way around a JSP file with some comfort.
This is about as much as we will cover on JavaServer Pages technology in this book.
With all that behind us, we are now ready to answer the question posed by this section's title-what exactly is Tomcat?
Tomcat is classified as a servlet container, that is, an environment within which servlets can live and prosper. As a container, it provides a lot of administrative support to servlets, allowing programmers to focus on the core application logic that is to be implemented, without having to bother about low level specifics such as session management and class loading.
The servlet and JSP specifications describe the service contract that the container promises to provide to the servlets and JSP files that we write. Together, the specifications describe all the services that a container should provide, and specify how the servlet may make use of those services. As with all other Application Programming Interfaces (APIs), the specifications describe the 'what' and leave the 'how' to the implementer of the specific container.
Tomcat serves as the 'reference implementation' of these specifications, and as a result, serves as a guinea pig or canary in the mine shaft for them. In other words, it provides a sample implementation to prove that the specification can indeed be implemented, and serves as a guide for other implementers.
The following diagram provides an early bird's eye view of the responsibilities of a servlet container.
The primary responsibility of a container is to process an incoming request and to generate a corresponding response that is then returned to the client.
A Connector component provides the external interface that allows clients to connect to the container. This component not only accepts incoming connections, but is also responsible for delegating the processing of the request to an available request processor thread. The 'Processors' block in the image denotes multiple threads in a pool that may be used to process the incoming request.
The request processing framework is implemented using a multiple level hierarchy of sub containers (the servlet Engine, virtual hosts, web application contexts, and servlet Wrappers) and nested components (Valves, Listeners, Loaders, Resources, and Security Realms). Note that the '+' sign in the above image indicates that there can be more than one instance of that component. For instance, more than one Host, Context, and servlet Wrapper component may be contained within its parent container.
The result of processing a request is represented by a response, which is then returned through the same Connector.
In addition to the core request processing components, the container also provides support for other aspects of operation, such as logging, security, and JMX monitoring.
In this book, our primary focus will be on the request processing responsibilities of a servlet container. These components form the unshaded boxes in the previous image. Additional topics will be considered only when they are crucial to understanding a request processing component's actions.
Note
It is important to note that a servlet container is a completely different beast from an application server.
In the simplest sense, an application server contains a servlet container, along with other containers, such as an EJB container, an applet container, and an application client container. In addition, an application server provides implementations for a number of Service APIs that are required for heavy duty applications. We will take a closer look at the Java EE platform in Chapter 2.
Examples of application servers include the JBoss Application Server, GlassFish, IBM's WebSphere, and BEA's WebLogic.
Whether or not you should use a full fledged application server, with its support for Enterprise JavaBeans and other Java EE heavy artillery, depends on your application needs.