EJB – 1 Creating a simple session bean

This example is deprecated.

I am running jboss-4.0.3SP1 on Windows XP.
Note what I have described is creation and deployment of a stateless session bean for Jboss. For other Application Servers, the configuration process might change and EJB lookup code using JNDI might vary. Anyway the rest of the code will prove useful when creating a session EJB from scratch with minor changes at places.
My work folder for ant has the following structure.

web.xml
application.xml
ejb-jar.xml
jboss.xml
build.bat
build.xml
build.propeties
<build>
<src>
    |<gorg>
      |<jboss>
        |<docs>
          |<interest>
              |InterestBean.java
              |Interest.java
              |InterestHome.java
              |InterestServlet.java
</pre>

ejb-jar.xml looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN" "http://java.sun.com/j2ee/dtds/ejb-jar_1_1.dtd">
<ejb-jar>
	<description>JBoss Interest Sample Application</description>
	<display-name>Interest EJB</display-name>
	<enterprise-beans>
		<session>
			<ejb-name>Interest</ejb-name>
			<home>gorg.jboss.docs.interest.InterestHome</home>
			<remote>gorg.jboss.docs.interest.Interest</remote>
			<ejb-class>gorg.jboss.docs.interest.InterestBean</ejb-class>
			<session-type>Stateless</session-type>
			<transaction-type>Bean</transaction-type>
		</session>
	</enterprise-beans>
</ejb-jar>

The ejb-jar.xml is a deployment descriptor and was introduced with EJB 2.0.
It describes the entity or session beans that are included in the application.
Every ejb-jar.xml has exactly one tag, which may contain , or tags and some other optional tags
The contains the names of the home, remote and the bean class as well as some other info.
The tag contains the descriptive name of the bean.
The tag contains the fully qualified name of the home class.
The tag contains the fully qualified name of the remote class.
The tag contains the fully qualified name of the bean class.
The <session-type&g; tag and the are specific to session beans.
In case of entity beans there is a tag that contains the fully qualified name for the entity bean’s primary key class.
This may be a primitive data type such as java.lang.String for a simple key or a fully qualified class name for a compound key.
The tag declares whether the bean can call another bean which calls the original bean.
The tag contains a tag that describes the cmp fields in the entity bean.
Lastly the tag contains the name of the primary key field (for simple pry key types) and is not required for compound keys.
jboss.xml looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<jboss>
	<enterprise-beans>
		<session>
			<ejb-name>Interest</ejb-name>
			<jndi-name>interest/Interest</jndi-name>
		</session>
	</enterprise-beans>
</jboss>

jboss.xml is a container specific configuration file that is used to define the jndi names for the beans in the package.

application.xml looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<!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>Interest EJB</display-name>
	<module>
		<ejb>Interest.jar</ejb>
	</module>
	<module>
		<web>
			<web-uri>Interest.war</web-uri>
			<context-root></context-root>
		</web>
	</module>
</application>

web.xml looks like this:

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app     PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
	<servlet>
		<servlet-name>InterestServlet</servlet-name>
		<servlet-class>gorg.jboss.docs.interest.InterestServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>InterestServlet</servlet-name>
		<url-pattern>/InterestServlet</url-pattern>
	</servlet-mapping>
</web-app>

web.xml contains the descriptive names for the servlets in the application as well as the fully qualifed servlet name.
It also maps the servlet to a url pattern.
build.xml looks like this:

<project name="Interest" default="build-all" basedir=".">

	<property environment="env" />
	<property file="./build.properties" />

	<!-- the build path -->
	<path id="build.path">
		<pathelement location="${jboss.dist}/server/default/lib" />
		<pathelement location="${jboss.dist}/server/default/lib/jboss-j2ee.jar" />
		<pathelement location="${jboss.dist}/client/javax.servlet.jar" />
		<pathelement location="${build.classes.dir}" />
	</path>

	<target name="war" depends="compile">
		<war warfile="${war}" webxml="web.xml">
			<classes dir="${build.classes.dir}">
				<include name="gorg/jboss/docs/interest/InterestServlet.class" />
				<include name="gorg/jboss/docs/interest/${appname}.class" />
				<include name="gorg/jboss/docs/interest/${appname}Home.class" />
			</classes>
			<lib dir="${jboss.client.dir}">
				<include name="jboss-client.jar" />
				<include name="jnp-client.jar" />
			</lib>
		</war>
	</target>

	<target name="jar" depends="compile">
		<jar jarfile="${jar}">
			<fileset dir="${build.classes.dir}">
				<include name="gorg/jboss/docs/interest/${appname}.class" />
				<include name="gorg/jboss/docs/interest/${appname}Home.class" />
				<include name="gorg/jboss/docs/interest/${appname}Bean.class" />
			</fileset>
			<metainf dir="${basedir}" includes="jboss.xml,ejb-jar.xml" />
		</jar>
	</target>

	<!-- build all, and copy to the jboss/deploy directory -->

	<target name="ear" depends="jar,war">
		<ear earfile="${ear}" appxml="application.xml">
			<fileset dir="${basedir}" includes="${jar},${war}" />
		</ear>
	</target>

	<!-- compilation options -->

	<target name="compile">
		<mkdir dir="${build.classes.dir}" />
		<javac srcdir="${src.dir}" destdir="${build.classes.dir}" debug="on"
			deprecation="on" classpathref="build.path" optimize="off" />
	</target>
	<target name="build-all" depends="ear">
		<copy file="${ear}" todir="${jboss.deploy.dir}" />
	</target>
	<target name="clean">
		<delete file="${jar}" />
		<delete file="${ear}" />
		<delete file="${war}" />
		<delete file="${jboss.deploy.dir}/${ear}" />
		<delete dir="${build.classes.dir}" />
	</target>
</project>

build.properties looks like this:

appname=Interest
# get JBOSS location from environment variable
dist.root=${env.JBOSS_HOME}
jboss.dist=${dist.root}
jboss.deploy.dir=${jboss.dist}/server/default/deploy
jboss.client.dir=${jboss.dist}/client

src.dir=${basedir}/src
src.docroot=${src}/docroot
build.dir=${basedir}/build
build.classes.dir=${build.dir}/classes

war=${appname}.war
jar=${appname}.jar
ear=${appname}.ear

Remember, to run build.xml using the build.bat provided by ant, you need to set JBOSS_HOME environment variable pointing to the jboss folder that contains the bin folder.
When you run build.bat at the dos prompt, the files in folder are compiled and appropriate class files are placed in folder, war, jar and ear files are created and the ear file is deployed to / / folder.
In the gorgjbossdocsinterest folder I have the following source files:
InterestBean.java

package gorg.jboss.docs.interest;

import java.rmi.RemoteException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;

public class InterestBean implements SessionBean {
	public double calculateCompoundInterest(double principle, double rate,
			double periods) {
		System.out.println("Someone called 'calculate Compound Interest!'");
		return principle * Math.pow(1 + rate, periods) - principle;
	}

	public void ejbCreate() {
	}

	public void ejbPostCreate() {
	}

	public void ejbRemove() {
	}

	public void ejbActivate() {
	}

	public void ejbPassivate() {
	}

	public void setSessionContext(SessionContext sc) {
	}
}

Interest.java

package gorg.jboss.docs.interest;

import javax.ejb.EJBObject;
import java.rmi.RemoteException;

public interface Interest extends EJBObject {
	public double calculateCompoundInterest(double principle, double rate,
			double periods) throws RemoteException;
}

InterestHome.java

package gorg.jboss.docs.interest;

import java.io.Serializable;
import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;

public interface InterestHome extends EJBHome {
	Interest create() throws RemoteException, CreateException;
}

InterestServlet.java

package gorg.jboss.docs.interest;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Hashtable;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import gorg.jboss.docs.interest.Interest;
import gorg.jboss.docs.interest.InterestHome;

public class InterestServlet extends HttpServlet {
	private InterestHome interestHome = null;

