The Cabin EJB demonstrates basic CMP 2.0 capability for a simple entity bean mapped to a single table. The following sections outline the steps necessary to build, deploy, and execute the Cabin EJB example. Please note that because you’re using JBoss’s default embedded database, you don’t need to configure the database or create tables. The code you’ll see here mirrors the example code provided in Chapter 4 of the EJB book.
Start up JBoss as described in the JBoss Installation and Configuration chapter at the beginning of this workbook.
The database table for this exercise will automatically be created in JBoss’s default database, HypersonicSQL, when the EJB JAR is deployed.
Perform the following steps:
Open a command prompt or shell terminal and change to the
ex04_1
directory created by the extraction
process.
Set the JAVA_HOME
and
JBOSS_HOME
environment variables to point to where
your JDK and JBoss 4.0 are installed. Examples:
Windows:
C:workbookex04_1> set JAVA_HOME=C:jdk1.4.2 C:workbookex04_1> set JBOSS_HOME=C:jboss-4.0
|
Unix:
$ export JAVA_HOME=/usr/local/jdk1.4.2 $ export JBOSS_HOME=/usr/local/jboss-4.0
|
Add ant
to your execution path. Ant is the build
utility
Windows:
C:workbookex04_1> set PATH=..antin;%PATH%
|
Unix:
$ export PATH=../ant/bin:$PATH
|
Perform the build by typing ant
. Ant uses
build.xml
to figure out what to compile and how
to build your JARs.
If you need to learn more about the Ant utility, visit the Ant project at the Jakarta web site at http://jakarta.apache.org/ant/index.html.
Ant compiles the Java source code, builds the EJB JAR, and deploys
the JAR simply by copying it to JBoss’s
deploy
directory. If you are watching the JBoss
console window, you will notice that JBoss automatically discovers
the EJB JAR once it has been copied into the deploy
directory, and automatically deploys the bean.
Another particularly interesting thing about building EJB JARs is that there is no special EJB compilation step. Unlike other servers, JBoss does not generate code for client stubs. Instead, it has a lightweight mechanism that creates client proxies when the EJB JAR is deployed, accelerating the development and deployment cycle.
The build.xml
file provided for each workbook exercise
gives the Ant utility information about how to compile and deploy
your Java programs and EJBs. The following build tasks can be
executed by typing ant
taskname
:
The default task (just typing ant
without a task
name) compiles the code, builds the EJB JAR, and deploys the JAR into
JBoss. The deployment procedure is just a simple copy into the JBoss
deploy
directory.
ant
compile
compiles all the
Java source files.
ant
clean
removes all
.class
and .jar
files from
the working directory and undeploys the JAR from JBoss by deleting
the file from JBoss’s deploy
directory.
ant
clean.db
provides you with
a clean copy of the HypersonicSQL database used throughout the
exercises. This task works only with HypersonicSQL.
run.client_xxx
runs a specific example program.
Each exercise in this book will have a run.client
rule for each example program.
Here’s a breakdown of what is contained in
build.xml
.
<project name="JBoss" default="ejbjar" basedir=".">
The default
attribute defines the default target
that ant
will run if you type only
ant
on the command line. The
basedir
attribute tells Ant what directory to run
the build in:
<property environment="env"/> <property name="src.dir" value="${basedir}/src/main"/> <property name="src.resources" value="${basedir}/src/resources"/> <property name="jboss.home" value="${env.JBOSS_HOME}"/> <property name="build.dir" value="${basedir}/build"/> <property name="build.classes.dir" value="${build.dir}/classes"/>
All the properties defined above are variables that Ant will use
throughout the build process. You can see that the
JBOSS_HOME
environment variable is pulled from the
system environment and other directory paths defined:
<path id="classpath"> <fileset dir="${jboss.home}/client"> <include name="**/*.jar"/> </fileset> <pathelement location="${build.classes.dir}"/> <pathelement location="${basedir}/jndi"/> </path>
To compile and run the example applications in this workbook, add all
the JARS in $JBOSS_HOME/client
to the Java
classpath. Also notice that build.xml
inserts
the ${basedir}/jndi
directory into the
classpath. A jndi.properties
file in this
directory enables the example programs to find and connect to
JBoss’s JNDI server:
<property name="build.classpath" refid="classpath"/> <target name="prepare" > <mkdir dir="${build.dir}"/> <mkdir dir="${build.classes.dir}"/> </target>
The prepare
target creates the directories where
the Java compiler will place compiled classes:
<target name="compile" depends="prepare"> <javac srcdir="${src.dir}" destdir="${build.classes.dir}" debug="on" deprecation="on" optimize="off" includes="**"> <classpath refid="classpath"/> </javac> </target>
The compile
target compiles all the Java files
under the src/main
directory. Notice that it
depends on the prepare
target;
prepare
will run before the
compile
target is executed:
<target name="ejbjar" depends="compile"> <jar jarfile="build/titan.jar"> <fileset dir="${build.classes.dir}"> <include name="com/titan/cabin/*.class"/> </fileset> <fileset dir="${src.resources}/"> <include name="**/*.xml"/> </fileset> </jar> <copy file="build/titan.jar" todir="${jboss.home}/server/default/deploy"/> </target>
The ejbjar
target creates the EJB JAR file and
deploys it to JBoss simply by copying it to JBoss’s
deploy
directory:
<target name="run.client_41a" depends="ejbjar"> <java classname="com.titan.clients.Client_1" fork="yes" dir="."> <classpath refid="classpath"/> </java> </target> <target name="run.client_41b" depends="ejbjar"> <java classname="com.titan.clients.Client_2" fork="yes" dir="."> <classpath refid="classpath"/> </java> </target>
The run.client_xxx
targets are used to run the
example programs in this chapter:
<target name="clean.db"> <delete dir="${jboss.home}/server/default/db/hypersonic"/> </target>
The clean.db
target cleans the default database
used by JBoss for the example programs in this book. Remember, you
can only use it when JBoss is not running:
<target name="clean"> <delete dir="${build.dir}"/> <delete file="${jboss.home}/server/default/deploy/titan.jar"/> </target> </project>
The clean
target removes compiled classes and
undeploys the EJB JAR from JBoss by deleting the JAR file in the
deploy
directory.
You do not need any JBoss-specific files to write a simple EJB. For
an entity bean as simple as the Cabin EJB, JBoss creates the
appropriate database tables within its embedded database Hypersonic
SQL by examining the ejb-jar.xml
deployment
descriptor.
In later chapters, you will learn how to map entity beans to different data sources and pre-existing database tables using JBoss-specific CMP deployment descriptors.
By default, JBoss uses the <ejb-name>
from
the bean’s ejb-jar.xml
deployment descriptor for the JNDI binding of the
bean’s home interface. If you do not like this
default, you can override it in a jboss.xml
file. Clients use this name to look up an EJB’s home
interface. For this example, CabinEJB
is bound to
CabinHomeRemote
.
Two example programs implement the sample clients provided in the EJB book:
package com.titan.clients; import com.titan.cabin.CabinHomeRemote; import com.titan.cabin.CabinRemote; import javax.naming.InitialContext; import javax.naming.Context; import javax.naming.NamingException; import javax.rmi.PortableRemoteObject; import java.rmi.RemoteException; public class Client_1 { public static void main(String [] args) { try { Context jndiContext = getInitialContext( ); Object ref = jndiContext.lookup("CabinHomeRemote"); CabinHomeRemote home = (CabinHomeRemote) PortableRemoteObject.narrow(ref,CabinHomeRemote.class); CabinRemote cabin_1 = home.create(new Integer(1)); cabin_1.setName("Master Suite"); cabin_1.setDeckLevel(1); cabin_1.setShipId(1); cabin_1.setBedCount(3); Integer pk = new Integer(1); CabinRemote cabin_2 = home.findByPrimaryKey(pk); System.out.println(cabin_2.getName( )); System.out.println(cabin_2.getDeckLevel( )); System.out.println(cabin_2.getShipId( )); System.out.println(cabin_2.getBedCount( )); } catch (java.rmi.RemoteException re){re.printStackTrace( );} catch (javax.naming.NamingException ne){ne.printStackTrace( );} catch (javax.ejb.CreateException ce){ce.printStackTrace( );} catch (javax.ejb.FinderException fe){fe.printStackTrace( );} } public static Context getInitialContext( ) throws javax.naming.NamingException { return new InitialContext( ); } }
The getInitialContext( )
method creates an
InitialContext
with no properties. Because no
properties are set, the Java library that implements
InitialContext
searches the classpath for the file
jndi.properties
. Each example program in this
workbook will have a jndi
directory that
contains a jndi.properties
file. You will be
executing all example programs through Ant, and it will set the
classpath appropriately to refer to this properties file.
Run the Client_1
application by invoking
ant
run.client_41a
at the
command prompt. Remember to set your JBOSS_HOME
and PATH
environment variables.
The output of Client_1
should look something
like this:
C:workbookex04_1>ant run.client_41a Buildfile: build.xml prepare: compile: ejbjar: run.client_41a: [java] Master Suite [java] 1 [java] 1 [java] 3
Client_1
adds a row to the database representing
the Cabin bean and does not delete it at the conclusion of the
program. You cannot run this program more than once unless you stop
JBoss, clean the database by invoking the Ant task
clean.db
and restarting JBoss. Otherwise, you will
get the following error:
run.client_41a: [java] javax.ejb.DuplicateKeyException: Entity with primary key 1 already exists [java] at org.jboss.ejb.plugins.cmp.jdbc.JDBCCreateEntityCommand. execute(JDBCCreateEntityCommand.java:160) [java] at org.jboss.ejb.plugins.cmp.jdbc.JDBCStoreManager. createEntity(JDBCStoreManager.java:633) [java] at org.jboss.ejb.plugins.CMPPersistenceManager. createEntity(CMPPersistenceManager.java:253) [java] at org.jboss.resource.connectionmanager.CachedConnectionInterceptor. createEntity(CachedConnectionInterce ... [java] at org.jboss.invocation.InvokerInterceptor.invoke(InvokerInterceptor. java:92) [java] at org.jboss.proxy.TransactionInterceptor. invoke(TransactionInterceptor.java:77) [java] at org.jboss.proxy.SecurityInterceptor.invoke(SecurityInterceptor. java:80) [java] at org.jboss.proxy.ejb.HomeInterceptor.invoke(HomeInterceptor.java: 175) [java] at org.jboss.proxy.ClientContainer.invoke(ClientContainer.java:82) [java] at $Proxy0.create(Unknown Source) [java] at com.titan.clients.Client_1.main(Client_1.java:22)
Run the Client_2
application by invoking
ant
run.client_41b
at the
command prompt. Remember to set your JBOSS_HOME
and PATH
environment variables.
The output of
Client_2
should look something like
this:
run.client_41b: [java] PK=1, Ship=1, Deck=1, BedCount=3, Name=Master Suite [java] PK=2, Ship=1, Deck=1, BedCount=2, Name=Suite 100 [java] PK=3, Ship=1, Deck=1, BedCount=3, Name=Suite 101 [java] PK=4, Ship=1, Deck=1, BedCount=2, Name=Suite 102 [java] PK=5, Ship=1, Deck=1, BedCount=3, Name=Suite 103 [java] PK=6, Ship=1, Deck=1, BedCount=2, Name=Suite 104 [java] PK=7, Ship=1, Deck=1, BedCount=3, Name=Suite 105 [java] PK=8, Ship=1, Deck=1, BedCount=2, Name=Suite 106 ... [java] PK=90, Ship=3, Deck=3, BedCount=3, Name=Suite 309 [java] PK=91, Ship=3, Deck=4, BedCount=2, Name=Suite 400 [java] PK=92, Ship=3, Deck=4, BedCount=3, Name=Suite 401 [java] PK=93, Ship=3, Deck=4, BedCount=2, Name=Suite 402 [java] PK=94, Ship=3, Deck=4, BedCount=3, Name=Suite 403 [java] PK=95, Ship=3, Deck=4, BedCount=2, Name=Suite 404 [java] PK=96, Ship=3, Deck=4, BedCount=3, Name=Suite 405 [java] PK=97, Ship=3, Deck=4, BedCount=2, Name=Suite 406 [java] PK=98, Ship=3, Deck=4, BedCount=3, Name=Suite 407 [java] PK=99, Ship=3, Deck=4, BedCount=2, Name=Suite 408 [java] PK=100, Ship=3, Deck=4, BedCount=3, Name=Suite 409
Like Client_1
, this example creates rows in the
database and does not delete them when it finishes.
Client_2
can be executed only once without
causing DuplicateKey
exceptions.
Every EJB in JBoss is deployed and managed as a JMX MBean. You can view and manage EJBs deployed within JBoss through your web browser by accessing the JMX management console available at http://localhost:8080/jmx-console/ (Figure 22-1).
Click on the jndiName=CabinHomeRemote,service=EJB link shown in Figure 22-1. Entity beans have two management functions. You can flush the entity bean’s cache or view the number of cached objects for it. To flush, click on the flushCache button. To view the number of cached beans, click on the getCacheSize button (Figure 22-2).