Chapter 20. Open Source Web Application Servers

Servlets and JSP need to be served up by something; that something is a Web application server. What started as simple Web servers serving up little more than HTML pages developed into Java application servers—the backbone of the enterprise IT environment.

What You Will Learn

In this chapter, we will describe the installation of both the JBoss and Geronimo Java application servers on a Linux platform. These servers not only run servlets and JSP, but they are also, as we shall see in later chapters, J2EE EJB containers, so the installation part of this chapter is important for using the technologies and examples covered in the remaining chapters. We will review the System V init system and explain how to add JBoss to the regular system of services on your Linux box. We will show you how to use groups and permissions to enable a number of nonroot users to do the basic application server administration.

Downloading JBoss

JBoss[1] is a complete application server. It provides a full, production-ready, J2EE environment. Be aware that as of this writing JBoss 4.0 has just passed the Sun J2EE certification tests, but even prior to the certification JBoss has been one of the most widely used J2EE application servers.

A great deal of JBoss information can be found on the JBoss Web site.[2] Visit the site’s download page[3] to download the product.

Note

Version 4.0 of JBoss has only just become available, so you will see us using the prior production stable version, 3.2.3. By the time you read this, however, version 4.0 will be the better choice. What we describe should apply equally well to both.

First off, you must choose what form of the product to download. The choice is really between a binary and source distribution. Within that choice, you can choose between a number of compression methods. We will download and install a binary. Just click on jboss-3.2.3.tgz and save the file. Before we install, we need to consider some issues of management.

Be an Enabler, or “Let’s Be Codependent!”

People often give inadequate consideration to the issues of management of software systems. This is especially true of Java systems, which are, by their nature, cross-platform. We have the luxury of dealing only with Linux systems here, so we can make some practical suggestions most books ignore.

Up to this point, we have largely been considering a situation where the Java developer is working on an individual workstation where he or she has root access. Now that we are talking about application servers, we are dealing with systems where, as the software progresses from development through rounds of testing to production, we will want to limit the people who are able to change certain elements of the system. Often, the “quick and dirty” strategy is to share out the root password to a number of users. This is a serious security risk, even when all parties are trusted. Why? Because root isn’t a person. When someone logs in as root, we do not know who that person is. We only know that it is someone who knows the root password. In some businesses, this is an unacceptable ambiguity in audit.

A common alternative is to restrict root login to the console only, and to require the use of the su (“set user”) command to promote an already logged-in user to root status. This provides a link back to the individual, so actions can be traced to single person. That improves auditability.

This strategy is better, but since root is an all-or-nothing proposition, it is a fairly blunt instrument. Once someone can su to root, that someone can do anything. That’s a lot of power to give to someone who just needs to be able to install WAR files.

Yet another strategy is to set up the sudo system.[4] Using sudo, you can specify what people can execute which commands as root, and where they may do it from. In other words, you might let user alice start and stop the Web server and mount and unmount filesystems when she is logged in to a local machine, but only to start the Web server when she is logged in on a machine outside your network. Check out the manpage for sudo to learn more. Even this isn’t the best solution for the present issue.

The best solution is not to require root power at all if you can avoid it. Remember that permissions on files in Linux are assigned to users, groups, and others. Most people do not think about the middle tier, groups. But groups are the best way to give control over parts of the filesystem to a collection of users without requiring them to share an account and password.

Nonroot-Installed Software

The problem with all of the power-sharing strategies we outlined earlier is that once the user escalates to root, there is no way to limit what he or she can do (well, sudo lets you limit it, but a mistake can be fatal—consider what happens if you let them run a program that lets them escape to a shell). So, for example, if you want to let the Web services group install and maintain JBoss, but you don’t want them to mess with any standard software on the system, then create a separate place for nonsystem software.

Two common places for such software on Linux systems are /opt and /usr/local. We tend to use /usr/local mainly because this is the default path on an awful lot of software that uses autoconf to handle cross-platform compilation (it is used by the majority of Free Software programs, but exceptions include what are arguably the four most widely used Free Software packages: the Linux kernel, the Apache Web server, the Perl language, and XFree86). So we are going to install JBoss under /usr/local and we are going to give a number of users the power to install and manage software in /usr/local.

You will need to be root to carry out this procedure. Here are the steps—but don’t worry, we’ll pad them out with a lot of ponderous explanation:

  1. Create the group.

    Groups are defined in the file /etc/group. Each line in that file defines a group. Each line is of the form:

    GroupName:x:GroupID:GroupMembers
    

    GroupName is the name of the group. It is the group name that shows up in long form ls output. The second field is for the group’s password. If we may confess, we don’t know if this feature works anymore. You used to be able to specify a group password, but this defeats the whole purpose of not sharing passwords. Sharing passwords is a security risk. Don’t do it. The third field is the group ID number. Remember that files have owning users and owning groups. These are both stored as numbers. User numbers are known as uids and group numbers as gids. These numbers should be unique. If you reuse a number for more than one group, the effect could be indeterminate, since it would depend on how a given program was written. Don’t reuse numbers. The final column is a comma-delimited list of user names. Those named users are said to belong to the group. We’ll talk some more about what that means as we go on.

    Imagine that user names bob, ted, carol, and alice are part of carl and michael’s Web development team and each has an account on the box on which we intend to install JBoss.

    So, we create a group entry in the /etc/group file:

    local:x:100:carl,michael,bob,carol,ted,alice
    

    If Bob later leaves to join the custodial staff, simply remove his name from the group and he loses his access.

    Tip

    The user’s default group is specified in the /etc/passwd file. Here’s a sample:

    mschwarz:x:500:500:Michael Schwarz:/home/mschwarz:/bin/bash
    

    The fields of this are:

    username:passwd:uid:gid:userinfo:homedir:loginprog
    

    where:

    • username is the login name of the user.

    • passwd is the user’s encrypted password. Or rather it used to be. Now, this is usually x and the encrypted password is stored in the /etc/shadow file. This is because /etc/passwd must be world-readable. The shadow file is not. This prevents someone reading the encrypted passwords to do an offline dictionary attack.

    • uid is the numeric user ID associated with this username.

    • gid is the numeric group ID of this user’s default group. Look for this number in /etc/group to find the name of the default group.

    • userinfo is additional information about this user. Sometimes called the gecos field for obscure historical reasons,[5] this field usually stores the user’s real name and possibly other information like office location and phone number.

    • homedir is the user’s home directory.

    • loginprog is the name of the program that will be executed when the user logs in. This is usually a shell, but it may be any program.

    Note

    There are two strategies that Linux distributions follow for assigning a default group to a new user. One is to put all users into a group called staff or some such. This is widely considered a security risk since it often leads to making files accidentally readable or writable by all users on the system. The more common method is to create a group for each user when the user is created.

    Tip

    If you get in the habit of creating groups, you might want to assign the numbers systematically: 500–599 groups for programs, 600–699 groups for program installation, 700–799 groups for company departments to allow them to control their own Web content, and so on.

  2. Change group ownership of /usr/local.

    Odds are, /usr/local already exists on your system. It may even have several programs installed in it. You must give the group ownership over everything in /usr/local and below. The chgrp command changes the group owner of files, and the -R argument says to do so recursively:

    # cd /usr/local
    # chgrp -R local .
    

    At this point, everything in /usr/local and below is group-owned by the local group.

  3. Set group permissions on /usr/local.

    Basically, you want the group to be able to read and write everything in /usr/local. To do this, you need to change the permissions on all the files with the chmod. As with chgrp, this command takes a -R argument that recursively walks the directory tree. We need to give everyone in the group read and write permission on all the files:

    # chmod -R g+rw .
    

    Note

    We are assuming you are carrying out these steps in sequence and thus your current working directory is still /usr/local.

  4. Set directory permissions on /usr/local.

    You want slightly different permissions on directories. First, you want the group to have execute permission on directories. This allows each member of the group to make each directory his or her current working directory. See Eric Raymond’s Unix and Internet Fundamentals[6] for a good basic introduction to file permissions on UNIX.

    Also, on Linux systems, when a user creates a file, that file is, by default, group-owned by the user’s primary group,[7] which is not what we want here. We want files created by a user in this directory to be group-owned by the local group. To do this, we have to set the setgid bit on all the directories in /usr/local and below. When a user creates a file in a directory that has the setgid bit set, that file will be group-owned by the group-owner of the directory if the user is a member of that group. If the user is not, it will be group-owned by the user’s default group as usual. So we need to set execute and setgid permissions on all the directories in /usr/local and below:

    # find /usr/local -type d -exec chmod g+xs {} ; -print
    /usr/local
    /usr/local/share
    /usr/local/share/bochs
    /usr/local/share/bochs/keymaps
    /usr/local/share/bochs/keymaps/CVS
    /usr/local/share/doc
    ...
    ...
    etc.
    

    With this setup, members of the local group can manage files and programs in /usr/local and below as they wish. They have full power over the files and they need nothing but their own login credentials to do it. The root password can remain private.

Finer Grained Control

This pattern can be repeated. We can give ownership of different branches under /usr/local to other groups to allow control to be doled out in small sets.

Installing JBoss

Using a platform-neutral system like Java has both advantages and disadvantages. A disadvantage is that, generally, Java products don’t use the traditional installation mechanisms of your native platform. You don’t install an RPM or a DEB. But this is somewhat offset by the fact that all a Java application needs is for its classes to be arranged in a particular pattern on the filesystem. In other words, all you need to do to install JBoss is to unpack the tarball.

You did the hard part already. Since you have created the group and made yourself a member of that group,[8] any member of the group can install the product:

$ cd /usr/local
$ tar xzvf jboss-3.2.3.tgz
jboss-3.2.3/lib/
jboss-3.2.3/client/
jboss-3.2.3/docs/
jboss-3.2.3/docs/dtd/
jboss-3.2.3/docs/dtd/html-svg/
...
...
etc.

Tip

At this point we suggest using one more Linux filesystem trick. The tarball unpacks into a directory whose name includes the product version—in this case, jboss-3.2.3. In many cases, you will want to be able to have more than one version of JBoss installed on a box simultaneously, either because you need to port projects from one version to another, or perhaps because you need to develop applications that will run on different versions on different target servers. To make your life easier, create a symbolic link to a generically named directory, such as jboss, and have that symlink point to jboss-3.2.3. Then you can write your startup and shutdown scripts to use the jboss pathname. You can then switch to another version by changing where the symlink points:

$ cd /usr/local
$ ln -s jboss-3.2.3 jboss

This process is discussed in detail in Section 6.2 in the context of switching between Java SDK versions.

Things That Make It Go

In order to explain how to integrate an Open Source application server into your system, we have to do a little Linux Sysadmin training. We need to show you how server processes are generally managed on Linux systems.

System V Init System

Virtually all Linux distributions use some variant of the System V init system to create and customize programs and services that run at the startup of the box. Now, we don’t want to write a Linux system administration manual, but we do need to tell you enough to decide how to make JBoss available when needed on your server.

The core of the System V init system is the /etc/inittab file. Everything else devolves from this configuration file. In the days before network services, the primary startup tasks were to get getty programs running and then run a single startup shell script. The /etc/inittab file handles these tasks beautifully. Since then, the world of UNIX and Linux has become a complex mixture of client-server programs and protocols, so a complex set of conventions has been developed to turn the primitive /etc/inittab into a much richer set of controls. Let’s take a very brief look at /etc/inittab and how it works; then we’ll move on to the extended scripts that manage server processes. That is where we will integrate JBoss.

A key concept in the System V init system is the runlevel. The idea is that a system can have a number of “standard” configurations, numbered from 0 to 6, where 0 is shutdown, 1 is single-user, 2 to 5 are up to the system administrator, and 6 is reboot. The init[9] command can be used (by the root user) to change the system from its current runlevel to another:

# init 1

What happens when you issue such a command is determined by the /etc/inittab file. Let’s take a look at the out-of-the-box /etc/inittab file from a Fedora Core 1[10] system (Example 20.1).

This is a pretty complex file, and we don’t want to bog down in it too much, since most of what interests us occurs outside this file.

The basic format of a line in /etc/inittab is:

id:runlevels:action:process

The id is a unique 1–4 character identifier. The runlevels is a list of the runlevel numbers to which the record applies. The action specifies what action is to be taken. The process is the program to run. The respawn action, for example, tells init that when the process exits, it should be run again. The once action says it should be run once on transition to the runlevel. We won’t go into too much more here. See the man inittab page for details.

The part that concerns us are the l0 through l6 entries. Note that these cause the /etc/rc.d/rc script to be run once, with the runlevel passed as an argument. This is the key to System V init system.

Example 20.1. Fedora Core 1 default /etc/inittab file

#
# inittab       This file describes how the INIT process should set up
#               the system in a certain runlevel.
#
# Author:       Miquel van Smoorenburg, [email protected]>
#               Modified for RHS Linux by Marc Ewing and Donnie Barnes
#

# Default runlevel. The runlevels used by RHS are:
#   0 - halt (Do NOT set initdefault to this)
#   1 - Single user mode
#   2 - Multiuser, without NFS
#       (The same as 3, if you do not have networking)
#   3 - Full multiuser mode
#   4 - unused
#   5 - X11
#   6 - reboot (Do NOT set initdefault to this)
#
id:5:initdefault:

# System initialization.
si::sysinit:/etc/rc.d/rc.sysinit

l0:0:wait:/etc/rc.d/rc 0
l1:1:wait:/etc/rc.d/rc 1
l2:2:wait:/etc/rc.d/rc 2
l3:3:wait:/etc/rc.d/rc 3
l4:4:wait:/etc/rc.d/rc 4
l5:5:wait:/etc/rc.d/rc 5
l6:6:wait:/etc/rc.d/rc 6

# Trap CTRL-ALT-DELETE
ca::ctrlaltdel:/sbin/shutdown -t3 -r now

# When our UPS tells us power has failed, assume we have a few minutes
# of power left. Schedule a shutdown for 2 minutes from now.
# This does, of course, assume you have powered installed and your
# UPS connected and working correctly.
pf::powerfail:/sbin/shutdown -f -h +2 "Power Failure; System Shutting Down"

# If power was restored before the shutdown kicked in, cancel it.
pr:12345:powerokwait:/sbin/shutdown -c "Power Restored; Shutdown Cancelled"