	public void init() throws ServletException {
		try {
			Properties p = new Properties();
			p.setProperty("java.naming.factory.initial",
					"org.jnp.interfaces.NamingContextFactory");
			p.setProperty("java.naming.provider.url", "localhost:1099");
			p.setProperty("java.naming.factory.url.pkgs",
					"org.jboss.naming:org.jnp.interfaces");
			InitialContext jndiContext = new InitialContext(p);
			Object ref = jndiContext.lookup("interest/Interest");
			interestHome = (InterestHome) PortableRemoteObject.narrow(ref,
					InterestHome.class);
		} catch (Exception e) {
			throw new ServletException(
					"Failed to lookup java:comp/env/ejb/Interest", e);
		}
	}

	public void doPost(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {
		String title = "Servlet Interface to EJB";
		double principal = getValue("principal", 1000.0, req);
		double rate = getValue("rate", 10.0, req);
		double periods = getValue("periods", 2.0, req);
		res.setContentType("text/html");
		PrintWriter out = res.getWriter();
		out.println("<html><head><title>");
		out.println(title);
		out.println("</title></head><body>");
		out.println("<h1>" + title + "</h1>");
		out.println("<h2>   Calling EJB.......</h2>");
		try {
			Interest bean = interestHome.create();
			out.print("Interest on " + principal);
			out.print("units at " + rate);
			out.print("% per period, compounded over   " + periods);
			out.println(" periods is ");
			out.println(bean.calculateCompoundInterest(principal, rate / 100,
					periods));
			bean.remove();
		} catch (Exception e) {
			out.println(e.toString());
		} finally {
			out.println("</body></html>");
			out.close();
		}
	}

	private double getValue(String name, double defaultValue,
			HttpServletRequest req) {
		double value = defaultValue;
		String pvalue = req.getParameter(name);
		if (pvalue != null) {
			try {
				value = Double.valueOf(pvalue).doubleValue();
			} catch (NumberFormatException e) {
			}
		}
		return value;
	}

	public void doGet(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {
		doPost(req, res);
	}
}

Use ant command “ant clean” at the dos prompt to clean compiled resources.
And ant command “ant build-all” to redeploy the folder to jboss.
The Interest.ear file has the following structure when it is deployed to jboss deploy folder”

Interest.ear
   |<meta-INF>
      |application.xml
   |Interest.jar
      |<gorg>
         |<jboss>
            |<docs>
               |<interest>
                  |InterestBean.class
                  |InterestHome.class
                  |Interest.class
      |<meta_INF>
         |ejb-jar.xml
         |jboss.xml
   |Interest.war
      |<meta-INF>
      |<web-INF>
         |web.xml
         |<classes>
            |<gorg>
               |<jboss>
                  |<docs>
                     |<interest>
                        |Interest.class
                        |InterestHome.class
                        |InterestServlet.class
         |<lib>
            |jboss-client.jar
            |jnp-client.jar

To run the application remember to perform the following steps:
1.set JBOSS_HOME and ANT_HOME environment variables to appropriate folders containing the folder in ant and jboss. Also set / in your path variable.
2.construct work folder as described above
3.Open dos prompt at work folder to build project – “ant build-all”
To redeploy – “ant clean” – and then – “ant build-all”
The ear file is deployed in servers/default/deploy in jboss

notice that
a) the parameters including environment variables are defined in a separate file, build.properties and this is simply referred to in the build.xml
b) You don’t have to copy the jboss jar files to your war lib directory to be included in the war, build.xml will simply pick it up from JBOSS_HOME/client

Start jboss
Type the following url on the browser.
http://localhost:8080/InterestServlet
You will get the following message on successful output.

Servlet Interface to EJB
Calling EJB.......
Interest on 1000.0units at 10.0% per period, compounded over 2.0 periods is 210.00000000000023

The Jboss console would show:

23:58:08,180 INFO  [STDOUT] Someone called 'calculate Compound Interest!'


Happy Programming!

About cuppajavamattiz
Matty Jacob - Avid technical blogger with interests in J2EE, Web Application Servers, Web frameworks, Open source libraries, Relational Databases, Web Services, Source control repositories, ETL, IDE Tools and related technologies.

Comments are closed.

%d bloggers like this: