We are going to develop an EJB Stateful Session Bean with a standalone client.
(In the next lab, we will use a HTML client).
This EJB is a cart bean where can be saved items such as books. It had methods to add an item,
remove an item, and retrieve a list of items.
|
Stateful Session Bean Life-cycle
|
|
Accelerate development with XDoclet
|
As seen in the theoratical part, developing an EJB invovles at least the development of
one class, two interfaces (may be four) and two XML deployment descriptors!
It would be nice to find a way to generate most of those files.
We will use the concept of "Attribute Oriented-Programming" with tools such as EJBGen or XDoclet.
The first one, EJBGen only targets BEA WLS.
Here is an article (online)
on how to use EJBGen.
The second one, XDoclet,
supports many different application servers, jBoss, JOnAS,
Pramati, OC4J, .. but also some frameworks such as JDO, JMX, WebWork or Struts.
Here is the documentation
We will use Xdoclet from now on for all our EJBs development.
|
1. Client Java -> EJB Stateful Session Bean
|
Folders structure
Using XDoclet, the following files are generated: ejb-jar.xml and jboss.xml in ejb-module/META-INF,
all the Java files in gen-src.
EJB CartBean
We are going to develop an EJB Stateful Session Bean (CartBean). "Stateful" means that the
container maintains de conversational state between the client and itself.
Here is code source.
A few XDoclet tags
/**
* CartBean
*
* @ejb.bean
* name = "Cart"
* type = "Stateful"
* jndi-name = "org.jyperion.sample.sessionbean.CartBean"
* view-type = "remote"
*
* @author janaudy
* @date 19, April 2003
*/
public class CartBean implements SessionBean { ...
The @ejb.bean tag specifies that this class is an EJB, of name (name) "Cart",
of type (type) "Stateful", with the JNDI name (jndi-name) "org.jyperion.sample.sessionbean.CartBean"
(will be use for lookups from the client side), and finally, the bean's visibility
(view-type) of type "remote".
Simple?
/**
* @ejb.interface-method
*
* @param nom
*/
public void addBook(String nom) { ...
@ejb.interface-method specifies that this method is accessible from the remote interface.
Uainf those tags, XDoclet will generate:
- Java files Home and Remote
- The ejb-jar.xml XML deployment descriptor
- The propriatary XML deployment descriptor: jboss.xml
ejb-jar.xml
The generated file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN" "http://java.sun.com/dtd/ejb-jar_2_0.dtd">
<ejb-jar >
<description><![CDATA[No Description.]]></description>
<display-name>Generated by XDoclet</display-name>
<enterprise-beans>
<!-- Session Beans -->
<session >
<description><![CDATA[CartBean]]></description>
<ejb-name>Cart</ejb-name>
<home>org.jyperion.j2ee.sample.sfsb.CartHome</home>
<remote>org.jyperion.j2ee.sample.sfsb.Cart</remote>
<ejb-class>org.jyperion.j2ee.sample.sfsb.CartBean</ejb-class>
<session-type>Stateful</session-type>
<transaction-type>Container</transaction-type>
</session>
<!--
To add session beans that you have deployment descriptor info for, add
a file to your XDoclet merge directory called session-beans.xml that contains
the <session></session> markup for those beans.
-->
<!-- Entity Beans -->
<!--
To add entity beans that you have deployment descriptor info for, add
a file to your XDoclet merge directory called entity-beans.xml that contains
the <entity></entity> markup for those beans.
-->
<!-- Message Driven Beans -->
<!--
To add message driven beans that you have deployment descriptor info for, add
a file to your XDoclet merge directory called message-driven-beans.xml that contains
the <message-driven></message-driven> markup for those beans.
-->
</enterprise-beans>
<!-- Relationships -->
<!-- Assembly Descriptor -->
<assembly-descriptor >
<!--
To add additional assembly descriptor info here, add a file to your
XDoclet merge directory called assembly-descriptor.xml that contains
the <assembly-descriptor></assembly-descriptor> markup.
-->
<!-- finder permissions -->
<!-- transactions -->
<!-- finder transactions -->
</assembly-descriptor>
</ejb-jar>
jboss.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jboss PUBLIC "-//JBoss//DTD JBOSS 3.0//EN" "http://www.jboss.org/j2ee/dtd/jboss_3_0.dtd">
<jboss>
<unauthenticated-principal>nobody</unauthenticated-principal>
<enterprise-beans>
<!--
To add beans that you have deployment descriptor info for, add
a file to your XDoclet merge directory called jboss-beans.xml that contains
the <session></session>, <entity></entity> and <message-driven></message-driven>
markup for those beans.
-->
<session>
<ejb-name>Cart</ejb-name>
<jndi-name>org.jyperion.sample.sessionbean.CartBean</jndi-name>
</session>
</enterprise-beans>
<resource-managers>
</resource-managers>
</jboss>
The 2 XML files are in the folder META-INF of the EJB module.
Then, we will generate a JAR file (build phase)..
Client
Here is the JbossCartClient code.
The client module also has a META-INF folder that contains another XML file that defines
the beans accessed by this client.
Furthermore, the client must defines a jndi.properties file that specifies the factory,
IP address and port of the application server.
application-client.xml
<?xml version="1.0"?>
<!DOCTYPE application-client PUBLIC "-//Sun Microsystems, Inc.//DTD J2EE Application Client 1.2//EN" "http://java.sun.com/j2ee/dtds/application-client_1_2.dtd">
<application-client>
<display-name>Cart</display-name>
<ejb-ref>
<ejb-ref-name>Cart</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<home>org.jyperion.j2ee.sample.sfsb.CartHome</home>
<remote>org.jyperion.j2ee.sample.sfsb.Cart</remote>
</ejb-ref>
</application-client>
jndi.properties
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost
EAR module: Enterprise ARchive
We will use the EAR format from now on.
Why an EAR?
Using this format, we can bundle all the necessary tiers (presentation (WAR), logic (JAR), data (JAR), ...)
within one logical file.
The EAR META-INF folder contains another XML descriptors that defines the modules to deploy:
<?xml version="1.0"?>
<!DOCTYPE application PUBLIC "-//Sun Microsystems, Inc.//DTD J2EE Application 1.2//EN" "http://java.sun.com/j2ee/dtds/application_1_2.dtd">
<application>
<display-name>Jyperion Stateful Session Bean sample</display-name>
<description>
</description>
<module>
<ejb>Cart.jar</ejb>
</module>
</application>
We will use ANT to build this file as well.
build
build.properties
####################
# J2EE Libs Folder #
####################
jboss.home=/Users/janaudy/Softwares/jboss-3.2.2RC4/
jboss.deploy=${jboss.home}/server/default/deploy/
ejb.libs=/Users/janaudy/Softwares/jboss-3.2.2RC4/server/default/lib
################
# XDoclet Libs #
################
xdoclet.libs=/Users/janaudy/Softwares/xdoclet-bin-1.2b3/lib
##################
# Modules and co #
##################
base=..
ear-module=${base}/ear-module
client-module=${base}/client-module
client-meta-inf=${client-module}/META-INF
ejb-module=${base}/ejb-module
ejb-meta-inf=${ejb-module}/META-INF
web-module=${base}/web-module
web-classes=${web-module}/WEB-INF/classes
src=${base}/src
gen-src-folder=${base}/gen-src
build.xml
<?xml version="1.0"?>
<project name="SessionBean" default="all" basedir="..">
<property file="build.properties"/>
<taskdef name="java2html"
classname="com.java2html.Java2HTMLTask">
<classpath>
<pathelement location="../../../../misc/java2html/j2h.jar"/>
</classpath>
</taskdef>
<!-- =================================================================== -->
<!-- Define the class path -->
<!-- =================================================================== -->
<path id="my.class.path">
<fileset dir="${ejb.libs}">
<include name="jboss-j2ee.jar"/>
<include name="jbosssx.jar"/>
</fileset>
<fileset dir="${xdoclet.libs}">
<include name="*.jar"/>
</fileset>
</path>
<!-- =================================================================== -->
<!-- Initialise -->
<!-- =================================================================== -->
<target name="init">
<tstamp>
<format property="TODAY" pattern="d-MM-yy"/>
</tstamp>
<taskdef name="xdoclet"
classname="xdoclet.DocletTask"
classpathref="my.class.path"/>
<taskdef name="ejbdoclet"
classname="xdoclet.modules.ejb.EjbDocletTask"
classpathref="my.class.path"/>
</target>
<!-- =================================================================== -->
<!-- Prepares the directory structure -->
<!-- =================================================================== -->
<target name="prepare" depends="init">
<delete file="${ejb-meta-inf}/orion-ejb-jar.xml"
verbose="true"/>
<delete file="${ear-module}/Cart.jar"
verbose="true"/>
<delete file="Cart.ear"
verbose="true"/>
<delete file="CartClient.jar"
verbose="true"/>
<delete file="${ejb-meta-inf}/ejb-jar.xml"
verbose="true"/>
<delete file="${ejb-meta-inf}/jboss.xml"
verbose="true"/>
</target>
<!-- =================================================================== -->
<!-- Invoke XDoclet's ejbdoclet -->
<!-- =================================================================== -->
<target name="ejbdoclet" depends="prepare">
<echo>+---------------------------------------------------+</echo>
<echo>| |</echo>
<echo>| R U N N I N G E J B D O C L E T |</echo>
<echo>| |</echo>
<echo>+---------------------------------------------------+</echo>
<ejbdoclet destdir="${gen-src-folder}"
excludedtags="@version,@author,@todo"
addedtags="@xdoclet-generated at ${TODAY},@copyright The XDoclet Team,@author XDoclet,@version 1.2 beta 2"
ejbspec="2.0"
verbose="true">
<fileset dir="${ejb-module}">
<include name="org/jyperion/j2ee/sample/sfsb/CartBean.java"/>
</fileset>
<deploymentdescriptor destdir="${ejb-meta-inf}"/>
<homeinterface/>
<remoteinterface/>
<localhomeinterface/>
<localinterface/>
<jboss version="3.0"
unauthenticatedPrincipal="nobody"
xmlencoding="UTF-8"
destdir="${ejb-meta-inf}"
validatexml="true"
preferredrelationmapping="relation-table"/>
</ejbdoclet>
</target>
<!-- =================================================================== -->
<!-- Compiles all the classes -->
<!-- =================================================================== -->
<target name="compile" depends="ejbdoclet">
<echo>+---------------------------------------------------+</echo>
<echo>| |</echo>
<echo>| C O M P I L I N G S O U R C E S |</echo>
<echo>| |</echo>
<echo>+---------------------------------------------------+</echo>
<javac destdir="${ejb-module}"
classpathref="my.class.path"
debug="on"
deprecation="on"
optimize="off">
<src path="${gen-src-folder}"/>
<src path="${ejb-module}"/>
</javac>
<javac destdir="${client-module}"
classpathref="my.class.path"
debug="on"
deprecation="on"
optimize="off">
<src path="${gen-src-folder}"/>
<src path="${client-module}"/>
</javac>
</target>
<!-- =================================================================== -->
<!-- Main -->
<!-- =================================================================== -->
<target name="jar">
<echo>+---------------------------------------------------+</echo>
<echo>| |</echo>
<echo>| R U N N I N G X D O C L E T |</echo>
<echo>| |</echo>
<echo>+---------------------------------------------------+</echo>
<echo>Jaring ...</echo>
<jar destfile="${ear-module}/Cart.jar"
basedir="${ejb-module}"/>
<jar destfile="Cart.ear"
basedir="${ear-module}"/>
<jar destfile="CartClient.jar"
basedir="${client-module}"/>
</target>
<!-- =================================================================== -->
<!-- Main -->
<!-- =================================================================== -->
<target name="j2h">
<echo>Running Java2HTML</echo>
<java2html title="EJB SessionBean (Cart) et Client Java"
simple="no"
tabsize="4"
marginsize="2"
header="true"
footer="false"
destination="../doc">
<fileset dir="${base}">
<include name="**/*.java"/>
</fileset>
</java2html>
</target>
<!-- =================================================================== -->
<!-- Deploy -->
<!-- =================================================================== -->
<target name="deploy">
<echo>Deploying in jBoss ...</echo>
<copy file="Cart.ear"
todir="${jboss.deploy}"/>
</target>
<target name="all" depends="compile, jar, j2h, deploy"/>
</project>
|
2. Client Web -> EJB Stateless Session Bean via un Servlet
|
We now know how to use JSPs, Servlets, EJBs, ANT and XDoclet.
The next step is to be able to invoke a Stateless Session Bean from a browser.
You will write a HTML client that invokes a method on a Stateless Session Bean that returns
the VM free memory.
|
Stateless Session Bean Life-cycle
|
The servlet becomes the client.
- Develop a HTML form calling a servlet via a GET
- Develop a servlet by overriding the method doGet
- Develop an EJB Stateless Session Bean using XDoclet with one
business method that returns the used memory within the JVM