1. Overview

In this article, we’re going to discuss how to get started with Enterprise JavaBean (EJB) development.

Enterprise JavaBeans are used for developing scalable, distributed, server-side components and typically encapsulate the business logic of the application.

We’ll use WildFly 10.1.0 as our preferred server solution, however, you are free to use any Java Enterprise application server of your choice.

2. Setup

Let’s start by discussing the Maven dependencies required for EJB 3.2 development and how to configure the WildFly application server using either the Maven Cargo plugin or manually.

2.1. Maven Dependency

In order to use EJB 3.2**,** make sure you add the latest version to the dependencies section of your pom.xml file:

<dependency>
    <groupId>javax</groupId>
    <artifactId>javaee-api</artifactId>
    <version>7.0</version>
    <scope>provided</scope>
</dependency>

2.2. WildFly Setup With Maven Cargo

Let’s talk about how to use the Maven Cargo plugin to setup the server.

Here is the code for the Maven profile that provisions the WildFly server:

<profile>
    <id>wildfly-standalone</id>
    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.cargo</groupId>
                <artifactId>cargo-maven2-plugin</artifactId>
                <version>${cargo-maven2-plugin.version</version>
                <configuration>
                    <container>
                        <containerId>wildfly10x</containerId>
                        <zipUrlInstaller>
                            <url>
                                http://download.jboss.org/
                                  wildfly/10.1.0.Final/
                                    wildfly-10.1.0.Final.zip
                            </url>
                        </zipUrlInstaller>
                    </container>
                    <configuration>
                        <properties>
                            <cargo.hostname>127.0.0.0</cargo.hostname>
                            <cargo.jboss.management-http.port>
                                9990
                            </cargo.jboss.management-http.port>
                            <cargo.servlet.users>
                                testUser:admin1234!
                            </cargo.servlet.users>
                        </properties>
                    </configuration>
                </configuration>
            </plugin>
        </plugins>
    </build>
</profile>

We use the plugin to download the WildFly 10.1 zip directly from the WildFly’s website. Which is then configured, by making sure that the hostname is 127.0.0.1 and setting the port to 9990.

Then we create a test user, by using the cargo.servlet.users property, with the user id testUser and the password admin1234!.

Now that configuration of the plugin is completed we should be able to call a Maven target and have the server download, installed, launched and the application deployed.

To do this, navigate to the ejb-remote directory and run the following command:

mvn clean package cargo:run

When you run this command for the first time, it will download the WildFly 10.1 zip file, extract it and execute the installation and then launch it. It will also add the test user discussed above. Any further executions will not download the zip file again.

2.3. Manual Setup of WildFly

In order to setup WildFly manually, you must download the installation zip file yourself from the wildfly.org website. The following steps are a high-level view of the WildFly server setup process:

After downloading and unzipping the file’s contents to the location where you want to install the server, configure the following environment variables:

JBOSS_HOME=/Users/$USER/../wildfly.x.x.Final
JAVA_HOME=`/usr/libexec/java_home -v 1.8`

Then in the bin directory, run the ./standalone.sh for Linux based operating systems or ./standalone.bat for Windows.

After this, you will have to add a user. This user will be used to connect to the remote EJB bean. To find out how to add a user you should take a look at the ‘add a user’ documentation.

For detailed setup instructions please visit WildFly’s Getting Started documentation.

The project POM has been configured to work with the Cargo plugin and manual server configuration by setting two profiles. By default, the Cargo plugin is selected. However to deploy the application to an already installed, configured and running Wildfly server execute the following command in the ejb-remote directory:

mvn clean install wildfly:deploy -Pwildfly-runtime

3. Remote vs Local

A business interface for a bean can be either local or remote.

A @Local annotated bean can only be accessed if it is in the same application as the bean that makes the invocation, i.e. if they reside in the same .ear or .war.

A @Remote annotated bean can be accessed from a different application, i.e. an application residing in a different JVM or application server.

There are some important points to keep in mind when designing a solution that includes EJBs:

  • The java.io.Serializable, java.io.Externalizable and interfaces defined by the javax.ejb package are always excluded when a bean is declared with @Local or @Remote
  • If a bean class is remote, then all implemented interfaces are to be remote
  • If a bean class contains no annotation or if the @Local annotation is specified, then all implemented interfaces are assumed to be local
  • Any interface that is explicitly defined for a bean which contains no interface must be declared as @Local
  • The EJB 3.2 release tends to provide more granularity for situations where local and remote interfaces need to explicitly defined

4. Creating the Remote EJB

Let’s first create the bean’s interface and call it HelloWorld:

@Remote
public interface HelloWorld {
    String getHelloWorld();
}

Now we will implement the above interface and name the concrete implementation HelloWorldBean:

@Stateless(name = "HelloWorld")
public class HelloWorldBean implements HelloWorld {

    @Resource
    private SessionContext context;

    @Override
    public String getHelloWorld() {
        return "Welcome to EJB Tutorial!";
    }
}

Note the @Stateless annotation on the class declaration. It denotes that this bean is a stateless session bean. This kind of bean does not have any associated client state, but it may preserve its instance state and is normally used to do independent operations.

The @Resource annotation injects the session context into the remote bean.

The SessionContext interface provides access to the runtime session context that the container provides for a session bean instance. The container then passes the SessionContext interface to an instance after the instance has been created. The session context remains associated with that instance for its lifetime.

The EJB container normally creates a pool of stateless bean’s objects and uses these objects to process client requests. As a result of this pooling mechanism, instance variable values are not guaranteed to be maintained across lookup method calls.

5. Remote Setup

In this section, we will discuss how to setup Maven to build and run the application on the server.

Let’s look at the plugins one by one.

5.1. The EJB Plugin

The EJB plugin which is given below is used to package an EJB module. We have specified the EJB version as 3.2.

The following plugin configuration is used to setup the target JAR for the bean:

<plugin>
    <artifactId>maven-ejb-plugin</artifactId>
    <version>2.4</version>
    <configuration>
        <ejbVersion>3.2</ejbVersion>
    </configuration>
</plugin>

5.2. Deploy the Remote EJB

To deploy the bean in a WildFly server ensure that the server is up and running.

Then to execute the remote setup we will need to run the following Maven commands against the pom file in the ejb-remote project:

Then we should run:

mvn wildfly:deploy

Alternatively, we can deploy it manually as an admin user from the admin console of the application server*.*

public HelloWorld lookup() throws NamingException { 
    String appName = ""; 
    String moduleName = "remote"; 
    String distinctName = ""; 
    String beanName = "HelloWorld"; 
    String viewClassName = HelloWorld.class.getName();
    String toLookup = String.format("ejb:%s/%s/%s/%s!%s",
      appName, moduleName, distinctName, beanName, viewClassName);
    return (HelloWorld) context.lookup(toLookup);
}

To connect to the remote bean we need a JNDI context. The context factory is provided by the Maven artifact org.jboss:jboss-remote-naming and this creates a JNDI context, which will resolve the URL constructed in the lookup method, into proxies to the remote application server process.

7.4. Define Lookup Parameters

We define the factory class with the parameter Context.INITIAL_CONTEXT_FACTORY.

The Context.URL_PKG_PREFIXES is used to define a package to scan for additional naming context.

The parameter org.jboss.ejb.client.scoped.context = false tells the context to read the connection parameters (such as the connection host and port) from the provided map instead of from a classpath configuration file. This is especially helpful if we want to create a JAR bundle that should be able to connect to different hosts.

The parameter Context.PROVIDER_URL defines the connection schema and should start with http-remoting://.

8. Testing

To test the deployment and check the setup, we can run the following test to make sure everything works properly:

@Test
public void testEJBClient() {
    EJBClient ejbClient = new EJBClient();
    HelloWorldBean bean = new HelloWorldBean();
    
    assertEquals(bean.getHelloWorld(), ejbClient.getEJBRemoteMessage());
}

With the test passing, we can now be sure everything is working as expected.

9. Conclusion

So we have created an EJB server and a client which invokes a method on a remote EJB. The project can be run on any application server by properly adding the dependencies for that server.

The entire project can be found over on GitHub.