WebObjects/Web Applications/Deployment/Tomcat Deployment Details

Place for detailed information on deploying WebObjects applications in Tomcat.

Assumptions

edit
  • Tomcat installation location: /usr/local/tomcat
  • Apache configuration location: /etc/httpd
  • Applications location: /usr/local/myapps
  • Java installation location: /usr/java/jdk1.5.0_06

Tomcat

edit

Common Libraries

edit

Install all common libraries into /usr/local/tomcat/shared/lib, e.g.:

 activation.jar
 commons-logging-1.1.jar
 httpunit-1.6.2.jar
 java-diff-1.0.5.jar
 mail.jar
 mysql-connector-java-5.0.6-bin.jar
 servlet-api.jar
 wsdl4j.jar

War file

edit

Install:

/usr/local/myapps/deploy/myapp.war

Hosts

edit

For each set of applications, here in sets of 10, create these files and directory structures. See the next section for the contents of ROOT.xml files.

Notice that each application has its own host directory, e.g. myapp01.mydomain.com, myapp02.mydomain.com, myapp03.mydomain.com, etc.


Place these under:

 /usr/local/myapps

Group01

 group01/catalina/conf/web.xml
 group01/catalina/conf/tomcat-users.xml
 group01/catalina/conf/context.xml
 group01/catalina/conf/Catalina/myapp01.mydomain.com/ROOT.xml
 group01/catalina/conf/Catalina/myapp02.mydomain.com/ROOT.xml
 group01/catalina/conf/Catalina/myapp03.mydomain.com/ROOT.xml
 group01/catalina/conf/Catalina/myapp04.mydomain.com/ROOT.xml
 group01/catalina/conf/Catalina/myapp05.mydomain.com/ROOT.xml
 group01/catalina/conf/Catalina/myapp06.mydomain.com/ROOT.xml
 group01/catalina/conf/Catalina/myapp07.mydomain.com/ROOT.xml
 group01/catalina/conf/Catalina/myapp08.mydomain.com/ROOT.xml
 group01/catalina/conf/Catalina/myapp09.mydomain.com/ROOT.xml
 group01/catalina/conf/Catalina/myapp10.mydomain.com/ROOT.xml
 group01/catalina/conf/server.xml
 group01/catalina/logs/

Group02

 group02/catalina/conf/web.xml
 group02/catalina/conf/tomcat-users.xml
 group02/catalina/conf/context.xml
 group02/catalina/conf/Catalina/myapp11.mydomain.com/ROOT.xml
 group02/catalina/conf/Catalina/myapp12.mydomain.com/ROOT.xml
 group02/catalina/conf/Catalina/myapp13.mydomain.com/ROOT.xml
 group02/catalina/conf/Catalina/myapp14.mydomain.com/ROOT.xml
 group02/catalina/conf/Catalina/myapp15.mydomain.com/ROOT.xml
 group02/catalina/conf/Catalina/myapp16.mydomain.com/ROOT.xml
 group02/catalina/conf/Catalina/myapp17.mydomain.com/ROOT.xml
 group02/catalina/conf/Catalina/myapp18.mydomain.com/ROOT.xml
 group02/catalina/conf/Catalina/myapp19.mydomain.com/ROOT.xml
 group02/catalina/conf/Catalina/myapp20.mydomain.com/ROOT.xml
 group02/catalina/conf/server.xml
 group02/catalina/logs/

ROOT.xml

edit

For each host/application, use this template, changing the "myapp01" string, wherever it occurs below, to match the host's name, e.g. myapp01, myapp02.

 <?xml version="1.0" encoding="UTF-8"?>
 <Context path="/" docBase="/usr/local/myapps/deploy/myapp.war" reloadable="true" antiJARLocking="true">
     <Environment name="wo/NSLog4jLoggerName" value="myapp04" type="java.lang.String" override="false"/>
     <Environment name="wo/myParameter" value="myValue" type="java.lang.String" override="false"/>
 </Context>

The wo/NSLog4jLoggerName parameter is used for log4j logging, see below. Have it match the application's name.

