
 Hello OpenEJB World! A basic CMP entity bean example
 |
1 Abstract 2 Before starting 3 Create the entity bean class 4 Create the entity bean's home interface 5 Create the entity bean's remote interface 6 Create the ejb-jar.xml 7 Compile the EJB 8 Package the EJB 9 Create necessary structures in the database (e.g. PostgreSQL) 10 Configure the data source 11 Deploy the EJB jar 12 A basic client application 13 Compile the application 14 Run it! 15 What if it didn't work
Abstract
The aim of this document is to help you out with deploying
container-managed persistence (CMP) entity beans into OpenEJB. The
database being used is PostgreSQL 7.2.1, but the steps are described in
such a way that it should be very easy to switch over to another database
system (chances are that when you send a request to the OpenEJB user mailing list about how to enable
your preffered RDBMS in OpenEJB, someone, possibly from the development
group, will pick it up and modify the document, accordingly).
The first sections deal with developing a CMP entity bean. It is a CMP
entity's view of Employee.You may skip them if your bean is ready and
waiting to be deployed.
We will be configuring PostgreSQL afterwards and creating the table and
sequence the entity bean is to be mapped to. OpenEJB interacts with
databases and XML files with the help of Castor. Although Castor plays a
great role in OpenEJB the document doesn't assume you are already familiar
with it nor will it be described here thoroughly. It is strongly adviced
to learn more about Castor, indeed. Please visit Castor home page to find out more.
A few words are aimed to rise your awareness of the structure of OpenEJB
configuration file - openejb.conf - and how to modify it. That is going to
be a very broad overview and some facts are skipped for the sake of
simplicity.
The last but not least step will be to start up everything (i.e. OpenEJB,
PostgreSQL) and access the Employee entity bean from the out-of-process
client (i.e. the client, which is outside of JVM OpenEJB runs in).
Everything was tested on MS Windows 2000 with PostgreSQL 7.2.1 installed
on Cygwin 1.3.12-2 as well as with Sun JDK 1.3.1_04 and PostgreSQL JDBC
driver.
Before starting
This example assumes you have already followed the steps outlined in the
basic EJB example.
Create the entity bean class
First, create the package where we will place our ejb and application
files.
C:\> cd \my\app
C:\my\app> mkdir org\acme\employee
In your favorite editor, create the file below.
C:\my\app\org\acme\employee\EmployeeBean.java |
package org.acme.employee;
import javax.ejb.*;
import java.rmi.RemoteException;
public class EmployeeBean implements EntityBean
{
public int id;
public String firstname;
public String lastname;
public String email;
public EntityContext context;
public EmployeeBean()
{
}
public Integer ejbCreate( String firstname, String lastname, String email )
throws CreateException
{
this.firstname = firstname;
this.lastname = lastname;
this.email = email;
return null;
}
public void ejbPostCreate( String firstname, String lastname, String email )
throws CreateException
{
}
public void says( String message )
{
System.out.println( "[" + firstname + " " + lastname +
"(" + id + ") " + email + "] " + message );
}
public void setEntityContext( EntityContext context )
throws EJBException, RemoteException
{
this.context = context;
}
public void unsetEntityContext()
throws EJBException, RemoteException
{
}
public void ejbActivate()
throws EJBException, RemoteException
{
}
public void ejbLoad()
throws EJBException, RemoteException
{
}
public void ejbPassivate()
throws EJBException, RemoteException
{
}
public void ejbRemove()
throws RemoveException, EJBException, RemoteException
{
}
public void ejbStore()
throws EJBException, RemoteException
{
}
}
|
Create the entity bean's home interface
In your favorite editor, create the file below.
C:\my\app\org\acme\employee\EmployeeHome.java |
package org.acme.employee;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;
import javax.ejb.FinderException;
import java.rmi.RemoteException;
public interface EmployeeHome extends EJBHome
{
public Employee create( String firstname, String lastname, String email )
throws RemoteException, CreateException;
public Employee findByPrimaryKey( Integer id )
throws RemoteException, FinderException;
}
|
Create the entity bean's remote interface
In your favorite editor, create the file below.
C:\my\app\org\acme\employee\Employee.java |
package org.acme.employee;
import javax.ejb.EJBObject;
import java.rmi.RemoteException;
public interface Employee extends EJBObject
{
public void says( String message )
throws RemoteException;
}
|
Create the ejb-jar.xml
C:\my\app> mkdir META-INF
And finally it's time for the deployment descriptor of the entity bean.
In your favorite editor, create the file below.
C:\my\app\META-INF\ejb-jar.xml |
<?xml version="1.0"?>
<!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>
<enterprise-beans>
<entity>
<ejb-name>EmployeeBean</ejb-name>
<home>org.acme.employee.EmployeeHome</home>
<remote>org.acme.employee.Employee</remote>
<ejb-class>org.acme.employee.EmployeeBean</ejb-class>
<persistence-type>Container</persistence-type>
<prim-key-class>java.lang.Integer</prim-key-class>
<reentrant>False</reentrant>
<cmp-field>
<field-name>id</field-name>
</cmp-field>
<cmp-field>
<field-name>firstname</field-name>
</cmp-field>
<cmp-field>
<field-name>lastname</field-name>
</cmp-field>
<cmp-field>
<field-name>email</field-name>
</cmp-field>
<primkey-field>id</primkey-field>
<resource-ref>
<res-ref-name>jdbc/postgresql</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</entity>
</enterprise-beans>
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>EmployeeBean</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Supports</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>
|
Compile the EJB
C:\my\app> javac -d . -classpath %OPENEJB_HOME%\lib\ejb-2.0.jar org\acme\employee\*.java
Package the EJB
C:\my\app> jar -cvMf employee.jar org/acme/employee/*.class META-INF
Create necessary structures in the database (e.g. PostgreSQL)
The procedure outlined here describes how to prepare PostgreSQL to work
with the Employee entity bean. It basically shows the SQL statements to
create the structures: a table and sequence. As sequences are a few RDBMS'
feature you will have to work it around if your chosen database doesn't
support it or try out PostgreSQL. Will it ever be a better time to find
out what PostgreSQL is really able to do?
Firstly, let's start up PostgreSQL. It's assumed you followed the
procedures on how to configure PostgreSQL to allow external users connect
to the system, and a database is already created. Just to make sure we are
on the same track from now on the name of the database will be reffered to
as mydb, and the user and its password are username and
password, respectively.
Now, please connect to the database (i.e. invoke psql mydb
username) and run the following SQL scripts:
create table employee (
id integer primary key,
first_name varchar(15),
last_name varchar(15),
email varchar(30));
create sequence employee_seq;
|
Configure the data source
Having done everything up to that point has showed you really nothing
about OpenEJB itself. As you might have guessed, we're about to change it
and see how different files influence the way OpenEJB works.
When OpenEJB starts up, the default configuration file is
%OPENEJB_HOME%\conf\openejb.conf. We will, however, be using another one -
our own configuration file. We're doing it because:
|
 | it shall get you familiar with the configuration file's elements |
 | it shall avoid bothering you with log messages that do not pertain to our example |
 | it shall get you a feeling of how easy (or not) is to manage OpenEJB |
Thus, here goes the configuration file - openejb.xml - which will satisfy
the aforementioned requirements.
Create the file in the conf directory.
C:\my\app> mkdir conf
In your favorite editor, create the file below.
C:\my\app\conf\openejb.xml |
<?xml version="1.0"?>
<openejb>
<Container id="Default CMP Container" ctype="CMP_ENTITY">
Global_TX_Database c:/my/app/conf/postgresql.cmp_global_database.xml
Local_TX_Database c:/my/app/conf/postgresql.cmp_local_database.xml
</Container>
<Deployments jar="c:/my/app/employee.jar"/>
<Connector id="Default JDBC Database">
JdbcDriver org.postgresql.Driver
JdbcUrl jdbc:postgresql://localhost/mydb
UserName username
Password password
</Connector>
<SecurityService id="Default Security Service"/>
<TransactionService id="Default Transaction Manager"/>
</openejb>
|
Before we go on a few words about the structure of the file.
NOTE |
In future versions of OpenEJB, you won't be required to include
the SecurityService or TransactionService lines in your config
files unless there is some part of them that you wish to configure.
|
|
Create the following files in the conf directory using your favorite
editor.
C:\my\app\conf\postgresql.cmp_global_database.xml |
<?xml version="1.0"?>
<database name="Global_TX_Database" engine="postgresql">
<jndi name="java:comp/env/jdbc/postgresql" />
<mapping href="c:/my/app//conf/postgresql.cmp_or_mapping.xml" />
</database>
|
C:\my\app\conf\postgresql.cmp_or_mapping.xml |
<?xml version="1.0"?>
<mapping>
<class name="org.acme.employee.EmployeeBean" identity="id" key-generator="SEQUENCE">
<map-to table="employee"/>
<field name="id" type="integer" direct="true">
<sql name="id" type="integer"/>
</field>
<field name="firstname" type="string" direct="true">
<sql name="first_name" type="varchar" dirty="check"/>
</field>
<field name="lastname" type="string" direct="true">
<sql name="last_name" type="varchar" dirty="check"/>
</field>
<field name="email" type="string" direct="true">
<sql name="email" type="varchar" dirty="check"/>
</field>
</class>
</mapping>
|
C:\my\app\conf\postgresql.cmp_local_database.xml |
<?xml version="1.0"?>
<database name="Local_TX_Database" engine="postgresql">
<driver class-name="org.postgresql.Driver" url="jdbc:postgresql://localhost/mydb">
<param name="user" value="username"/>
<param name="password" value="password"/>
</driver>
<mapping href="C:\my\app\conf\postgresql.cmp_or_mapping.xml"/>
</database>
|
NOTE |
As connections to PostgreSQL are being performed through JDBC data source
PostgreSQL JDBC2 driver's classes have to be available to OpenEJB. Thus,
you need to download from PostgreSQL
JDBC2 driver home page and save it in %OPENEJB_HOME%\lib directory as
pgjdbc2.jar. The driver will be loaded by OpenEJB at startup.
|
|
Deploy the EJB jar
Use the OpenEJB Deploy Tool to deploy your jar.
C:\my\app> cd %OPENEJB_HOME%
C:\openejb> openejb deploy -a -conf c:\my\app\conf\openejb.xml c:\my\app\employee.jar
The tool will ask for the resource to link the bean's reference to. You
should type in 1 as it points to the resource declared in our
configuration file which is the "Default JDBC Database", i.e. PostgreSQL.
NOTE |
Since the OpenEJB deployment tool writes to your jar file, make sure that
no other programs are using it when you deploy (i.e. if you use an editor
such as Forte for Java to create the jar file, that editor may still be
using it). If you get an error such as "Error in writing existing jar
file" close any programs that may be using the jar and try deploying
again.
|
|
A basic client application
Create the basic client application to access your Employee entity bean.
The client looks up the entity EJBHome object, creates a user, then finds
it with findByPrimaryKey and finally compare the references to each
other in order to find out whether or not they points to the same
EJBObject managed by OpenEJB. The following lines show invocation of the
bussines method - says - and at the end removes the bean's
representation from the table.
Please refer to the basic EJB example to
choose proper InitialContext environment variables.
C:\openejb> cd c:\my\app
Create the file in your favorite editor.
C:\my\app\org\acme\employee\EmployeeClient.java |
package org.acme.employee;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;
import java.util.Properties;
public class EmployeeClient
{
public static void main( String[] args )
throws Exception
{
Properties env = new Properties();
//The JNDI properties you set depend
//on which server you are using.
Stirng jndiProvider = "org.openejb.client.JNDIContext";
env.put( "java.naming.factory.initial", jndiProvider );
env.put( "java.naming.provider.url", "localhost:4201" );
env.put( "java.naming.security.principal", "fakeuser" );
env.put( "java.naming.security.credentials", "fakepass" );
Context ctx = new InitialContext( env );
Object obj = ctx.lookup( "EmployeeBean" );
obj = PortableRemoteObject.narrow( obj, EmployeeHome.class );
EmployeeHome home = ( EmployeeHome ) obj;
Employee empl_create = home.create( "Jacek", "Laskowski",
"OpenEJB-" + System.currentTimeMillis() + "@SF.net" );
Integer primaryKey = ( Integer ) empl_create.getPrimaryKey();
Employee empl_find = home.findByPrimaryKey( primaryKey );
System.out.println( "Are the \"create\" and \"find\" users identical ? "+
empl_create.isIdentical( empl_find ) );
empl_find.says( "Hello OpenEJB World!" );
empl_find.remove();
}
}
|
Compile the application
C:\my\app> javac -d . -classpath .;%OPENEJB_HOME%/lib/ejb-1.0.jar;%OPENEJB_HOME%/lib/jndi_1.2.1.jar org\acme\employee\EmployeeClient.java
Run it!
Create the file in your favorite editor.
C:\my\app\RunIt.bat |
@echo off
set OPENEJB_HOME=C:\openejb
set PATH=%PATH%;%OPENEJB_HOME%\bin
set OLD_CLASSPATH=%CLASSPATH%
set CP=
for %%i in (%OPENEJB_HOME%\lib\*.jar) do call cp.bat %%i
for %%i in (%OPENEJB_HOME%\dist\*.jar) do call cp.bat %%i
set CP=c:\my\app\employee.jar;%CP%
set CLASSPATH=%JAVA_HOME%\lib\tools.jar;%CP%
%JAVA_HOME%\bin\java -Dopenejb.home=%OPENEJB_HOME% org.acme.employee.EmployeeClient
set CLASSPATH=%OLD_CLASSPATH% |
Open the command line window and start up OpenEJB with the following
command:
C:\> cd %OPENEJB_HOME%
C:\openejb> start openejb start -conf c:\my\app\conf\openejb.xml
Now run the script!
C:\> cd \my\app
C:\my\app> RunIt
You will see the following sample output on the out-of-process client's console:
C:\my\app>RunIt
Are the "create" and "find" users identical ? true |
And the following on the OpenEJB server's console:
OpenEJB Remote Server 0.8.1 build: 20020731-0133
http://openejb.sf.net
----------------STARTUP----------------
[init] OpenEJB Container System
[init] OpenEJB Remote Server
** Starting Services **
NAME IP PORT
ejb server 127.0.0.1 4201
admin console 127.0.0.1 4200
-----------------INFO------------------
To log into the admin console, telnet to:
telnet 127.0.0.1 4200
---------------------------------------
Ready!
[FirstName LastName(1) OpenEJB-1029465232802@SF.net] Hello OpenEJB World ! |
What if it didn't work
If you ran into any problems, first check your openejb.log file at
%OPENEJB_HOME%\openejb.log. Look for any lines that begin with
"WARN", "ERROR", or "FATAL".
There is a list of the most common problems with possible solutions:
|
 |
Problem:
OpenEJB Remote Server 0.8.1 build: 20020731-0133
http://openejb.sf.net
----------------STARTUP----------------
[init] OpenEJB Container System
java.lang.ClassNotFoundException: org.postgresql.Driver
at java.net.URLClassLoader$1.run(URLClassLoader.java:195)
at java.security.AccessController.doPrivileged(Native Method)
...
|
Solution: Add the PostgreSQL JDBC2 driver to OpenEJB's
CLASSPATH. See the Configure the data source
section for more details.
|
If nothing has helped, email it to the OpenEJB user mailing list and let people know
you are using the basic CMP entity bean example.
|