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.
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.
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.
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.
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.
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:
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 uid
s and group numbers as gid
s. 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.
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.
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.
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.
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.
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 .
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.
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.
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.
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.
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
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 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
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?
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).
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.
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.
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]
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.
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 ... $
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.
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.
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.
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.
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 [email protected]. 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.
3.22.71.64