Setup your own variables here as well for application specific configuration.

server.xml

edit

For each group above, install host definitions as such, matching the previous naming scheme, into that group's server.xml. Here are the entries for group02:

 <Server port="8502" shutdown="SHUTDOWN">
   <Service name="group02">
     <Connector port="8902" enableLookups="false" debug="0" protocol="AJP/1.3" /> 
     <Engine name="Catalina" defaultHost="myapp11.mydomain.com">
         <Host name="myapp11.mydomain.com" debug="0" unpackWARs="false" autoDeploy="true" />
         <Host name="myapp12.mydomain.com" debug="0" unpackWARs="false" autoDeploy="true" />
         <Host name="myapp13.mydomain.com" debug="0" unpackWARs="false" autoDeploy="true" />
         <Host name="myapp14.mydomain.com" debug="0" unpackWARs="false" autoDeploy="true" />
         <Host name="myapp15.mydomain.com" debug="0" unpackWARs="false" autoDeploy="true" />
         <Host name="myapp16.mydomain.com" debug="0" unpackWARs="false" autoDeploy="true" />
         <Host name="myapp17.mydomain.com" debug="0" unpackWARs="false" autoDeploy="true" />
         <Host name="myapp18.mydomain.com" debug="0" unpackWARs="false" autoDeploy="true" />
         <Host name="myapp19.mydomain.com" debug="0" unpackWARs="false" autoDeploy="true" />
         <Host name="myapp20.mydomain.com" debug="0" unpackWARs="false" autoDeploy="true" />
     </Engine>
   </Service>
 </Server>
  • the Connector port must be unique for each Service used on a single physical machine, and must match up with the corresponding modjk worker port used in the Apache worker.properties configuration file, covered below.

NOTE: per application deployment files and classes can be found in the applications work directory, but need not be altered at any time by the administrator.

Logging

edit

Log4j debug mode

edit

Add this to your start of Tomcat to get explicit debug information from log4j. Log4j can be very frustrating, so this is key in debugging the steps it is taking:

 log4j.debug=true

See the below Tomcat startup command for details.

Getting started

edit

Install the log4j properties file into Tomcat's common/clases directory:

 /usr/local/tomcat/common/classes/log4j.properties

If this location does not seem effective, try:

 /usr/local/myapps/group01/catalina/common/classes/log4j.properties

changing the path to the appropriate group for your application, e.g. from group01 to group02.

Commented lines can be uncommented, and the application's corresponding Tomcat server restarted, to output logging for a particular application. Here the example is for application named "myapp01"; this name is defined in the ROOT.xml file above by the wo/NSLog4jLoggerName parameter:

 #log4j.logger.myapp01=DEBUG, A2 
 #log4j.appender.A2=org.apache.log4j.RollingFileAppender 
 #log4j.appender.A2.File=${catalina.base}/logs/myapp01.log 
 #log4j.appender.A2.MaxFileSize=100MB 
 #log4j.appender.A2.MaxBackupIndex=2 
 #log4j.appender.A2.layout=org.apache.log4j.PatternLayout 
 #log4j.appender.A2.layout.ConversionPattern=%-5p %c [%t] %r - %m%n
 #log4j.appender.A2.Threshold=DEBUG
 
 log4j.rootLogger=INFO, Tomcat
 log4j.appender.Tomcat=org.apache.log4j.FileAppender
 log4j.appender.Tomcat.File=${catalina.base}/logs/tomcat.log
 log4j.appender.Tomcat.layout=org.apache.log4j.PatternLayout 
 log4j.appender.Tomcat.layout.ConversionPattern=%p %t %c - %m%n
 log4j.logger.myapp01=FATAL
 log4j.logger.myapp02=FATAL
 log4j.logger.myapp03=FATAL
 log4j.logger.myapp04=FATAL
 log4j.logger.myapp05=FATAL
 log4j.logger.myapp06=FATAL
 log4j.logger.myapp07=FATAL
 log4j.logger.myapp08=FATAL
 log4j.logger.myapp09=FATAL
 log4j.logger.myapp10=FATAL
 log4j.logger.myapp11=FATAL
 log4j.logger.myapp12=FATAL
 log4j.logger.myapp13=FATAL
 log4j.logger.myapp14=FATAL
 log4j.logger.myapp15=FATAL
 log4j.logger.myapp16=FATAL
 log4j.logger.myapp17=FATAL
 log4j.logger.myapp18=FATAL
 log4j.logger.myapp19=FATAL
 log4j.logger.myapp20=FATAL