# Run gettys in standard runlevels
1:2345:respawn:/sbin/mingetty tty1
2:2345:respawn:/sbin/mingetty tty2
3:2345:respawn:/sbin/mingetty tty3
4:2345:respawn:/sbin/mingetty tty4
5:2345:respawn:/sbin/mingetty tty5
6:2345:respawn:/sbin/mingetty tty6

# Run xdm in runlevel 5
x:5:respawn:/etc/X11/prefdm -nodaemon

Note

Some Linux distributions run different scripts for each runlevel instead of passing the runlevel as an argument to a single script. The details are not important. The net effect is that a script is run for each runlevel.

Sure, you could put the code to run JBoss directly in that script if you want. But these scripts have been designed to handle arbitrary sets of services without you having to modify those scripts directly. How? By doing what Linux (and its UNIX antecedents) does so well: making complex systems out of simple parts.

Each service you might wish to start and stop gets a shell script that controls it. This shell script must take a command argument. The minimum set of commands that must be supported are start and stop. Other options such as restart and status are often supported, but start and stop are the important ones.

The script for atd, the one-shot job scheduler, is a fine example. Let’s take a look at it (Example 20.2).

Example 20.2. The atd init shell script

#!/bin/bash
#
# /etc/rc.d/init.d/atd
#
# Starts the at daemon
#
# chkconfig: 345 95 5
# description: Runs commands scheduled by the at command at the 
#    time specified when at was run, and runs batch commands when 
#    the load average is low enough.
# processname: atd

# Source function library.
. /etc/init.d/functions

test -x /usr/sbin/atd || exit 0

RETVAL=0

#
# See how we were called.
#

prog="atd"

start() {
  # Check if atd is already running
  if [ ! -f /var/lock/subsys/atd ]; then
    echo -n $"Starting $prog: "
    daemon /usr/sbin/atd
    RETVAL=$?
    [ $RETVAL -eq 0 ] touch /var/lock/subsys/atd
    echo
  fi
  return $RETVAL
}

stop() {
  echo -n $"Stopping $prog: "
  killproc /usr/sbin/atd
  RETVAL=$?
  [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/atd
  echo
    return $RETVAL
}

restart() {
  stop
  start
}

reload() {
  restart
}
status_at() {
  status /usr/sbin/atd
}

case "$1" in
start)
  start
  ;;
stop)
  stop
  ;;
reload|restart)
  restart
  ;;
condrestart)
  if [ -f /var/lock/subsys/atd ]; then
    restart
  fi
  ;;
status)
  status_at
  ;;
*)
  echo $"Usage: $0 {start|stop|restart|condrestart|status}"
  exit 1
esac

exit $?
exit $RETVAL

This script is from a RedHat Linux system. Those comments at the top are a magic incantation for the chkconfig program that ships with that distribution[11] (and with Fedora Core). We’ll talk more about chkconfig in the next section.

As you can see, the basic premise is that when a daemon is started, the process ID is saved into a file. If the “stop” option is passed, the PID is looked up and the process is killed. That’s the basic idea. But wait! There’s more!

Each runlevel has a directory of scripts. Let’s look at the contents of such a directory (Example 20.3).

Example 20.3. A directory of scripts

[mschwarz@host238 mschwarz]$ cd /etc/rc5.d
[mschwarz@host238 rc5.d]$ ls
K01yum         K73ypbind           S18rpcgssd     S58ntpd
K05saslauthd   K74nscd             S19rpcidmapd   S80sendmail
K11jboss       K89netplugd         S19rpcsvcgssd  S80spamassassin
K12mysqld      S00microcode_ctl    S20random      S85gpm
K15httpd       S04readahead_early  S24pcmcia      S90crond
K15postgresql  S05kudzu            S25netfs       S90vmware
K20nfs         S06cpuspeed         S26apmd        S90xfs
K24irda        S08iptables         S28autofs      S95anacron
K35smb         S09isdn             S40smartd      S95atd
K35vncserver   S10network          S44acpid       S96readahead
K35winbind     S12syslog           S55cups        S97messagebus
K36lisa        S13irqbalance       S55sshd        S97rhnsd
K50snmpd       S13portmap          S56rawdevices  S99local
K50snmptrapd   S14nfslock          S56xinetd

Notice the file S95atd? Let’s look at the long form ls output for that file:

[mschwarz@host238 rc5.d]$ ls -la S95atd
lrwxrwxrwx  1 root   root   13 Feb  2 02:08 S95atd -> ../init.d/atd

The file is a symbolic link to the file in the init.d directory! If you take a look at the actual script run by the /etc/inittab file on a runlevel change, you will notice that what it does is to pick up all the files in the rcX.d directory (where X is the runlevel being changed to[12]) that begin with the letter K, run through them in numerical order, and execute the linked scripts with stop as the argument. It then picks up all the files that begin with S, runs through them in numerical order, and executes the linked scripts with start as the argument.

