Tomcat ~ override that web.xml

For many, their first experience with Java Servlets and Java Server Pages was on Apache Tomcat. For decades Tomcat has been a viable production platform for Java web applications. It’s Open-Source, free, configurable and stable.

Like many web applications, the Oracle REST Data Services application can be automatically deployed in a running Tomcat container just by copying the ords.war to the host’s appBase ( $CATALINA_BASE/webapps by default). There is a prerequisite step though. The ords.war must be updated with the location of the configuration directory. That location is written to the web.xml as a <context-param> called config.dir.

Since ORDS a standard Java web application, Tomcat can be configured to use a different web.xml than what is in the WAR file. There are not many valid cases where one might wish to do this though and there are often better alternatives. For example, if you want the ords.war to be unchanged but use a different database, just update the files in the configuration directory. That’s what they are there for.

Perhaps there are additional settings you want to define for your environment that are only applicable to the ORDS web application. Those entries probably don’t belong in the central server.xml or web.xml. So what can one do? Once an application is deployed, the web.xml can be edited in $CATALINA_BASE/webapps but those changes are transient and may not survive a server restart. One approach is to use a Context configuration file for the deployment. Here’s an example, using a Tomcat 9.0.29 server with the default configuration.

In my case, I want to have a different display name and point the config.dir to a different location. This allows me to have the exact same ords.war used in two different Tomcat servers. Let’s say that my ords.war config.dir has the correct location for where to find the configuration files on the production server, but I want to use the exact same war, unmodified on a developer server for testing.

Note that the approach outlined here is not specific to ORDS and applies to any web application in Tomcat.

So I define my custom web.xml for ORDS and call it ords_tomcat_test_web.xml because that sounds descriptive enough. I’m changing the display name to Oracle REST Data Services on Apache Tomcat and the config.dir to /scratch/ords_conf. Let’s say the previous values were Oracle REST Data Services and /u01/oracle/ords/config/ respectively.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" id="WebApp_ID" version="2.4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
	<display-name>Oracle REST Data Services on Apache Tomcat</display-name>

	<context-param>
		<param-name>config.dir</param-name>
		<!-- Enter the location where configuration settings should be stored -->
		<param-value>/scratch/ords_conf</param-value>
	</context-param>
	<context-param>
		<param-name>version</param-name>
		<param-value>20.3.0.301.1819</param-value>
	</context-param>

	<listener>
		<listener-class>oracle.dbtools.entrypoint.WebApplicationEntryPoint</listener-class>
	</listener>

	<servlet>
		<description>
		</description>
		<display-name>HttpEndPoint</display-name>
		<servlet-name>HttpEndPoint</servlet-name>
		<servlet-class>oracle.dbtools.entrypoint.WebApplicationRequestEntryPoint</servlet-class>
	</servlet>

	<servlet-mapping>
		<servlet-name>HttpEndPoint</servlet-name>
		<url-pattern>/*</url-pattern>
	</servlet-mapping>

	<servlet>
		<description>
		</description>
		<display-name>Forbidden</display-name>
		<servlet-name>Forbidden</servlet-name>
		<servlet-class>oracle.dbtools.entrypoint.Forbidden</servlet-class>
	</servlet>

	<servlet-mapping>
		<servlet-name>Forbidden</servlet-name>
		<url-pattern>/oracle/dbtools/jarcl</url-pattern>
	</servlet-mapping>

	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
		<welcome-file>index.htm</welcome-file>
		<welcome-file>index.jsp</welcome-file>
		<welcome-file>default.html</welcome-file>
		<welcome-file>default.htm</welcome-file>
		<welcome-file>default.jsp</welcome-file>
	</welcome-file-list>

</web-app>

To tell Apache Tomcat to use this ords_tomcat_test_web.xml instead of the web.xml in the ords.war I define a Context configuration xml file in $CATALINA_BASE/conf/[enginename]/[hostname]/. In my case $CATALINA_BASE/conf/Catalina/localhost/ords.xml and the entry defines a altDDName attribute. The value is the absolute path to the alternative deployment descriptor for this context. This overrides the default deployment descriptor located at /WEB-INF/web.xml.

<?xml version="1.0" encoding="UTF-8"?>
<Context altDDName="/scratch/ords_tomcat_test_web.xml">
</Context>

The link between the Context configuration and the ords.war is that, ignoring suffix, they have the same filename. ords.xml is the Context configuration for ords.war. At startup, Tomcat will expect to find an ords web application in the webapps directory. If ords.war is not there, Tomcat will still attempt to deploy a web application with the path /ords. An error will show in the logs, and since there’s no real application to run, it will not be in a started state but will be deployed.

2020-12-16T12:45:05.831Z INFO        Deploying deployment descriptor [/scratch/apache-tomcat-9.0.29/conf/Catalina/localhost/ords.xml]
2020-12-16T12:45:05.838Z SEVERE      Error deploying deployment descriptor [/scratch/apache-tomcat-9.0.29/conf/Catalina/localhost/ords.xml]
java.lang.IllegalStateException: Error starting child
	at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:720)
	at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:690)

... removed for brevity ...

2020-12-16T12:45:05.839Z INFO        Deployment of deployment descriptor [/scratch/apache-tomcat-9.0.29/conf/Catalina/localhost/ords.xml] has finished in [7] ms

Just drop in the ords.war as you would with any other web application for auto deployment and Tomcat picks up the change…

2020-12-16T12:46:25.877Z INFO        Reloading context [/ords]
2020-12-16T12:46:34.238Z INFO        Configuration properties for: |apex|pu|
database.api.enabled=true
db.connectionType=basic
db.hostname=localhost
db.port=1521
db.servicename=mydevdb

... removed for brevity ...

2020-12-16T12:46:46.402Z INFO        Oracle REST Data Services initialized
Oracle REST Data Services version : 20.3.0.r3011819
Oracle REST Data Services server info: Apache Tomcat/9.0.29

The configuration properties are being picked up from /scratch/ords_conf/ords/defaults.xml which point to mydevdb. Also the display name is coming from the alternative deployment descriptor.

Display name from customer deployment descriptor

Auto deployment continues to work and the Context configuration survives restarts. Keep in mind that undeploying the application will remove the Context configuration ords.xml as well as the application files from webapps.

Note that this is not the prescribed way to use ORDS in Tomcat and providing your own web.xml to override the package one may result in unspecified behaviour with future versions of ORDS or Tomcat.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s