bekwam courses

WildFly EJB Development with IntelliJ and Maven

January 2, 2019

Coming from a CORBA background, I wasn't too bothered by the complexity of the early versions of Enterprise Java Beans. However, it didn't take long for me to appreciate the ease of development with the Spring Framework. And it wasn't just me who had this appreciation. The authors of JavaEE overhauled their product in JavaEE 5 to reduce the amount of code needed to build EJBs. JavaEE 6 brought additional EJB packaging options. This article shows a development environment setup for efficiently working with EJBs with this newer innovations.

The IntelliJ screenshots in this article are of the Ultimate Edition which is the commercial (not free) edition. Ultimate is needed for the JBoss connector.

This article demonstrates a JAX-RS (REST) web service backed by a Stateless EJB. When an HTTP GET is issued to the web service, the web service invokes the EJB. The EJB contains business logic -- a simple String format call -- and returns a synchronous result to the web service. The web service returns a text/plain String to the caller, a browser in this case. In this article, the REST web service is the component "MessageResource" and the EJB is "MessageEJB".

Background

WAR. JAR. EAR. These are all zip files that adhere to a certain JavaEE specification. A special suffix is a cue to the application as to the type of artifacts, the internal structure, and the deployment descriptors in the file. These are the types of JavaEE archives used in the article.

WAR
Web archive - static web pages, dynamic Java Server Pages, REST or SOAP services, embedded EJBs
JAR
Java archive - a library or EJB packaging
EAR
Enterprise archive - an archive containing WARs, EJB JARs, application clients, and plain JAR libraries

The following screenshot shows the Embedded JAR deployment. A WAR containing both the MessageResource component and MessageEJB component is deployed to WildFly as wf-restful-w-ejbs-devenv-demo-rs.war. The EJB is packaged in its own JAR, wf-restful-w-ejbs-devenv-demo-ejb.jar. That JAR is found in the /WEB-INF/lib folder of the WAR.

UML Deployment Diagram
Embedded JAR Deployment

I generally prefer this deployment because it maintains the source in different source modules yet is deployable in a single artifact. By keeping the source separate, I'm able to maintain the web and business logic dependencies separately. In a later section, a Maven multi-module configuration will be shown which keeps both the web and the EJB source in a single browsable unit for the developer while preserving the distinctness.

Although not presented in the devenv setup steps below, I included the following alternative deployments for comparison. This first diagram shows a deployment whereby the REST Java source and the EJB Java source are co-mingled. This results in a single WAR file with all generated .class files packaged in the /WEB-INF/classes folder.

UML Deployment Diagram
Single WAR Deployment (No EJB JAR)

The historical deployment of EJBs has been to use an Enterprise Archive (EAR) file. This is best suited for deployment multiple WARs and EJB JARs in a single artifact. In this deployment the WAR itself is packaged in a containing archive, the EAR. The EJB JAR is deployed alongside the WARs.

UML Deployment Diagram
EAR Deployment

Maven and IntelliJ Project Setup

This article presents a multi-module Maven project. A containing parent project will be defined (packaging=pom) that contains two children. One child will be the EJB (packaging=jar) and the other the RESTful web service (packaging=war). There is a dependency of the RESTful service on the EJB JAR. This dependency will package the EJB JAR in the /WEB-INF/lib folder of the WAR.

  1. In IntelliJ, select File > New > Project
  2. Select Maven
  3. Going through the wizard, specify a group, artifact, and then a path. In this example, group=org.bekwam and artifact=wf-restful-w-ejb-devenv-demo
  4. Right-click the parent project and select New > Module
  5. Select Maven and go through the wizard to specify the Maven coordinates for the EJB JAR. In this example, this is group=org.bekwam and artifact=wf-restful-w-ejb-devenv-demo-ejb. Make sure that a parent is listed in the New Module dialog.
  6. Right-click the parent project again and select New > Module
  7. Select Maven and go through the wizard to specify the Maven coordinates for the RESTful WAR. In this example, this is group=org.bekwam and artifact=wf-restful-w-ejb-devenv-demo-rs. Make sure that a parent is listed in the New Module dialog.

At this point, the folders that will house the source code have been created. Next, we will edit the Maven files to match the artifacts that we want to produce.

  1. Double-click the parent pom.xml to edit. Make sure that the pom has the artifact "wf15-restful-w-ejbs-devenv-demo" listed.
  2. Set the Java 8 version using the properties element (see listing below)
  3. Add the shared JavaEE dependency
  4. Verify that both the JAX-RS and the EJB modules appear in the modules element

Compare your edits with the listing below. Directly edit any missing settings.


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.bekwam</groupId>
    <artifactId>wf15-restful-w-ejbs-devenv-demo</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>wf15-restful-w-ejbs-devenv-demo-rs</module>
        <module>wf15-restful-w-ejbs-devenv-demo-ejb</module>
    </modules>

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

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


</project>

Next, edit the pom of the EJB module. This is the pom with the artifactId "wf15-restful-w-ejbs-devenv-demo-ejb".

  1. Set the packaging to "ejb".

The EJB pom.xml is listed below.

	
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>wf15-restful-w-ejbs-devenv-demo</artifactId>
        <groupId>org.bekwam</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <packaging>ejb</packaging>

    <artifactId>wf15-restful-w-ejbs-devenv-demo-ejb</artifactId>

</project>

Finally, edit the pom of the JAX-RS module. This is the pom with the artifactId "wf15-restful-w-ejbs-devenv-demo-rs".

  1. Change the packaging to war (see the listing below)
  2. Add a dependency for the RESTEasy framework
  3. Add a dependency for the EJB module
  4. Add a WAR plugin configuration section allowing for now web.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>wf15-restful-w-ejbs-devenv-demo</artifactId>
        <groupId>org.bekwam</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <packaging>war</packaging>
    <artifactId>wf15-restful-w-ejbs-devenv-demo-rs</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-jaxrs</artifactId>
            <version>3.6.2.Final</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.bekwam</groupId>
            <artifactId>wf15-restful-w-ejbs-devenv-demo-ejb</artifactId>
            <version>${project.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

EJB Code

Once requiring multiple classes, interfaces, and XML, the EJB as of JavaEE 6 can be reduced to a single Java class: the No-Interface View. This is a Local EJB as in local to the JVM and not exposed remotely. MessageEJB is the single Java class that realizes the MessageEJB component shown in the deployment diagrams. The class is a POJO marked up with the @Stateless annotation. The single getMessage() method returns a randomized formatted String based on the passed-in value "name".

In the src/main/java folder of the EJB module, create a package "msg.ejb". Add the following Java class to that package.

MessageEJB.java Listing

	
package msg.ejb;

import javax.ejb.Stateless;
import java.util.Random;

@Stateless
public class MessageEJB {

    private final String[] messages = { "Hey", "Hi", "Hello" };

    public String getMessage(String name) {
        return String.format("%s %s!", messages[new Random().nextInt(3)], name);
    }
}
	

RESTful Web Services Code

The JAX-RS code listed below, MessageResource, handles and HTTP GET and delegates immediately to a dependency-injected MessageEJB. The Application subclass is a JAX-RS requirement for letting WildFly know about the service.

In the src/main/java folder of the JAX-RS module, create a package "msg.rs". Add the following two Java classes to that package.

MessageResource.java Listing


package msg.rs;

import msg.ejb.MessageEJB;

import javax.ejb.EJB;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;

@Path("/message")
public class MessageResource {

    @EJB
    private MessageEJB messageEJB;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String getMessage(@QueryParam("name") String name) { return messageEJB.getMessage(name); }
}

The @EJB annotation automatically injects an instance of the @Stateless MessageEJB into the RESTful web service.

APIApplication.java

	
package msg.rs;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import java.util.HashSet;
import java.util.Set;

@ApplicationPath("/api")
public class APIApplication extends Application {
    @Override
    public Set<Class<?>> getClasses() {
        Set<Class<?>> set = new HashSet<>();
        set.add( MessageResource.class );
        return set;
    }
}	
	

The resulting project, module, package structure should look like the following screenshot of the IntelliJ Project Browser.

IntelliJ Project Browser
Project, Modules, and Packages

Deployment and Testing

To deploy the WAR file for testing, follow the WildFly Runtime setup in this article. You'll deploy the exploded WAR file as in that example.

To test the service, run the app server, and enter the following URL in a browser. You will see something like this. The actual greeting (Hey/Hi) may be different because of the randomness.

A Browser Showing a Greeting
Testing the RESTful Web Service and EJB

Because the WildFly Runtime setup specified "Redeploy" in the JBoss configuration screen, you can edit either the EJB or the JAX-RS code and press Ctrl-F10 to test your changes.

In past versions of JavaEE, quite a few classes were required to expose your business logic as an EJB. These days, only one is required, the No-Interface View. And that class contains a minimum of EJB markings. This article showed how to develop a concise EJB in a simple deployment. Because you're leveraging WildFly, this component is ready to handle many new functions such as DB access, reliable messaging, transactions, and role-based authorization.


Headshot of Carl Walker

By Carl Walker

President and Principal Consultant of Bekwam, Inc