A Simple Entity Bean with OpenEJB

With a stateless session bean under our belt, a simple entity bean logically follows. This example mirrors the OpenEJB CMP entity bean example provided by the OpenEJB team. The database changes from PostgreSQL to HSqlDB. And the ant build file incorporates a custom OpenEJB configuration, automated entity bean deployment, and both local and remote execution.

Let’s start with the mapping file. The example is self-explanatory: specify the primary key or identity value along with the insertion key generation method, map the three bean member variables to database elements, and declare types for each mapping pair. This example uses the HSqlDB identity for key generation, where the OpenEJB example used a PostgreSQL sequence. Take a look at the Castor DTD and the Castor JDO key generator support for more information on writing a mapping file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0"?>

<mapping>
  <class name="org.acme.keyword.KeywordBean" identity="id" key-generator="IDENTITY">
    <map-to table="keywords" />
    <field name="id" type="integer" direct="true">
      <sql name="id" type="integer" />
    </field>
    <field name="name" type="string" direct="true">
      <sql name="name" type="varchar" dirty="check"/>
    </field>
    <field name="info" type="string" direct="true">
      <sql name="description" type="varchar" dirty="check"/>
    </field>
  </class>
</mapping>

The remaining configuration files mirror the OpenEJB entity bean example. Note that the included configuration files use absolute path names and must be modified for your installation. All the configuration files are located in the ./src/conf/ directory.

There are only slight changes to the ant build file for this example. We explicitly copy the jar file to the deployments directory and execute the deploy method in place. This works around surprising deploy copy method behavior when using a custom bean deployments directory. The new deploy target is shown below. Note that an input file has been specified for the openejb deploy method — the input file provides the query for a Home findByName method.

1
2
3
4
5
6
7
8
9
  <target name="deploy" depends="jar,deploy-check" unless="deploy.notNeeded">
    <copy file="${BeanJar}" todir="${obj-dir}/beans" />
    <exec dir="${OPENEJB}"
          executable="${OPENEJB}/openejb.sh"
          input="${src-dir}/conf/keyword.deploy"
          >
      <arg line="deploy -conf ${src-dir}/conf/openejb.xml -a ${obj-dir}/beans/${JarName}"/>
    </exec>
  </target>

Here is the Home interface definition. The findByPrimaryKey method is automatically implemented while the findByName method requires that we define a query when deploying the bean (as described in the previous paragraph).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package org.acme.keyword;

import javax.ejb.CreateException;
import javax.ejb.EJBHome;
import javax.ejb.FinderException;
import java.rmi.RemoteException;


public interface KeywordHome extends EJBHome
{
    public Keyword create( String name )
        throws RemoteException, CreateException;

    public Keyword create( String name, String info )
        throws RemoteException, CreateException;

    public Keyword findByPrimaryKey( Integer id )
        throws RemoteException, FinderException;

    public Keyword findByName( String name )
        throws RemoteException, FinderException;
}

Exercise the entity bean with this simple driver method. It simply searches for a keyword bean named openejb. If the bean exists, then we remove it. And if it does not exist, then we create it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import org.acme.keyword.*;

import java.util.Properties;
import java.rmi.*;
import javax.ejb.*;
import javax.rmi.*;
import javax.naming.*;


public class Driver
{

    public static void main( String[] args )
    {
        try {
            InitialContext ctx = new InitialContext( System.getProperties() );
            Object obj = ctx.lookup( "KeywordBean" );
            KeywordHome home = (KeywordHome)
                PortableRemoteObject.narrow( obj,KeywordHome.class );

            Keyword keyword;
            try {
                keyword = home.findByName( "openejb" );
                System.out.println( "Remove: " + keyword.name() +
                                    "-" + keyword.info() );
                keyword.remove();
            }
            catch ( ObjectNotFoundException notFound ) {
                System.out.println( "Create keyword openejb" );
                keyword = home.create( "openejb","an EJB container" );
            }
            catch ( FinderException fe ) {
                fe.printStackTrace();
            }
        }
        catch ( Exception ex ) {
            ex.printStackTrace();
        }
    }

}

Sample output from two local executions. The first execution creates the bean and the second removes it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
$ ant local
Buildfile: build.xml

init:

compile:

jar:

deploy-check:

deploy:

local:
     [java] OpenEJB 0.9.2    build: 20030605-0409
     [java] http:/\/openejb.sf.net
     [java] Create keyword openejb



BUILD SUCCESSFUL
Total time: 27 seconds
$ ant local
Buildfile: build.xml

init:

compile:

jar:

deploy-check:

deploy:

local:
     [java] OpenEJB 0.9.2    build: 20030605-0409
     [java] http:/\/openejb.sf.net
     [java] Remove: openejb-an EJB container



BUILD SUCCESSFUL
Total time: 18 seconds

Just for the record, here is my openejb software configuration. And here is the simple OpenEJB Entity Bean.

Disclaimer: I don’t claim to be an expert on OpenEJB. Please send comments and corrections.