WebObjects/Web Applications/Deployment/Tomcat Deployment Details
Place for detailed information on deploying WebObjects applications in Tomcat.
Assumptions
[edit | edit source]- 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 | edit source]Common Libraries
[edit | edit source]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 | edit source]Install:
/usr/local/myapps/deploy/myapp.war
Hosts
[edit | edit source]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 | edit source]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 | edit source]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 | edit source]Log4j debug mode
[edit | edit source]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 | edit source]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 | edit source]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 | edit source]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 | edit source]Core modjk Settings
[edit | edit source]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 | edit source]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 | edit source]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 | edit source]Once the Tomcat servers are up and Apache running, hit a website:
http://myapp04.mydomain.com
Auto Deployment
[edit | edit source]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 | edit source]Rewrite Debugging
[edit | edit source]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 | edit source]javax.servlet.UnavailableException: Error initializing servlet adaptor: access denied
[edit | edit source]Waiting on more information.
javax.naming.NameNotFoundException: Name jdbc is not bound in this Context
[edit | edit source]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 | edit source]Unknown, but probably just a result of a previous complete failure of the app to start.
java.lang.reflect.InvocationTargetException
[edit | edit source]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 | edit source]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 | edit source]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)