8 min read

Bootstrapping the embedded container

As we saw earlier, Bootstrap is simply a convenience class that is used to run the Embedded class, or rather to run Catalina, which subclasses Embedded. The Catalina class is intended to add the ability to process a server.xml file to its parent class. It even exposes a main() method, so you can invoke it directly with appropriate command-line arguments.

Bootstrap uses its newly constructed serverLoader to load the Catalina class, which is then instantiated.

It delegates the loading process to this Catalina instance’s load() method. This method updates the catalina.base and catalina.home system properties to absolute references, verifies that the working directory is set appropriately, and initializes the naming system, which is Tomcat’s implementation of the JNDI API. For now, all we need to note is that it indicates that JNDI is enabled by setting the catalina.useNaming system property to true, and prefixing the Context.URL_PKG_PREFIXES system property with the package org.apache.naming using a colon delimiter.

The Context.URL_PKG_PREFIXES property indicates a list of fully qualified package prefixes for URL context factories. Setting org.apache.naming as the first entry makes it the first URL context factory implementation that will be located.

For the java:comp/env Environment Naming Context (ENC), the actual class name for the URL context factory implementation is generated as org.apache.naming.java.javaURLContextFactory. If the Context.INITIAL_CONTEXT_FACTORY is currently not set for this environment, then this is set as the default INITIAL_CONTEXT_FACTORY to be used.

Bootstrapping the Tomcat component hierarchy

The configuration for a Tomcat instance is found in the confserver.xml file. This file is now processed, converting each element found into a Java object. The net result at the end of this processing is a Java object tree that mirrors this configuration file.

This conversion process is facilitated by the use of the Apache Commons Digester project (http://commons.apache.org/digester/), an open source Commons project that allows you to harness the power of a SAX parser while at the same time avoiding the complexity that comes with event driven parsing.

Commons Digester

The Digester project was originally devised as a way of unmarshalling the struts-config.xml configuration file for Struts, but was moved out to a Commons project due to its general purpose usefulness.

The basic principle behind the Digester is very simple. It takes an XML document and a RuleSet document as inputs, and generates a graph of Java objects that represents the structure that is defined in the XML instance document.

 Tomcat 6 Developer's Guide

There are three key concepts that come into play when using the Digester—a pattern, a rule, and an object stack.

The pattern

As the digester parses the input XML instance document, it keeps track of the elements it visits. Each element is identified by its parent’s name followed by a forward slash (‘/’) and then by its name.

For instance, in the example document below, the root element is represented by the pattern rolodex. Two <contact> elements are represented by the pattern rolodex/contact, the <company> elements are represented by the pattern rolodex/contact/company, and so on.

<rolodex type=paperSales>
<contact id="1">
<firstname>Damodar</firstname>
<lastname>Chetty</lastname>
<company>Software Engineering Solutions, Inc.</company>
</contact>
<contact id="2">
<firstname>John</firstname>
<lastname>Smith</lastname>
<company>Ingenuitix, Inc.</company>
</contact>
</rolodex>

The rule

A rule specifies the action(s) that the Digester should take when a particular pattern is encountered.

The common rules you will encounter are:

  • Creational actions (create an instance of a given class to represent this XML element)
  • Property setting actions (call setters on the Java object representing this XML element, passing in the value of either a child element or an attribute)
  • Method invocation actions (call the specified method on the Java object representing this element, passing in the specified parameters)
  • Object linking actions (set an object reference by calling a setter on one object while passing in the other as an argument)

The object stack

As objects are created, using the creational actions discussed above, Digester pushes them to the top of its internal stack. All actions typically affect the object at the top of the stack.

A creational action will automatically pop the element on the top of the stack when the end tag for the pattern is detected.

Using the Digester

The typical sequence of actions is to create an object using a creational action, set its properties using a property setting action, and once the object is fully formed, to pop it off the top of the stack by linking it to its parent, which is usually just below it on the stack. Once the child has been popped off, the parent is once again at the top of the stack. This repeats as additional children objects are created, initialized, linked, and popped. Once all the children are processed and the parent object is fully initialized, the parent itself is popped off the stack, and we are done.

You instantiate an org.apache.commons.digester.Digester by invoking the createDigester() method of org.apache.commons.digester.xmlrules.DigesterLoader and passing it the URL for the file containing the patterns and rules.

Patterns and rules can also be specified programmatically by calling methods directly on the digester instance. However, defining them in a separate XML RuleSet instance document is much more modular, as it extracts rule configuration out of program code, making the code more readable and maintainable.

Then, you invoke the parse() method of a Digester instance and pass it the actual XML instance document. The digester uses its configured rules to convert elements in the instance document into Java objects.

The server.xml Digester

The Catalina instance creates a Digester to process the server.xml file. Every element in this file is converted into an instance of the appropriate class, its properties are set based on configuration information in this file, and connections between the objects are set up, until what you are left with is a functioning framework of classes.

This ability to configure the structure of cooperating classes using a declarative approach makes it easy to customize a Tomcat installation with very little effort.

The createStartDigester() method in Catalina does the work of instantiating a new Digester and registering patterns and rules with it. The Catalina instance is then pushed to the top of the Digester stack, making it the root ancestor for all the elements parsed from the server.xml document.

The rules can be described as follows:

Pattern

Rule

Server

Creational action: Instantiates an org.apache.catalina.core.StandardServer

Set properties action: Copies attribute values over to the topmost object of the stack using mutator methods that are named similarly to the attribute

Object linking action: Invokes setServer()to set this newly minted Server instance on the Catalina instance found on the stack.

Server/

GlobalNamingResources

Creational action: Instantiate an org.apache.catalina.deploy.NamingResources

Set properties action: Copies attribute values from this element over to the topmost object on the stack

Object linking action: Sets this newly instantiated object on the StandardServer instance at the top of the stack, by invoking its setGlobalNamingResources().

Server/Listener

Creational action: Instantiate the class specified by the fully qualified class name provided as an attribute.

Set properties action: Copy attributes from this element.

Object linking action: Sets this instance on the StandardServer instance at the top of the stack, by invoking its addLifecycleListener() method with this new instance.

Server/Service

Creational action: Instantiates an org.apache.catalina.core.StandardService.

Set properties action: Copy attributes from this element

Object linking action: Invokes addService()on the StandardServer instance at the top of the stack passing in this newly minted instance

Server/Service/Listener

Creational action: Instantiate the class specified by the fully qualified class name provided as the className attribute

Set properties action: Copy attributes from this element

Object linking action: Invokes addLifecycleListener() on the StandardService instance at the top of the stack, passing in this listener instance

Server/Service/Executor

 

Creational action: Instantiate the class org.apache.catalina.core.StandardThreadExecutor

Set properties action: Copy attributes for this element

Object linking action: Invokes addExecutor() with this instance, on the StandardService instance at the top of the stack

Server/Service/Connector

 

Creational action: Instantiate the class org.apache.catalina.startup.ConnectorCreateRule

Set properties action: Copy all attributes for this element except for the executor property

Object linking action: Invokes addConnector(), passing in this instance, on the StandardService instance at the top of the stack

Server/Service/Connector/Listener

 

Creational action: Instantiate the class specified by the fully qualified class name provided as the className attribute

Set properties action: Copy attributes from this element

Object linking action: Invokes addLifecycleListener(), passing in this instance, on the Connector instance at the top of the stack

Server/Service/Engine

 

Set the Engine instance’s parent class loader to the serverLoader

LEAVE A REPLY

Please enter your comment!
Please enter your name here