Another method to view an application's logging information is, e.g, to comment the appropriate line and restart the server:

#   log4j.logger.myapp16=FATAL

This will output logging information for the myapp16 application to /usr/local/tomcat/logs/tomcat.log.

Server Startup

edit

Start each server up separtely. Environmental variables may be exported beforehand, or passed like so on the command line, before the executable is called:

 JAVA_OPTS="-Xms256m -Xmx256m" JAVA_HOME=/usr/java/jdk1.5.0_06 CATALINA_BASE=/usr/local/myapps/group01/catalina /usr/local/tomcat/bin/startup.sh
 JAVA_OPTS="-Xms256m -Xmx256m" JAVA_HOME=/usr/java/jdk1.5.0_06 CATALINA_BASE=/usr/local/myapps/group02/catalina /usr/local/tomcat/bin/startup.sh
 JAVA_OPTS="-Xms256m -Xmx256m" JAVA_HOME=/usr/java/jdk1.5.0_06 CATALINA_BASE=/usr/local/myapps/group03/catalina /usr/local/tomcat/bin/startup.sh
 JAVA_OPTS="-Xms256m -Xmx256m" JAVA_HOME=/usr/java/jdk1.5.0_06 CATALINA_BASE=/usr/local/myapps/group04/catalina /usr/local/tomcat/bin/startup.sh
 JAVA_OPTS="-Xms256m -Xmx256m" JAVA_HOME=/usr/java/jdk1.5.0_06 CATALINA_BASE=/usr/local/myapps/group05/catalina /usr/local/tomcat/bin/startup.sh


Or start a Tomcat instance with log4j debugging on to determine what steps log4j is using in determining log settings and output:

 JAVA_OPTS="-Dlog4j.debug=true -Xms256m -Xmx256m" JAVA_HOME=/usr/java/jdk1.5.0_06 CATALINA_BASE=/usr/local/myapps/group01/catalina /usr/local/tomcat/bin/startup.sh

Server Shutdown

edit

On Linux, this command will shutdown all java processes on the server, be careful:

 pkill java

or a particular process may be stipulated, e.g. 12203:

 pkill -P 10203

And sometimes Tomcat gets hung, be careful though, this will kill every single last java process on your system, no questions asked:

 pkill -9 java

This will also work, in this case for the group01 server:

 CATALINA_BASE=/usr/local/myapps/group01/catalina /usr/local/tomcat/bin/shutdown.sh

Apache

edit

Core modjk Settings

edit

Add to httpd.conf

 JkLogFile "/usr/local/tomcat/logs/mod_jk.log"
 JkLogLevel info
 JkOptions +ForwardURICompat
 JkWorkersFile /etc/httpd/workers.properties

And add /etc/httpd/worker.properties, containing:

 worker.list=worker01,worker02,worker03,worker04,worker05
 
 worker.worker01.type=ajp13
 worker.worker01.host=localhost
 worker.worker01.port=8901
 worker.worker02.type=ajp13
 worker.worker02.host=localhost
 worker.worker02.port=8902
 worker.worker03.type=ajp13
 worker.worker03.host=localhost
 worker.worker03.port=8903
 worker.worker04.type=ajp13
 worker.worker04.host=localhost
 worker.worker04.port=8904
 worker.worker05.type=ajp13
 worker.worker05.host=localhost
 worker.worker05.port=8905

Virtual Hosts

edit