This sounds like a mess, but it is actually a very nice way to automate the starting and stopping of services by runlevel. Adding or removing a new service is simply a matter of creating the /etc/init.d script, and then adding the appropriate symlinks to the rcX.d directories.[13] So, first we have to take an init script and modify it to run JBoss.

RedHat/Fedora chkconfig

RedHat and its stepchild, Fedora, use a program called chkconfig to automate the setup and integration of init scripts.

The chkconfig program has four basic functions. Two involve adding and removing services from management. That’s our main interest here, but we’ll get to that in a moment. The other two involve querying and setting the runlevels in which services run. That is the more common use, so we’ll look at those first.

[root@host238 root]# chkconfig --list ntpd
ntpd           0:off   1:off   2:off   3:on    4:off    5:on    6:off

Tip

chkconfig --list without specifying a service name will list all the services managed by chkconfig, including those that are provided by xinetd, which we will not cover here.

As you can see, ntpd runs at runlevels 3 and 5, and does not run at any others. The --list argument lets you query the runlevels.

[root@host238 root]# chkconfig --levels 2345 ntpd on
[root@host238 root]# chkconfig --list ntpd
ntpd           0:off   1:off   2:on    3:on    4:on   5:on   6:off

The --levels argument lets you specify a list of runlevels that will apply to the named service. The last argument may be on or off to specify which setting to apply to those runlevels. The current value (on or off) for a specified runlevel is overwritten by whatever you specify. There is more to this; see the manpage for chkconfig for details.

Now, before we put JBoss under management, we need to make a script for it. Or rather, we need to modify the one provided by JBoss. In the bin subdirectory of JBoss, you will find a script called jboss_init_redhat.sh. You will notice that it has the “chkconfig mojo” in it—that is, the “chkconfig:” comment line. We mentioned this in passing when we looked at the atd init script, but we didn’t tell you what those three numbers after the colon actually mean. The first is the list of runlevels in which you want the program to run. The second is the start priority, which is the number that will follow the S in the rcX.d runlevel symlink directory. The third number is the stop priority, which is the number that will follow the K in the rcX.d runlevel symlink directory.

These start and stop priority numbers can be very important indeed. Some services (like NFS) depend upon others (like portmap). Your JBoss server might depend on a service like mysqld or postgresql. Don’t toy with these orders lightly. You can seriously mess up your services if you don’t know what you are doing. Still, you will probably have to tweak things to get them completely right. Just be cautious and think about every change.

Example 20.4 is the script as it comes with JBoss 3.2.3.

There are three things we have to change here. The first are the runlevels in the “chkconfig:” line (we’ll show you the changed lines with a couple of lines of context):

#
# chkconfig: 345 80 20
# description: JBoss EJB Container
#

Next, we may need to change the paths to JBoss and to the Java runtime. In our case, if you installed into /usr/local and created the symbolic link as we suggested, you don’t need to change the JBOSS_HOME, but you have to change the JAVAPTH variable:[14]

Example 20.4. Out-of-the-box JBoss init script for RedHat

#!/bin/sh
#
# JBoss Control Script
#
# chkconfig: 3 80 20
# description: JBoss EJB Container
#
# To use this script,
# run it as root - it will switch to the specified user.
# It loses all console output - use the log.
#
# Here is a little (and extremely primitive)
# startup/shutdown script for RedHat systems. It assumes
# that JBoss lives in /usr/local/jboss, it's run by user
# 'jboss' and JDK binaries are in /usr/local/jdk/bin. All
# this can be changed in the script itself.
# Bojan
#
# Either amend this script for your requirements
# or just ensure that the following variables are set correctly
# before calling the script.

# [ #420297 ] JBoss startup/shutdown for RedHat

# define where jboss is - this is the directory
# containing directories log, bin, conf, etc.
JBOSS_HOME=${JBOSS_HOME:-"/usr/local/jboss"}

# make sure Java is on your path
JAVAPTH=${JAVAPTH:-"/usr/local/jdk/bin"}

# define the classpath for the shutdown class
JBOSSCP=${JBOSSCP:-"$JBOSS_HOME/bin/shutdown.jar:$JBOSS_HOME/client/jnet.jar"}

# define the script to use to start jboss
JBOSSSH=${JBOSSSH:-"$JBOSS_HOME/bin/run.sh -c all"}

if [ -n "$JBOSS_CONSOLE" -a ! -d "$JBOSS_CONSOLE" ]; then
  # ensure the file exists
  touch $JBOSS_CONSOLE
fi

if [ -n "$JBOSS_CONSOLE" -a ! -f "$JBOSS_CONSOLE" ]; then
  echo "WARNING: location for saving console log invalid: $JBOSS_CONSOLE"
  echo "WARNING: ignoring it and using /dev/null"
  JBOSS_CONSOLE="/dev/null"
fi

