Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Microservices Using WildFly Swarm, Docker, and Couchbase

DZone's Guide to

Microservices Using WildFly Swarm, Docker, and Couchbase

See how to use Wildfly Swarm, Docker, and Couchbase to develop microservices in Java with source code.

· Integration Zone
Free Resource

Today’s data climate is fast-paced and it’s not slowing down. Here’s why your current integration solution is not enough. Brought to you in partnership with Liaison Technologies.

Containers, Microservices, and NoSQL provide an awesome threesome for building your modern applications. These applications need to be agile, meet constantly evolving customer demands, be pervasive, and should work across mobile, web, and IoT platforms.

This blog will explain a simple microservices stack using WildFly Swarm, Docker, and Couchbase. Complete code and instructions in this blog are documented at: github.com/arun-gupta/wildfly-swarm-couchbase.

Let's understand the key components of this stack first!

wildfly-swarm-logoWildFly Swarm allows to package and run JavaEE applications by packaging them with just enough of the server runtime to java -jar your application. With built-in service discovery, single sign-on using Keycloak, monitoring using Hawkular, and many more features, WildFly Swarm provides all the necessary components to develop your microservice.

docker-for-mac

Docker for Mac provides native support for running Docker containers on Mac OSX. It relies upon Hypervisor.framework in OSX. Docker engine runs in an Alpine Linux distribution on top of an xhyve Virtual Machine, and even the VM is managed by Docker. There is no need for Docker Machine or VirtualBox, and it integrates with OSX security sandbox model. DockerCon 2016 removed the private beta restriction from Docker for Mac, and so it's available for everybody now. Couchbase Logo

NoSQL provides the agility and flexibility of schema-less databases. This allows the application to evolve independently and rapidly without going through cumbersome database migrations. Couchbase offers true horizontal scaling with homogenous architecture, as opposed to non-scalable master/slave architecture. It also offers auto-sharding, SQL-like query language for JSON (N1QL), mobile database and synchronization with the backend server, and much more. The complete sample application in this blog is at: github.com/arun-gupta/wildfly-swarm-couchbase.

WildFly Swarm Application

Let's look at the Java EE REST endpoint:

package com.couchbase.wildfly.swarm;

. . .

@Path("airline")
public class AirlineResource {

    @Inject Database database;

    @GET
    public String getAll() {
        N1qlQuery query = N1qlQuery.simple("SELECT * FROM `travel-sample` LIMIT 10");
        N1qlQueryResult result = database.getBucket().query(query);
        return result.allRows().toString();
    }

. . .
}

It uses standard JAX-RS annotation to convert a POJO into a REST endpoint. The Couchbase Java API provides a fluent API and uses a N1QL statement to query the documents and return the results. The N1QL statement returns the first 10 elements from the query result. Learn more about N1QL syntax in this interactive tutorial. Database abstraction is defined as:

package com.couchbase.wildfly.swarm;

. . .

@Singleton
@Startup
public class Database {

    CouchbaseCluster cluster;
    Bucket bucket;

    public CouchbaseCluster getCluster() {
        if (null == cluster) {
            String couchbaseURI = System.getenv("COUCHBASE_URI");
            if (null == couchbaseURI) {
                System.err.println("WARING: No COUCHBASE_URI specified, defaulting to localhost");
                couchbaseURI = "localhost:8093";
            }
            System.out.println("Couchbase endpoint: " + System.getenv("COUCHBASE_URI"));
            cluster = CouchbaseCluster.create(couchbaseURI);
        }
        return cluster;
    }

    public Bucket getBucket() {
        if (null == bucket) {
            bucket = getCluster().openBucket("travel-sample");
        }
        return bucket;
    }
}

This is a singleton EJB that is eagerly initialized. It uses the Couchbase Java SDK to connect to Couchbase. Database endpoint can be specified using the COUCHBASE_URI environment variable. Next up is pom.xml for configuring the WildFly Swarm and Couchbase Java Client:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.wildfly.swarm</groupId>
            <artifactId>bom</artifactId>
            <version>${version.wildfly-swarm}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-web-api</artifactId>
        <version>7.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.wildfly.swarm</groupId>
        <artifactId>jaxrs-cdi</artifactId>
    </dependency>
    <dependency>
        <groupId>org.wildfly.swarm</groupId>
        <artifactId>ejb</artifactId>
    </dependency>
    <dependency>
        <groupId>com.couchbase.client</groupId>
         <artifactId>java-client</artifactId>
        <version>2.2.5</version>
    </dependency>
