# Tomcat Configuration ## Contents - [tomcat.sysvinit](#tomcatsysvinit) - [custom.properties](#customproperties) - [httpd\_proxy.conf](#httpd_proxyconf) - [httpd\_jk.conf](#httpd_jkconf) - [workers.properties](#workersproperties) - [uriworkers.properties](#uriworkersproperties) - [server.xml](#serverxml) - [References](#references) Articles in this series - [Tomcat Mechanics](tomcat_mechanics.md) - **Tomcat Configuration** - [Tomcat Packaging](tomcat_packaging.md) - [Tomcat Logging](tomcat_logging.md) ## tomcat.sysvinit Advanced SysVinit script: ``` #!/bin/bash # # Startup script for Tomcat # # chkconfig: 345 82 20 # description: Tomcat is a servlet runner LOCALDIR=/usr/local JAVA_HOME=$LOCALDIR/java CATALINA_HOME=$LOCALDIR/tomcat CPFILE=$LOCALDIR/etc/custom.properties XMFILE=$LOCALDIR/etc/server.xml export LOCALDIR JAVA_HOME CATALINA_HOME # Configure as needed for the specific apps JAVA_OPTS="-server -Xms1536m -Xmx1536m -Xmn384m -XX:+UseParallelGC" export JAVA_OPTS # Disable NPTL if necessary #LD_ASSUME_KERNEL=2.4.1 #export LD_ASSUME_KERNEL # Source various Catalina options as needed CATALINA_OPTS="" while read OPTION && [[ "$OPTION" != end ]] do # drop leading spaces option=${OPTION##} # skip comments [ "${OPTION#\#}" == "${OPTION}" ] || continue # skip blank lines [ -n "${OPTION}" ] || continue CATALINA_OPTS="$CATALINA_OPTS -D$OPTION" done < "$CPFILE" export CATALINA_OPTS # See how we were called. case "$1" in start) cd $CATALINA_HOME ./bin/startup.sh -config $XMFILE ;; stop) cd $CATALINA_HOME ./bin/shutdown.sh -config $XMFILE ;; restart) $0 stop sleep 3 $0 start ;; *) echo "Usage: $0 {start|stop|restart}" exit 1 esac exit 0 ``` ## custom.properties For use in the `CPFILE` setting of the initscript: ``` # A way to dynamically include Java properties (-Dfoo=bar) # from the commandline initscript (see *.sysvinit) # java.library.path=/usr/local/lib java.awt.headless=true java.util.logging.config.file=/usr/local/etc/logging.properties ``` ## httpd\_proxy.conf Using `mod_proxy_ajp.so` as shipped with Apache: ``` ## http://httpd.apache.org/docs/2.2/mod/mod_proxy.html ## Global variables ProxyRequests off ProxyPreserveHost on ## This is a status handler for controlling the balancers ProxyPass /balancer-manager ! SetHandler balancer-manager ## Direct passing ProxyPass /webapp1 ajp://192.168.66.226:8009/mywebapp1 ProxyPassReverse /webapp1 ajp://192.168.66.226:8009/mywebapp1 ## By location directives Allow from all ProxyPass ajp://192.168.66.226:8009/resources maxattempts=3 ProxyPassReverse ajp://192.168.66.226:8009/resources maxattempts=3 ## Load balancer with various options # Each Tomcat server.xml must have a matching jvmRoute, like so: # # # # # Be aware this bug exists in ProxyPassReverse with balancer:// # https://issues.apache.org/bugzilla/show_bug.cgi?id=51982 ProxyPass / balancer://javacluster/ ProxyPassReverse / ajp://192.168.66.226:8009/ ProxyPassReverse / ajp://192.168.66.227:8009/ ProxyPassReverse / ajp://192.168.66.228:8009/ ProxySet lbmethod=byrequests ProxySet timeout=15 ProxySet nofailover=on ProxySet stickysession=JSESSIONID BalancerMember ajp://192.168.66.226:8009 loadfactor=1 keepalive=On route=t226 BalancerMember ajp://192.168.66.227:8009 loadfactor=1 keepalive=On route=t227 # This is a hot standby BalancerMember ajp://192.168.66.228:8009 status=+H keepalive=On route=t228 ``` ## httpd\_jk.conf Using `mod_jk.so` compiled from the Tomcat Connector source: ``` ## See the official site for full descriptions and examples ## http://tomcat.apache.org/connectors-doc/reference/apache.html # Loading the core mod_jk.so LoadModule mod_jk.so /usr/local/lib/mod_jk.so # Logging JkLogFile /var/log/httpd/mod_jk.log JkLogLevel error # # Max format length 63 # JkLogStampFormat "[%a %b %d %H:%M:%S.%Q %Y]" # # JkRequestLogFormat "%w %T %s %U%q" # Shared memory file name. Used by balancer and status workers. JkShmFile /var/log/httpd/mod_jk.shm # # The default value depends on the platform. # JkShmSize 256 # The directive JkOptions allow you to set many forwarding options which will # enable (+) or disable (-). See the documentation. # JkOptions +ForwardURIProxy # JkOptions +ForwardURICompatUnparsed # JkOptions +ForwardURICompat # JkOptions +ForwardURIEscaped # JkOptions +RejectUnsafeURI # JkOptions +ForwardDirectories # JkOptions +ForwardLocalAddress # JkOptions +FlushPackets # JkOptions +FlushHeader # JkOptions +DisableReuse # JkOptions +ForwardKeySize # JkOptions +ForwardSSLCertChain # The name of a worker file for the Tomcat servlet containers. JkWorkersFile /usr/local/etc/workers.properties # Enables setting worker properties inside Apache configuration file. # JkWorkerProperty worker.node1.connect_timeout=60 # Name of the Apache environment variable that can be used to set worker # names in combination with SetHandler jakarta-servlet. # JkWorkerIndicator JK_WORKER_NAME # This directive configures the watchdog thread interval in seconds. (1.2.27+) # JkWatchdogInterval 60 # Turns on SSL processing and information gathering by mod_jk # In order to make SSL data available for mod_jk in Apache, you need to set # SSLOptions +StdEnvVars. For the certificate information you also need to add # SSLOptions +ExportCertData. JkExtractSSL On # JkHTTPSIndicator HTTPS # JkCERTSIndicator SSL_CLIENT_CERT # JkCIPHERIndicator SSL_CIPHER # JkCERTCHAINPrefix SSL_CLIENT_CERT_CHAIN_ # JkSESSIONIndicator SSL_SESSION_ID # JkKEYSIZEIndicator SSL_CIPHER_USEKEYSIZE # Adds a name and an optional default value of environment variable that # should be sent to servlet-engine as a request attribute. # JkEnvVar SSL_CLIENT_V_START undefined # # Environement variables (1.2.28+) # JkLocalNameIndicator JK_LOCAL_NAME # JkLocalPortIndicator JK_LOCAL_PORT # JkRemoteHostIndicator JK_REMOTE_HOST # JkRemoteAddrIndicator JK_REMOTE_ADDR # JkRemotePortIndicator JK_REMOTE_PORT (1.2.32+) # JkRemoteUserIndicator JK_REMOTE_USER # JkAuthTypeIndicator JK_AUTH_TYPE # If this directive is set to On in some virtual server, the session # IDs ;jsessionid=... will be removed for non matched URLs. (1.2.21+) # # JkStripSession Off # File containing multiple mappings from a context to a Tomcat worker. # JkMountFile /usr/local/etc/uriworkermap.properties # # This directive configures the reload check interval in seconds. # If you set this directive to "0", reload checking is turned off. # JkMountFileReload 60 # Automount a webapp by name # JkAutoAlias /usr/local/tomcat/webapps # A mount point from a context to a Tomcat worker. JkMount /*.jsp loadbalancer ... # Copy mounts from global defs JkMountCopy On # A mount point for this vhost only JkMount /foosball/*.jsp node1 # # Remove a sub-path from the mount # JkUnMount /foosball/images node1 # Protect web.xml and other sensitive files (think .htaccess) Order Deny, Allow Deny from all # Setting advanced env vars on the fly # JK_WORKER_NAME (1.2.19+) # JK_REPLY_TIMEOUT (1.2.27+) # # Automatically map all encoded urls SetHandler jakarta-servlet SetEnv JK_WORKER_NAME my_worker # # Map all subdirs to workers via naming rule # and exclude static content. SetHandler jakarta-servlet SetEnvIf REQUEST_URI ^/apps/([^/]*)/ JK_WORKER_NAME=$1 SetEnvIf REQUEST_URI ^/apps/([^/]*)/ JK_REPLY_TIMEOUT=60 SetEnvIf REQUEST_URI ^/apps/([^/]*)/static no-jk ... ``` ## workers.properties For `mod_jk.so` use: ``` ## http://tomcat.apache.org/connectors-doc/reference/workers.html ## workers.properties # # This file provides jk derived plugins with with the needed information to # connect to the different tomcat workers. # # As a general note, the characters $( and ) are used internally to define # macros. Do not use them in your own configuration!!! # # Whenever you see a set of lines such as: # x=value # y=$(x)\something # # the final value for y will be value\something # # workers.tomcat_home should point to the location where you # installed tomcat. This is where you have your conf, webapps and lib # directories. # workers.tomcat_home=/usr/local/tomcat # workers.java_home should point to your Java installation. Normally # you should have a bin and lib directories beneath it. # workers.java_home=/usr/java # You should configure your environment slash... ps=\ on NT and / on UNIX # and maybe something different elsewhere. # ps=/ # Worker connection pool maintain timeout in seconds. If set to the positive # value JK will scan all connections for all workers specified in # worker.list directive and check if connections needs to be recycled. # worker.maintain=60 # The workers that your plugins should create and work with # worker.list=loadbalancer,node1,status ############################################################################## # # worker..type # # Type of the worker (can be one of ajp13, ajp14, lb or status). # The type of the worker defines the directives that can be applied to the # worker. # #! JNI workers have been deprecated. #! They will likely not work. Do not use them. ############################################################################## # The loadbalancer (type lb) workers perform wighted round-robin # load balancing with sticky sessions. # Note: # ----> If a worker dies, the load balancer will check its state # once in a while. Until then all work is redirected to peer # workers. # worker.loadbalancer.type=lb # A comma separated list of workers that the load balancer need to manage. # (1.2.7+) # worker.loadbalancer.balance_workers=node1 # Specifies whether requests with SESSION ID's should be routed back to the # same Tomcat worker. If sticky_session is set to True or 1 sessions are # sticky, otherwise sticky_session is set to False. # worker.loadbalancer.sticky_session=true # Specifies whether requests with SESSION ID's for workers that are in error # state should be rejected. If sticky_session_force is set to True or 1 and # the worker that matches that SESSION ID is in error state, client will # recieve 500 (Server Error). If set to False or 0 failover on another # worker will be issued with loosing client session. This directive is # used only when you set sticky_session=True. (1.2.9+) # worker.loadbalancer.sticky_session_force=false # Specifies what method load balancer is using for electing best worker. # (1.2.9+) # If method is set to R[equest] balancer will use number of requests to find # the best worker. # If method is set to S[ession] the balancer will use number of sessions to # find the best worker. (1.2.20+) # If set to T[raffic] balancer will use the network traffic # between JK and Tomcat to find the best worker. # If set to B[usyness] the balancer will pick the worker with the lowest # current load, based on how many requests the worker is currently serving. # worker.loadbalancer.method=Request # Specifies what lock method the load balancer will use for synchronizing # shared memory runtime data. If lock is set to O[ptimistic] balancer will # not use shared memory lock to find the best worker. If set to P[essimistic] # balancer will use shared memory lock. The balancer will work more accurately # in case of Pessimistic locking, but can slow down the average response time. # (1.2.13+) # worker.loadbalancer.lock=Optimistic # If the load balancer can not get a valid member worker or in case of # failover, it will try again a number of times given by retries. Before each # retry, it will make a pause define by retry_interval directive. (1.2.16+) # worker.loadbalancer.retries=2 # Space delimited list of uri maps the worker should handle. It is only used' # if the worker is included in worker.list. # #worker.loadbalancer.mount= # Set a default secret word for all defined workers. (1.2.12+) # Use request.secret="secret key word" in your Tomcat AJP Connector # configuration. # If you set a secret on a load balancer, all its members will inherit this # secret. # #worker.loadbalancer.secret= # If you use a reply_timeout for the members of a load balancer worker, and # you want to tolerate a few requests taking longer than reply_timeout, you # can set this attribute to some positive value. # # Long running requests will still time out after reply_timeout milliseconds # waiting for data, but the corresponding member worker will only be put into # an error state, if more than max_reply_timeouts requests have timed out. More # precisely, the counter for those bad requests will be divided by two, # whenever the load balancer does its internal maintenance (by default every # 60 seconds). (1.2.24+) # #worker.loadbalancer.max_reply_timeouts=0 # The recover time is the time in seconds the load balancer will not try to # use a worker, after it went into error state. # #worker.loadbalancer.recover_time=60 # Setting a member of a load balancer into an error state is quite serious. # E.g. it means that if you need stickyness, all access to the sessions of # the respective node is blocked. (1.2.28+) # #worker.loadbalancer.error_escalation_time= recover_time / 2 # The name of the cookie that contains the routing identifier needed for # session stickyness. (1.2.27+) # #worker.loadbalancer.session_cookie=JSESSIONID # The name of the path parameter that contains the routing identifier # needed for session stickyness. (1.2.27+) # #worker.loadbalancer.session_path=;jsessionid ############################################################################## # Defining a worker named node1 and of type ajp13 # Note that the name and the type do not have to match. # worker.node1.port=8009 worker.node1.host=localhost worker.node1.type=ajp13 # Socket timeout in seconds used for communication channel between JK and # remote host. If remote host does not respond inside that timeout the JK # will generate an error, and retry again. If set to value zero (default) # the JK will wait for infinite on all socket operations. # worker.node1.socket_timeout=30 # Socket connect timeout in milliseconds used for the communication channel # between JK and remote host. If the remote host does not respond inside # the timeout specified, JK will generate an error, and retry again. # # Note that socket_timeout is in seconds, and socket_connect_timeout in # milliseconds, so in absolute terms the default socket_connect_timeout is # equal to socket_timeout. (1.2.27+) # #worker.node1.socket_connect_timeout=socket_timeout*1000 # This directive should be used when you have a firewall between your # webserver and the Tomcat engine, who tend to drop inactive connections. # This flag will told Operating System to send KEEP_ALIVE message on inactive # connections (interval depend on global OS settings, generally 120ms), # and thus prevent the firewall to cut the connection. To enable keepalive # set this property value to True. # worker.node1.socket_keepalive=False # This flag determines, under which conditions established connections are # probed to ensure they are still working. The probe is done with an empty # AJP13 packet (CPing) and expects to receive an appropriate answer (CPong) # within some timeout. The value of the flag can be any combination of the # following flags (multiple values are combined without any separators): # # C (connect): If set, the connection will be probed once after connecting # to the backend. The timeout can be set by connect_timeout. If it is not # set, the value of ping_timeout will be used instead. # P (prepost): If set, the connection will be probed before sending each # request to the backend. The timeout can be set by prepost_timeout. If it # is not set, the value of ping_timeout will be used instead. # I (interval): If set, the connection will be probed during the regular # internal maintenance cycle, but only if it is idle longer than # connection_ping_interval. The timeout can be set by ping_timeout. # A If set, all of the above probes will be used. # (1.2.27+) # #worker.node1.ping_mode= # Timeout in milliseconds used when waiting for the CPong answer of a CPing # connection probe. The activation of the probes is done via ping_mode. The # timeouts for ping_mode connect and prepost can be overwritten individually # via connect_timeout and prepost_timeout. (1.2.27+) # #worker.node1.ping_timeout=10000 # When using interval connection probing, connections idle for longer than # this interval in seconds are probed by CPing packets whether they still # work. (1.2.27+) # #worker.node1.connection_ping_interval=0 / (ping_timeout/1000)*10 # This defines the number of connections made to the AJP backend that are # maintained as a connection pool. It will limit the number of those # connection that each web server child process can made. # # Do not use connection_pool_size with values higher then 1 on Apache 2.x # prefork or Apache 1.3.x! # worker.node1.connection_pool_size=1 # Minimum size of the connection pool that will be maintained. # This property is used only when the connection_pool_size is specified. Its # default value is (connection_pool_size+1)/2. (1.2.16+) # # Do not use connection_pool_minsize with values higher then 1 on Apache # 2.x prefork or Apache 1.3.x! # #worker.node1.connection_pool_minsize=(pool+1)/2 # Cache timeout property should be used with connection_pool_size to specify # how long JK should keep an inactive socket in cache before closing it. This # property should be used to reduce the number of threads on the Tomcat # WebServer. The default value zero disables the closing (infinite timeout). # worker.node1.connection_pool_timeout=60 # Timeout the worker will wait for a free socket in cache before giving up. # (1.2.27+) # #worker.node1.connection_acquire_timeout=retries * retry_interval # Specifies the load balance factor when used with # a load balancing worker. # Note: # ----> lbfactor must be > 0 # ----> Low lbfactor means less work done by the worker. # worker.node1.lbfactor=1 # Connect timeout property told webserver to send a PING request on ajp13 # connection after connection is established. The parameter is the delay # in milliseconds to wait for the PONG reply. (1.2.6+) # worker.node1.connect_timeout=5000 # Prepost timeout property told webserver to send a PING request on ajp13 # connection before forwarding to it a request. The parameter is the delay # in milliseconds to wait for the PONG reply. (1.2.6+) # worker.node1.prepost_timeout=5000 # Reply_timeout property told webserver to wait some time for reply to a # forwarded request before considering the remote tomcat is dead and # eventually switch to another tomcat in a cluster group. By default # webserver will wait forever which could be an issue for you. The parameter # is the number of milliseconds to wait for reply, so adjust it carefully # if you have long running servlets. (1.2.6+) # worker.node1.reply_timeout=600000 # The number of retries that the worker will try in case of error returned # from remote Tomcat. If the number of retries set is greater then two # (the default value), on each retry after default an extra wait of 100ms # will be inserted. # worker.node1.retries=2 # The amount of time in milliseconds the worker sleeps before doing any # retry. (1.2.27+) # #worker.node1.retry_interval=100 # The recover time is the time in seconds the load balancer will not try to # use a worker, after it went into error state. Only after this time has # passed, a worker in error state will be marked as in recovering, so that # it will be tried for new requests. # worker.node1.recover_time=60 # Recovery options property told webserver how to handle recovery when it # detect that tomcat failed. By default, webserver will forward the request # to another tomcat in LB mode (or to another ajp thread in ajp13 mode). # (1.2.6+) # 0 (full recovery) # 1 (don't recover if tomcat failed after getting the request) # 2 (don't recover if tomcat failed after sending the headers to client) # 3 (don't recover if tomcat failed getting the request or after sending # the headers to client). # 4 (the connection between the webserver and tomcat will be closed if # the client connection to the webserver is terminated during the # request/response cycle) (1.2.16+) # 8: always recover requests for HTTP method HEAD (even if Bits 1 or 2 # are set) (1.2.24+) # 16: always recover requests for HTTP method GET (even if Bits 1 or 2 # are set) (1.2.24+) # worker.node1.recovery_options=4 # Set this value to the HTTP status code that will cause a worker to fail # if returned from Servlet container. Use this directive to deal with cases # when the servlet container can temporary return non-200 responses for a # short amount of time, e.g during redeployment. (1.2.20+) # #worker.node1.fail_on_status=503 # This attribute sets the maximal AJP packet size in Bytes. The maximum value # is 65536. If you change it from the default, you must also change the # packetSize attribute of your AJP connector on the Tomcat side! (1.2.19+) # #worker.node1.max_packet_size=8192 # Space delimited list of uri maps the worker should handle. It is only used' # if the worker is included in worker.list. # #worker.node1.mount= # You can set a secret keyword on the Tomcat AJP Connector. Then only requests # from workers with the same secret keyword will be accepted. (1.2.12+) # Use request.useSecret="true" and request.secret="secret key word" at your # tomcat ajp Connector configuration. # #worker.node1.secret= # Using this directive, a balanced worker of a load balancer can be configured # as disabled or stopped. A disabled worker only gets requests, which belong # to sessions for that worker. A stopped worker does not get any requests. # Users will loose their sessions, unless session replication via clustering # is used. # # Use d or D to disable and s or S to stop. If this directive is not present # the deprecated directives "disabled" or "stopped" are used. # worker.node1.activation=Active # Normally the name of a balanced worker in a load balancer is equal to the # jvmRoute of the corresponding Tomcat instance. If you want to include a # worker corresponding to a Tomcat instance into several load balancers with # different balancing configuration (e.g. disabled, stopped) you can use this # attribute. (1.2.20+) # #worker.node1.route= # Express preferences between the balanced workers of an lb worker. A load # balancer will never choose some balanced worker in case there is another # usable worker with lower distance. (1.2.16+) # worker.node1.distance=0 # Domain directive can be used only when the worker is a member of the load # balancer. Workers that share the same domain name are treated as single # worker. If sticky_session is used, then the domain name is used as session # route. # # This directive is used for large system with more then 6 Tomcats, to be # able to cluster the Tomcats in two groups and thus lowering the session # replication transfer between them. (1.2.8+) # #worker.node1.domain= # Set to the preferred failover worker. If worker matching SESSION ID is # in error state then the redirect worker will be used instead. It will be # used even if being disabled, thus offering hot standby. (1.2.9+) # #worker.node1.redirect= # This directive allows to copy configurations between workers in a # hierarchical way. If worker castor sets: # worker.castor.reference=worker.pollux # then it inherits all properties of pollux, except for the ones that are # explicitly set for castor # #worker.node1.reference= ############################################################################## # http://tomcat.apache.org/connectors-doc/reference/status.html # The status worker does not communicate with Tomcat. Instead it is # responsible for the load balancer management. # worker.status.type=status # Specifies the url for cascading stylesheet to use. # #worker.status.css= # A status worker with read_only=True will not allow any operations, that # change the runtime state or configuration of the other workers. These are # edit/update/reset/recover. (1.2.20+) # worker.status.read_only=True # It is a list of users which gets compared to the user name authenticated # by the web server. If the name is not contained in this list, access is # denied. Per default the list is empty and then access is allowed to anybody. # (1.2.20+) # #worker.status.user= # By default, the user names are matched case sensitively. # #worker.status.user_case_insensitive=False # For every load balancer worker, the status worker shows a summary of the # state of its members. There are three such states, "good", "bad" and # "degraded". (1.2.20+) # #worker.status.good=a.o,a.n,a.b,a.r # By default, members are assumed to be "bad", if their activation is # "stopped" or their runtime state is "error". (1.2.20+) # #worker.status.bad=s,e # The prefix, which will be used by the status worker when producing # properties output (mime=prop). Each property key will be prefixed by this # value. (1.2.20+) # #worker.status.prefix=worker # This directive can be used to customise the XML output from the status # worker. If set to - no namespace will be used. (1.2.20+) # #worker.status.ns=jk: # This directive can be used to customise the XML output from the status # worker. If set to - no xmlns will be used. (1.2.20+) # #worker.status.xmlns=xmlns:jk="http://tomcat.apache.org" # This directive can be used to customise the XML output from the status # worker. This value will be inserted to the output xml after the xml # header. (1.2.20+) # #worker.status.doctype= ``` ## uriworkers.properties For `mod_jk.so` use: ``` ## http://tomcat.apache.org/connectors-doc/reference/uriworkermap.html # # Inside the URI pattern three special characters can be used, '*', '?' and # '|'. The character '*' is a wildchar that matches any number of arbitrary # characters in the URI, '?' matches exactly one character. Each URI pattern # has to start with the character '/', or with '*' or with '?', optionally # prefixed by any combination of the modifiers '!' and '-' # Mapping the URI /myapp1 and everything under /myapp1/: /myapp1/*=myworker # Exclude the subdirectory static: !/myapp/static|/*=myworker # Exclude some suffixes: !*.html=myworker # Mapping the webapps /myapp1 and /myapp2: /myapp1|/*=myworker1 /myapp2|/*=myworker2 # Exclude the all subdirectories static for all workers: !/*/static|/*=* # Exclude some suffixes for all workers: !*.html=* # We are not in maintenance. # The maintenance rule got defined somewhere else. -/*=maintenance ############################################################################## # Rule extensions were added in version 1.2.27 and are not available in # earlier versions. (reply_timeout, active/disable/stopped, fail_on_status, # use_server_errors) # This is an extension example, setting a reply_timeout of 1 minute # only for this mapping. /myapp=myworker;reply_timeout=60000 # This is an example using multiple extensions /myapp=myloadbalancer;reply_timeout=60000;stopped=member1 # Use web server error page for all errors /myapp=myworker;use_server_errors=400 # Use web server error page only for technical errors /myotherapp=myworker;use_server_errors=500 ``` ## server.xml The Tomcat connector endpoint: ``` ``` ## References **Tomcat Configuration** - - - - - **Java Resources** - - - **Version Of Tomcat In JBoss AS** - **Advanced BASH Scripting Guide** -