# define what will be done with the console log
JBOSS_CONSOLE=${JBOSS_CONSOLE:-"/dev/null"}

# define the user under which JBoss will run,
# or use RUNASIS to run as the current user
JBOSSUS=${JBOSSUS:-"jboss"}

CMD_START="cd $JBOSS_HOME/bin; $JBOSSSH"
CMD_STOP="java -classpath $JBOSSCP org.jboss.Shutdown --shutdown"

if [ "$JBOSSUS" = "RUNASIS" ]; then
  SUBIT=""
else
  SUBIT="su - $JBOSSUS -c "
fi

if [ -z "`echo $PATH | grep $JAVAPTH`" ]; then
  export PATH=$PATH:$JAVAPTH
fi

if [ ! -d "$JBOSS_HOME" ]; then
  echo JBOSS_HOME does not exist as a valid directory : $JBOSS_HOME
  exit 1
fi

echo CMD_START = $CMD_START

case "$1" in
start)
    cd $JBOSS_HOME/bin
    if [ -z "$SUBIT" ]; then
        eval $CMD_START ${JBOSS_CONSOLE} 2>1
    else
        $SUBIT "$CMD_START ${JBOSS_CONSOLE} 2>1 "
    fi
    ;;
stop)
    if [ -z "$SUBIT" ]; then
        $CMD_STOP
    else
        $SUBIT "$CMD_STOP"
    fi
    ;;
restart)
    $0 stop
    $0 start
    ;;
*)
    echo "usage: $0 (start|stop|restart|help)"
esac
# define where JBoss is - this is the directory
# containing directories log, bin, conf, etc.
JBOSS_HOME=${JBOSS_HOME:-"/usr/local/jboss"}

# make sure Java is on your path
JAVAPTH=${JAVAPTH:-"/usr/java/jdk/bin"}

Finally, we don’t need to run the “all” configuration, we only need the default configuration at the moment, so we change the argument to the run.sh invocation:

# define the script to use to start JBoss
JBOSSSH=${JBOSSSH:-"$JBOSS_HOME/bin/run.sh -c default"}

Now, this script allows you to run JBoss as any user. It defaults to user jboss if none is specified. You have to decide what to do here. Without specifying a user, it will run as root. That is a major security risk. On an out-of-the-box RedHat or Fedora system, there is no user called jboss. We will have to create one. There are a lot of security concerns to creating a special “nonlogin” user. The most important involve changing the user entries in /etc/passwd and /etc/shadow after you create the user. Unfortunately, the JBoss program needs to run a shell script, so you cannot set the shell to /sbin/nologin as is usual. Set the password for the user in /etc/shadow to x, which is completely invalid and will forbid login to the account by password.

Example 20.5. Using chkconfig to include JBoss start script

[root@cvs root]# cd /usr/local/jboss/bin
[root@cvs bin]# cp jboss_init_redhat.sh /etc/init.d/jboss
[root@cvs bin]# chkconfig --add jboss
[root@cvs bin]# chkconfig --list jboss
jboss           0:off 1:off 2:off 3:on          4:on    5:on    6:off
[root@cvs bin]# /etc/init.d/jboss start
CMD_START = cd /usr/local/jboss/bin; /usr/local/jboss/bin/run.sh -c default

Finally, you will need to add the user jboss to any groups you created for JBoss management (such as local in our case). Truth be told, it would be a good idea to use the jboss user to install JBoss. It will avoid having to deal with some file ownership and permission issues. If you do not do this, the simplest way to get this init script working (you will get permission errors) is to run

chmod -R g+w /usr/local/jboss

That will make the script work with the jboss user, provided jboss belongs to the group owner of the JBoss installation.

The final step is to copy your modified script to its final destination and run chkconfig to install it in all the runlevels (Example 20.5).

You now have JBoss running. You can start and stop it with the script, and it will come up and shut down automatically depending on the runlevel you switch to. Beauty, eh?

Other Distributions

You don’t need chkconfig to set up equivalent scripts. In fact, the same script provided by JBoss for RedHat will work with most distributions that use System V init system. You will have to copy the init script and then create the appropriate symlinks manually, or locate the automated setup tools for your particular distribution (Debian, for example, has many such tools which you select with their package management system).

IDE Integration

Another piece of software you might want to look at is JBoss-IDE,[15] an Eclipse plug-in for JBoss. The software is not downloadable from the footnoted Web site, it is available only from the Eclipse Install/Update manager, so run your copy of Eclipse and install it. We will not cover JBoss-IDE here, but if you use Eclipse as your development platform, JBoss-IDE is very useful for managing and deploying EJB’s, servlets, and JSP.

Disposition of Forces

Not to go all Sun-Tzu on you or anything, but if you want to win the war, you must control the initiative. In other words, move only when you are ready. Deploying software into JBoss could not be easier if you get everything ready before you begin.

