Deploying EJB JARs to a WildFly Swarm Microservice

Datetime:2016-08-23 01:56:59          Topic: EJB  Microservice           Share

If there is one standard that is synonymous with JavaEE, it’s EJB. Enterprise Java Beans have been around for decades, and having the choice to use them in your WildFly Swarm microservices is something that I suspect will appeal to a lot of developers.

To get started with EJBs, we need to import some new dependencies. I have lamented in previous posts that it can be quite painful trying to work out the versions of the various dependencies that make up a Swarm application. WildFly Swarm Beta 8 was just released, but that doesn’t mean that every dependency has been updated to Beta 8, and working out what versions to use is time consuming and error prone.

Maven has solved this particular issue with the BOM, or Bill Of Materials. By referencing a BOM, you can then add dependencies without having to know each individual version. Gradle doesn’t have this functionality natively , but a  3rd party plugin provides us with the ability to reference the Swarm BOM and let it deal with the dependency versions.

With dependency versions now being supplied by the BOM, we can go ahead and add dependencies on the Swarm EJB library, which gives us the EJB functionality,  and the Java EE 7.0 spec library, which gives us all the EJB imports we need to reference. You’ll also notice that we have defined a custom Main class, which is where we will be constructing the EJB application hosted by Swarm.

buildscript {
    repositories {
        mavenLocal()
        mavenCentral()
    }

    dependencies {
        classpath "org.wildfly.swarm:wildfly-swarm-plugin:1.0.0.Beta8"
        classpath "io.spring.gradle:dependency-management-plugin:0.5.6.RELEASE"
    }
}

group 'com.matthewcasperson'
version '1.0-SNAPSHOT'

apply plugin: 'java'
apply plugin: "io.spring.dependency-management"
apply plugin: 'wildfly-swarm'

sourceCompatibility = 1.8

swarm {
    mainClassName = 'com.matthewcasperson.swarmdemo.Main'
}

def swarmVersion = '1.0.0.Beta8'
repositories {
    mavenCentral()
    mavenLocal()
    maven {
        url 'http://repository.jboss.org/nexus/content/groups/public-jboss'
    }
    maven {
        url 'https://maven.repository.redhat.com/nexus/content/repositories/public'
    }
}

dependencyManagement {
    imports {
        mavenBom "org.wildfly.swarm:bom:$swarmVersion"
    }
}


dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.11'

    compileOnly 'javax:javaee-api:7.0'
    compile 'org.apache.commons:commons-lang3:3.4'

    compile 'org.wildfly.swarm:bootstrap'
    compile 'org.wildfly.swarm:ejb'

}

// For heroku
task stage {
    dependsOn build
}

Let’s take a look at the EJB itself. It is very simple, defining a singleton that is to be instantiated at startup, and with a method to be executed once the EJB is constructed. Inside this method we log out some information that will let us know that the EJB has been built and executed.

package com.matthewcasperson.swarmdemo;

import org.apache.commons.lang3.StringUtils;

import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * A simple EJB that will log to the console when it is started up. Note that
 * we make use of o=some third party libraries (Apache Commons Lang in this case)
 * just to prove that we can build a self contained EJB JAR file.
 */
@Startup
@Singleton
public class EJB {
    private static final Logger LOGGER = Logger.getLogger(EJB.class.getName());

    /*
        This method will be called by the EJB container when the instance is constructed.
     */
    @PostConstruct
    public void postConstruct() {
        /*
            Notice that we have made use of the Apache Lang library here to trim our log message.
         */
        LOGGER.log(Level.INFO, StringUtils.trim("  EJB.postConstruct() called"));
    }
}

To make this scenario a little more realistic we have added a dependency on the StringUtils class, which is provided by the Apache Commons Lang project. It serves no real purpose, but does force us to consider how we are going to package these third party dependencies with our EJB.

The whole notion of an UberJar is a workaround to the fact that on their own, JAR files are pretty useless because they are often not self contained and require a whole host of supporting JAR files to form a complete application.

Unlike a WAR or EAR file, a JAR file doesn’t natively support the notion of packaging dependencies. WAR files can contain compiled Java classes alongside supporting JAR files to provide a self contained application. UberJars emulate this by extracting a collection of JAR files and repackaging them as a single JAR file that can be run standalone.

This process of building up a self contained JAR is something that we will replicate in the custom Main class of our demo application.

If you have ever looked inside the JAR file created by the Swarm build plugins, you’ll notice a directory called m2repo. This is where Swarm stores the JAR files that we imported as part of the Gradle/Maven build script. What we need to do is find a way to embed these JAR files into the Shinkwrap EJB JAR file that we build up inside the Main class.

Fortunately, Swarm comes with a class called ArtifactLookup that we can leverage to find these embeded JAR files and add them to the Shinkwrap EJB JAR that we want to deploy. Calling ArtifactLookup.get().allArtifacts(new String[]{"org.wildfly.swarm"}) returns the dependencies that the Swarm build plugin embedded into the Swarm UberJar, excluding any that relate to Swarm itself (which our application is not interested in).

We then loop over this collection of dependencies and merge them into our Shinkwrap JAR file, which has the effect of creating a EJB UberJar that we can deploy within Swarm.

In effect we have taken the dependencies embedded in the Swarm UberJar (i.e. the UberJar built by the Swarm build plugins at compile time) and used them to create a virtual Shinkwrap EJB UberJar at runtime which can then be deployed to Swarm container. This “Swarm UberJar hosting an EJB UberJar” situation can be a bit mind bending at first, but just think of Swarm as being an environment which provides the dependencies and tools you need to construct the you application artifacts at runtime and deploy them to an instance of WildFly provided by Swarm. So instead of using a Gradle or Maven script to compile a WAR/JAR file and deploying that manually to a separate WildFly server, you use the Shinkwrap and Swarm APIs to build the same artifacts at runtime and then deploy them to the Swarm WildFly server.

That was kind of a wordy explaination, but fortunately the code is actually pretty concise.

package com.matthewcasperson.swarmdemo;

import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.wildfly.swarm.container.Container;
import org.wildfly.swarm.spi.api.ArtifactLookup;
import org.wildfly.swarm.spi.api.JARArchive;

import java.util.List;

/**
 * Created by matthewcasperson on 2/05/2016.
 */
public class Main {
    public static void main(final String[] args) throws Exception {
        final Container container = new Container();
        container.start();

        final JARArchive ejbArchive = ShrinkWrap.create(JARArchive.class);
        ejbArchive.addClass(EJB.class);

        /*
            Merge in the dependencies that the warm build plugin included in the Swarm UberJar
            into an EJB UberJar. This gives us a self contained EJB JAR file that Swarm can then
            deploy and run.
         */
        final List<JavaArchive> artifacts = ArtifactLookup.get().allArtifacts(new String[]{"org.wildfly.swarm"});
        for (final JavaArchive javaArchive : artifacts) {
            ejbArchive.merge(javaArchive);
        }

        // Deploy your app
        container.deploy(ejbArchive);
    }
}

When run, you’ll see the log message being printed to the console, complete with the trimming provided by the Apache library.

You can find the source code to this demo on GitHub .

You can find articles in this serieshere.





About List