</dependencies>

It uses a WildFly Swarm "bill of materials" to pull in all the dependencies. Only the specific dependencies needed for the build are specified in <dependencies>. These are then packaged in the "fat jar". WildFly Swarm Maven plugin is used to package and run the application:

<plugin>
    <groupId>org.wildfly.swarm</groupId>
    <artifactId>wildfly-swarm-plugin</artifactId>
    <version>${version.wildfly-swarm}</version>
    <executions>
        <execution>
            <goals>
                <goal>package</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <environment>
            <COUCHBASE_URI>${COUCHBASE_URI}</COUCHBASE_URI>
        </environment>
    </configuration>
</plugin>

COUCHBASE_URI is used to read the host of where Couchbase database server is running.

Run Couchbase Server

Run the Couchbase server using Docker for Mac:

docker run -d --name db -p 8091-8093:8091-8093 -p 11210:11210 arungupta/couchbase

The arungupta/couchbase is built upon the standard Couchbase image and uses Couchbase REST API to configure the server. Wait for a couple of minutes for the sample bucket to be populated with the JSON documents. Invoke the Couchbase CLI tool cbq create a primary index on the sample bucket:

docker run -it --link db:db arungupta/couchbase cbq -u Administrator -p password -engine http://db:8093 -s "create primary index \`travel-sample-primary-index\` on \`travel-sample\`;"

This will show the output as:

Connected to : http://db:8093/. Type Ctrl-D or \QUIT to exit.

Path to history file for the shell : /root/.cbq_history 
{
    "requestID": "d0b2e4dd-b702-49e2-971c-a4c640ddb498",
    "signature": null,
    "results": [
    ],
    "status": "success",
    "metrics": {
        "elapsedTime": "3.154540272s",
        "executionTime": "3.154493281s",
        "resultCount": 0,
        "resultSize": 0
    }
}

This output shows that result of creating index was successful. One of the advantages of running Docker for Mac is that all the containers are accessible at localhost. This means Couchbase Web Console can be accessed at localhost:8091. couchbase-web-console-docker-mac-wildfly-swarm-microsoervice

This screen ensures that Couchbase is configured  correctly.

Run WildFly Swarm Microservice

Package and run the self-contained microservice as:

mvn wildfly-swarm:run

If Couchbase is running on a different host, then the command will change to:

mvn -DCOUCHBASE_URI=<IP> wildfly-swarm:run

It shows the output as:

[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building nosql-microservices 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 

. . . 

2016-06-27 22:21:47,170 WARN  [org.jboss.as.dependency.private] (MSC service thread 1-6) WFLYSRV0018: Deployment "deployment.nosql-microservices.war" is using a private module ("org.jboss.jts:main") which may be changed or removed in future versions without notice.
2016-06-27 22:21:47,203 INFO  [org.jboss.weld.deployer] (MSC service thread 1-1) WFLYWELD0003: Processing weld deployment nosql-microservices.war
2016-06-27 22:21:47,542 INFO  [org.hibernate.validator.internal.util.Version] (MSC service thread 1-1) HV000001: Hibernate Validator 5.2.3.Final
2016-06-27 22:21:47,600 INFO  [org.jboss.as.ejb3.deployment] (MSC service thread 1-1) WFLYEJB0473: JNDI bindings for session bean named 'Database' in deployment unit 'deployment "nosql-microservices.war"' are as follows:

 java:global/nosql-microservices/Database!com.couchbase.wildfly.swarm.Database
 java:app/nosql-microservices/Database!com.couchbase.wildfly.swarm.Database
 java:module/Database!com.couchbase.wildfly.swarm.Database
 java:global/nosql-microservices/Database
 java:app/nosql-microservices/Database
 java:module/Database

2016-06-27 22:21:47,731 INFO  [org.jboss.weld.deployer] (MSC service thread 1-3) WFLYWELD0006: Starting Services for CDI deployment: nosql-microservices.war
2016-06-27 22:21:47,758 INFO  [org.jboss.weld.Version] (MSC service thread 1-3) WELD-000900: 2.3.2 (Final)
2016-06-27 22:21:47,780 INFO  [org.wildfly.extension.undertow] (MSC service thread 1-1) WFLYUT0018: Host default-host starting
2016-06-27 22:21:47,788 INFO  [org.jboss.weld.deployer] (MSC service thread 1-8) WFLYWELD0009: Starting weld service for deployment nosql-microservices.war
2016-06-27 22:21:48,180 INFO  [stdout] (ServerService Thread Pool -- 10) Couchbase endpoint: 
2016-06-27 22:21:48,275 INFO  [com.couchbase.client.core.CouchbaseCore] (ServerService Thread Pool -- 10) CouchbaseEnvironment: {sslEnabled=false, sslKeystoreFile='null', sslKeystorePassword='null', queryEnabled=false, queryPort=8093, bootstrapHttpEnabled=true, bootstrapCarrierEnabled=true, bootstrapHttpDirectPort=8091, bootstrapHttpSslPort=18091, bootstrapCarrierDirectPort=11210, bootstrapCarrierSslPort=11207, ioPoolSize=8, computationPoolSize=8, responseBufferSize=16384, requestBufferSize=16384, kvServiceEndpoints=1, viewServiceEndpoints=1, queryServiceEndpoints=1, searchServiceEndpoints=1, ioPool=NioEventLoopGroup, coreScheduler=CoreScheduler, eventBus=DefaultEventBus, packageNameAndVersion=couchbase-jvm-core/1.2.5 (git: 1.2.5), dcpEnabled=false, retryStrategy=BestEffort, maxRequestLifetime=75000, retryDelay=ExponentialDelay{growBy 1.0 MICROSECONDS, powers of 2; lower=100, upper=100000}, reconnectDelay=ExponentialDelay{growBy 1.0 MILLISECONDS, powers of 2; lower=32, upper=4096}, observeIntervalDelay=ExponentialDelay{growBy 1.0 MICROSECONDS, powers of 2; lower=10, upper=100000}, keepAliveInterval=30000, autoreleaseAfter=2000, bufferPoolingEnabled=true, tcpNodelayEnabled=true, mutationTokensEnabled=false, socketConnectTimeout=1000, dcpConnectionBufferSize=20971520, dcpConnectionBufferAckThreshold=0.2, queryTimeout=75000, viewTimeout=75000, kvTimeout=2500, connectTimeout=5000, disconnectTimeout=25000, dnsSrvEnabled=false}
2016-06-27 22:21:48,829 INFO  [com.couchbase.client.core.node.Node] (cb-io-1-1) Connected to Node localhost
2016-06-27 22:21:49,035 INFO  [com.couchbase.client.core.config.ConfigurationProvider] (cb-computations-1) Opened bucket travel-sample
2016-06-27 22:21:49,415 INFO  [org.jboss.resteasy.resteasy_jaxrs.i18n] (ServerService Thread Pool -- 10) RESTEASY002225: Deploying javax.ws.rs.core.Application: class com.couchbase.wildfly.swarm.MyApplication
2016-06-27 22:21:49,438 INFO  [org.wildfly.extension.undertow] (ServerService Thread Pool -- 10) WFLYUT0021: Registered web context: /
2016-06-27 22:21:49,457 INFO  [org.jboss.as.server] (main) WFLYSRV0010: Deployed "nosql-microservices.war" (runtime-name : "nosql-microservices.war")

Now the application can be accessed as:

curl http://localhost:8080/webresources/airline

And a formatted output looks like:

[
  {
    "travel-sample": {
      "country": "United States",
      "iata": "Q5",
      "callsign": "MILE-AIR",
      "name": "40-Mile Air",
      "icao": "MLA",
      "id": 10,
      "type": "airline"
    }
  },

  . . .

  {
    "travel-sample": {
      "country": "France",
      "iata": "A5",
      "callsign": "AIRLINAIR",
      "name": "Airlinair",
      "icao": "RLA",
      "id": 1203,
      "type": "airline"
    }
  }
]

So you built a simple microservice using WildFly Swarm accessing a Couchbase database running as a Docker container. Now, ideally this WildFly Swarm service should be packaged as a Docker image and then that Docker image would serve as the service. A Maven profile with the name docker is already added to pom.xml but issue #3 is making that scenario fail.

Is iPaaS solving the right problems? Not knowing the fundamental difference between iPaaS and iPaaS+ could cost you down the road. Brought to you in partnership with Liaison Technologies.

Topics:
microservices ,java ,couchbase ,nosql ,docker ,wildfly swarm

Published at DZone with permission of Arun Gupta, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}