You see, the key is to create a correctly configured WAR file, as a build.xml file from our project does (Example 20.6).

If you look at the deploy task, you will see that it simply copies the WAR file to a particular directory under the Web server[16] and, it turns out, that is all you need to do to deploy to JBoss. JBoss will notice the new WAR file, stop any existing version, and start the new one. It all depends on getting the WAR file right.

Apache Geronimo

An up-and-coming alternative to JBoss is Apache Geronimo. Part of the Apache Software Foundation’s set of projects, Geronimo is an Open Source, Apache-licensed[17] implementation of the J2EE specification. Furthermore, Geronimo aims to be an Open Source J2EE implementation that is J2EE-certified by Sun.[18] We will take a quick walk through the installation of the Apache Geronimo Java application server. Geronimo not only runs servlets and JSP, but it is also, as we shall see in later chapters, a J2EE EJB container, so the installation part of this chapter is important for using the examples and technologies covered in the remaining chapters.

Example 20.6. Ant build.xml for the BudgetPro servlet and JSP examples

<!-- ================ File and Directory Names ================= -->
<!-- ...
  app.name     The name of our application, used for file/dir names.
  build.home   The name of the directory into which the
               "compile" target will generate its output.
  server.home  The name of the directory where the Web server
               is installed.
  deploy.home  The name of the directory into which the WAR file
               will be copied.
-->

  <property name="server.home" value="/usr/local/jboss" />
  <property name="deploy.home"
            value="${server.home}/server/default/deploy"/>

<!-- ... -->

<!-- ================ Deploy Target ============================ -->
<!--
  The "deploy" target copies the WAR file into a location required
  (i.e., defined) by the servlet container. For some servlet
  containers, you must restart them before they will recognize our
  new/modified Web application. Others may reload automatically.
-->

  <target name="deploy" depends="compile"
          description="Deploy application to servlet container">

    <!-- Copy the contents of the build directory -->
    <mkdir   dir="${deploy.home}"/>
    <copy  todir="${deploy.home}" file="${app.name}.war"/>

  </target>

<!-- ... -->

<!-- ================ Product WAR file ========================= -->

  <target name="war" depends="compile"
          description="Create WAR file to be deployed">
    <war destfile="${app.name}.war" webxml="web/WEB-INF/web.xml">
      <fileset dir="${build.home}"/>
    </war>
  </target>

Geronimo is a complete application server. It provides a full, production-ready, J2EE environment. It is the stated goal of the Geronimo project to pass the Sun J2EE certification tests. Such certification will, in all probability, quickly make Geronimo one of the most widely used J2EE application servers.

A great deal of Geronimo information can be found on the Geronimo Web site.[19]

Note

As of this writing, the project was just nearing the certification process. Only the milestone releases were available for downloading. By the time you read this, however, a fully certified version will likely be production-ready. There may be slight differences in the download and installation procedures. Be sure to follow the instructions from the Web site and any readme files for the most up-to-date information.

First off, you must choose what form of the product to download. The choice is really between a binary and source distribution. Within that choice, you can choose between two compression methods, zip or tar/ gzip. While the first is typical for Windows distributions and the second for Linux, you can choose either, as Linux has utilities for decompressing both. More importantly, the binaries are Java JAR files so they are not tied to a particular operating system. We will download and install a binary. Just click on the tar.gz filename and save the file.

If you haven’t read the previous sections because you were going to skip JBoss and just use Geronimo, please go back and read Section 20.3. It deals with administration and privileges for setting up your installation, and you’ll want to know that for this chapter’s installation discussion, too.

Installing Geronimo

Using a platform-neutral system like Java has both advantages and disadvantages. A disadvantage is that, generally, Java products don’t use the traditional installation mechanisms of your native platform. For Linux users that means that with Java you don’t install using an RPM or a DEB. But this is somewhat offset by the fact that all a Java application needs is for its classes (in JARs) to be arranged in a particular pattern on the filesystem. In other words, all you need to do to install Geronimo is to unpack the tarball.

You did the hard part already. Since you have created the group and made yourself a member of that group (see Section 20.3), any member of the group can install the product:

$ cd /usr/local
$ tar xzvf geronimo.tar.gz
...
$

Tip

At this point we suggest using one more Linux filesystem trick. The tarball unpacks into a directory whose name includes the product version—in this case, geronimo-1.0-M1. In many cases, you will want to be able to have more than one version of Geronimo installed on a box simultaneously, either because you need to port projects from one version to another, or perhaps because you need to develop applications that will run on different versions on different target servers. To make your life easier, create a symbolic link to a generically named directory, such as geronimo and have that symlink point to geronimo-1.0-M1. Then you can write your startup and shutdown scripts to use the geronimo pathname. You can then switch to another version by changing where the symlink points:

$ cd /usr/local
$ ln -s geronimo-1.0-M1/ geronimo

This process is discussed in detail in Section 6.2 in the context of switching between Java SDK versions.