Each virtual host contains such an entry, with specifics modified appropriately, e.g. change myapp02 to match your application's name:

 <VirtualHost *:80>
         ServerName myapp02.mydomain.com
         DocumentRoot "/Library/WebServer/WebSites/myapp02"
 
         JkMount  /WebObjects/* worker01
 
         <Location "/MyApp/WEB-INF/*">
             AllowOverride None
             deny from all
         </Location>
 
         <Location "/MyApp/META-INF/*">
             AllowOverride None
             deny from all
         </Location>
 
         <IfModule mod_rewrite.c>
                 Include "/etc/httpd/mods/mod_rewrite_tomcat.conf"
                 RewriteRule     (.*)/cgi-bin/(.*)/___AppNamePlaceHolder___(\.woa(/.*)?)?        $1/$2/MyApp$3       [L,PT]
         </IfModule>
 </VirtualHost>

Rewrite Rules

edit

Assure that apache has been built and/or installed to use mod_rewrite.

Then install /etc/httpd/mod_rewrite.conf:

 RewriteEngine On
 RewriteRule     ^/WebObjects/.*$                        - [L,PT]
 

This is just an example, you will have to figure this out for yourself in detail. Or figure it out and update this wiki with universal rules.

Testing

edit

Once the Tomcat servers are up and Apache running, hit a website:

 http://myapp04.mydomain.com

Auto Deployment

edit

Touching the WAR file will redeploy all the applications. Replacing the WAR file with an updated version of your application, will auto deploy the new version systematically, one application per Tomcat server at a time. This can be followed by tailing /usr/local/tomcat/logs/tomcat.log.

Touching or updating of the ROOT.xml application files will reload/redeploy the application, and if any changes have been made, they will be picked up by the new deployment.

Troubleshooting

edit

Rewrite Debugging

edit

To get rewrite rule logging, add the following to the top of your rewrite fils:

 RewriteLog              /tmp/mod_rewrite.log
 RewriteLogLevel         9

Restart Apache and tail /tmp/mod_rewrite.log while hitting the website.

Common Errors

edit

javax.servlet.UnavailableException: Error initializing servlet adaptor: access denied

edit

Waiting on more information.

javax.naming.NameNotFoundException: Name jdbc is not bound in this Context

edit

See above comment. At present, not stopping the app from running fine. Looks like an unused entry in the web.xml file.

javax.servlet.UnavailableException: Error initializing servlet adaptor: null

edit

Unknown, but probably just a result of a previous complete failure of the app to start.

java.lang.reflect.InvocationTargetException

edit

Get rid of duplicate copy of jar file in the class path, most likely in /usr/local/tomcat/common/lib:

Caused by: java.lang.ExceptionInInitializerError
Caused by: java.lang.IllegalStateException
There is already a unique instance for Bundle named 'JavaXML'.

like so:

 mv /usr/local/tomcat/common/lib/JavaXML.jar /var/tmp

javax.servlet.UnavailableException

edit

Unknown, misconfiguration.

 - Servlet  threw load() exception
 javax.servlet.UnavailableException: Can't find application bundle. 
 You can either define WOROOT, LOCALROOT and WOAINSTALLROOT as Java system properties 
 (e.g. in your application server's launch script as command line arguments) or in the application Deployment Descriptor file (web.xml).
       at com.webobjects.jspservlet.WOServletAdaptor._applicationInit(WOServletAdaptor.java:335)

java.lang.IllegalStateException: Cannot fire array fault with a null handler

edit
       at com.webobjects.eoaccess.EODatabaseContext._fireArrayFault(EODatabaseContext.java:4399)
       at com.webobjects.eoaccess.EOAccessArrayFaultHandler.completeInitializationOfObject(EOAccessArrayFaultHandler.java:70)
       at com.webobjects.eocontrol._EOCheapCopyMutableArray.willRead(_EOCheapCopyMutableArray.java:38)
       at com.webobjects.eocontrol._EOCheapCopyMutableArray.count(_EOCheapCopyMutableArray.java:92)
       at com.webobjects.eocontrol.EOSortOrdering._sortUsingKeyOrderArray(EOSortOrdering.java:173)
       at com.webobjects.eocontrol.EOSortOrdering.sortArrayUsingKeyOrderArray(EOSortOrdering.java:254)