Running the Geronimo Server

Getting the Geronimo server up and running is simply a matter of running a Java application contained in the server.jar file in the bin directory.

$ cd /usr/local/geronimo
$ java -jar bin/server.jar org/apache/geronimo/Server

That last parameter looks like a pathname, but it isn’t. It is a configuration ID which just uses the pathname-like syntax as a namespace, to be unique to Geronimo (by virtue of the /org/apache/geronimo prefix). That name tells the server which of the several possible configurations you want to use. For more information on the other configurations, refer to the Geronimo Wiki.[20]

Having once invoked a particular configuration, you need not repeat that configuration choice on subsequent invocations. That means that the next time you run Geronimo, you can just use:

$ java -jar bin/server.jar

If you want to put this in a startup script you’ll want to use the full specification, so as to be absolutely sure what you are getting.

To stop the server invoked from a command line, simply type Control-C. If the server was invoked from a startup script, you will need to find its process ID (e.g., with the ps command) and use the Linux kill command to send it a signal.

Review

In this chapter we have looked at the installation of both the JBoss and Geronimo Java application servers on a Linux platform. For both of these Open Source servers installation was little more than getting the JAR files in a usable location. We reviewed the System V init system and explained how to add JBoss to the regular system of services on your Linux box. We showed you how to use groups and permissions to enable a number of nonroot users to do the basic application server administration.

What You Still Don’t Know

There is configuration information about your Web applications that must be provided to the Web servers in XML files. A small bit of this will be discussed in Chapter 23, but much of this you will need to find elsewhere. Since this information is in XML and specific to each application server, there is little of it that is specific to the deployment on a Linux system.

Resources

Documentation on JBoss is available from JBoss.org. They have an interesting business model in that they open-source their code but charge for the documentation. Expect to see more third-party books on JBoss, or you may see a move toward Geronimo instead.

Geronimo is, as of this writing, a bit sparse on documentation, too. There is a Wiki site with the beginnings of documentation. Try and hunt down what you need starting from http://wiki.apache.org/geronimo/ and at the http://geronimo.apache.org/ home page.



[1] JBoss is actually a combination of two distinct projects: JBoss, the EJB container and JMS server, and Tomcat, the servlet and JSP server. You can install and use Tomcat alone. We won’t bother to do that in this book. We’ll install JBoss and use JBoss for everything. We are also lazy typists who do not like to keep typing JBoss/Tomcat, so we’ll refer to it merely as JBoss from now on. If you are deploying only servlets and JSP, then, by all means, download and install Tomcat only. It is part of the Apache Jakarta project.

[4] Some folks pronounce this “ess-you doo,” and some “pseudo.” Whatever floats your boat.

[5] See http://www.hyperdictionary.com/dictionary/GCOS if you are dying to know why.

[7] Which is the group ID specified for the user in the /etc/passwd file.

[8] Group membership is established at login. It may be necessary to log out and log back in to take advantage of a newly created group. There are other obscure ways, such as running a subshell with the login argument or running su -, but the simplest is to log out and log back in.

[9] telinit is a common alias from other UNIX implementations. Linux symlinks this to init.

[10] During the writing of this book, RedHat decided to put their completely Free Software OS out to a public-controlled project and to stop calling it “RedHat.” The name RedHat is reserved for Fedora-based Linux systems that must be purchased with support contracts. It is still the same system with a different name maintained by basically the same people. The key difference is that you cannot purchase support for Fedora (at least from RedHat, we expect some enterprising folks to offer Fedora support for a fee at some point).

[11] The RedHat chkconfig program is conceptually similar to the one in the IRIX operating system.

[12] That phrase actually caused my high school grammar teacher to materialize in my office and scold me. I invite anyone who can come up with an elegant and grammatical way to phrase that to contact me at . I’m perfectly serious.

[13] Just a quick reminder that not all Linux distributions name their directories or scripts in precisely the same way, but they all use something similar. By examining the /etc/inittab file and the contents of the /etc directory, you should be able to figure out the details of any given distribution. Over time, more and more distributions have come to exactly match the naming scheme described here. RedHat, Fedora, and Debian, for example, all follow this naming scheme.

[14] We are assuming you have set up your Java SDK as described in Chapter 6. If your java* commands are located somewhere else, change this path to point at them.

[16] Note that that’s normal for development. For integration and production, either someone authorized will run the same build on the target, or (more likely) the WAR file will be “formally” built, tagged, and copied to the test or production server. We’ll talk more about that when we get to application maintenance issues.

[17] Most notably, it doesn’t require anyone to open the source of their changes or customizations if they improve on an Apache software project, unlike the GPL which does.

[18] As of this writing, there was still a legal hurdle to overcome, since Sun requires derivative works to be branded and compatible, whereas the Apache license places no such requirements on its derivative works. This may be resolved by the time you are reading this.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.22.71.64