Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

Saturday, March 7, 2020

Java EE Micro Services Using Thorntail



Context


The Software Development world is growing every minute and as it evolves the systems are becoming more and more normalised and refined into Micro Services, this has also inspired the likes of Spring Boot and many other frameworks.

I have realised that when it comes to enterprise software most Java developers are either using Spring or  Java EE / Jakarta EE. For the who are using Spring we have Spring Boot to help us with fast project kick off and development. More to that some use it for the Micro Service pattern or methodology. What happens when you you as a developer want to use JEE? Spring Boot may not be what you are looking for and perhaps you are looking for something along the lines of WildFly.

We will have a look at a baby project along these lines, a new sidecar project supporting WildFly to enable deconstructing the application server as is and pasting just enough of it back together with your application to create a self-contained executable jar. This project is formerly known as "Wildly Swarm" and now known, as Thorntail. I mentioned Spring Boot and now you can imagine where this is going. 



1. Assumptions


Now remember that we spoke about Micro Services so the best use case for this article would be something along the lines of some sort of API. In this case we will create a RESTFul API. We assume that you have an understanding of the following tech / tools.

  • WildFly AS
  • Java 8 
  • Maven
  • JAX-RS


2. Project Setup Using Maven


Let's set up the project using maven, as our automated build tool and also  grab some wildly fractions (dependencies) we need. Worry not we will cover a little bit about fractions as we go. We will start off with some basic properties settings. These can be anything you prefer so feel free to change these properties up. Just the important one is that since this will be a web application we want to package it as a ".war" file, so keep that one as is in the example.


<groupId>za.co.anylytical.showcase</groupId>
<artifactId>thorntail-rest-services</artifactId>
<name>Thorntail REST API Showcase</name>
<version>1.0.0-SNAPSHOT</version>
<packaging>war</packaging>


We have more of our properties, mainly for our versions in this case. We are also now telling maven that our Java version will be 8. At the moment [07-03-2020] the latest version of Thorntail is "2.6.0.Final". So we will be using the latest version. As of Jboss 7.x we no longer really need the ".web.xml" so the tag  <failOnMissingWebXml>  also is there to make sure that we don't get failures as we will not be using the ".web.xml" file in this example. 


<properties>
    <version.thorntail>2.6.0.Final</version.thorntail>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <failOnMissingWebXml>false</failOnMissingWebXml>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>


Maven being a very good and strong dependency management tool, it also has a very cool feature using BOM (Bill Of Materials) which pretty much allows us to access a set collection of various dependencies and hand pick the ones we need for our app. So in this case we will import the Thorntail specific BOM and then choose the dependencies we need for our JAX-RS API.


<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>io.thorntail</groupId>
            <artifactId>bom-all</artifactId>
            <version>${version.thorntail}</version>
            <scope>import</scope>
            <type>pom</type>
        </dependency>
    </dependencies>
</dependencyManagement>


There's a Thorntail Maven Plugin maven plugin available that can help us work on packing our application much easier. Let's set that up next.


<build>
    <finalName>thorntail-api</finalName>
    <plugins>
        <plugin>
            <groupId>io.thorntail</groupId>
            <artifactId>thorntail-maven-plugin</artifactId>
            <version>${version.thorntail}</version>
            <executions>
                <execution>
                    <goals>
                        <goal>package</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>


Earlier in the article we mentioned "fractions". This is a concept based on Thorntail, a "fraction" can include all or none of the WildFly components. Ultimately a fraction contributes configuration or capabilities to a runtime system. This is simply because we are loading in smaller pieces that we need, thus, Fractions. Looking at our current topic, (Thorntail) these fractions are in the form of dependencies. Let's go shopping for some ingredients that make up our REST Service API.


<dependencies>
    <dependency>
        <groupId>io.thorntail</groupId>
        <artifactId>swagger</artifactId>
    </dependency>
    <dependency>
        <groupId>io.thorntail</groupId>
        <artifactId>jaxrs</artifactId>
    </dependency>
    <dependency>
        <groupId>io.thorntail</groupId>
        <artifactId>swagger-webapp</artifactId>
    </dependency>
</dependencies>


That's it for the project set up with maven. As you can see, the fractions we are pulling in are very basic and specific, not need for the entire heavy WildFly. We have hand picked only Swaggertogether with its own web application piece, for the Web UI and finally the core piece we need for our REST API, JAX-RSAt this point we are now ready for some code implementation. 



3. Java REST Resource Implementation Using JAX-RS API


Let's now create a Rest resource implementation using Java and JAX-RS API. 

package za.co.anylytical.showcase.rest;
 
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
 
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
 
@Path("/text")
@Api( value = "/text", tags = "Text API")
@Produces( MediaType.APPLICATION_JSON)
public class SampleResource {

    @GET
    @ApiOperation(
            value = "Gets a text message",
            notes = "Returns the message as HTTP Resposne",
            response = Response.class)
    @Produces( MediaType.APPLICATION_JSON)
    public Response get() {
        return Response.status(Response.Status.OK)
                .entity( "Hey, there, you requested for text?")
                .build();
    }
}


According to the JAX-RS standards, the next step is to include a class extending javax.ws.rs.core.Application to define the rest @ApplicationPath and also register our rest resources. 


package za.co.anylytical.showcase.config;
 
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
 
@ApplicationPath("/")
public class ResourceConfig extends Application {
 
}


We will be adding the second last piece to our implementation before we can test it out. We will include a class implementing the ContainerResponseFilter interface, which works like a filter for the ContainerResponse extension point on the server side, in order to filter the response message after the invocation has executed:


package za.co.anylytical.showcase.filters;
 
import java.io.IOException;
 
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;
 
 
@Provider
public class CORSFilter implements ContainerResponseFilter {
 
    @Override
    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
        responseContext.getHeaders().add("Access-Control-Allow-Origin", "*");
        responseContext.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        responseContext.getHeaders().add("Access-Control-Max-Age", "-1");
        responseContext.getHeaders().add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    }
 
}


Let's configure our Wildfly port and context-root just because port 8080 is so over rated, plus we will be looking at an alternative to setting up, similar to the spring boot way with the application.properties or .yml file. In your source code resources folder, add a new file project-defaults.yml

Add the following piece of yml in your file. 


thorntail:
  http:
    port: 8881
  context:
    path: that-service


We are now all set, it's time to build our app and then try to run it and see. Let's talk to maven to see if it can help us bootstrap the rest service.


4. Run The Project Using Maven


Build the app. Make sure you are in the root project folder where you can run your pom file.

$ mvn clean install


Run the application, remember there's no standalone application server. So we are actually going to just execute our ".jar" file as mentioned in the beginning of this article. Let's get on with it then. 

$ java -jar target/thorntail-api-thorntail.jar

NB: At this point it will boot up very quick and you should see something along these lines. Just click the image below to enlarge it.


5. Swagger Checkout


So let's check the swagger out for some basic testing and checks. Now head over to the link http://localhost:8881/swagger-uiand you should see a swagger screen with the default API loaded. 
NB: A quick look at the default swagger home page once you launch it. Just click the image below to enlarge it.


You probably want to check your API, so while you are on that swagger screen just insert the following URL into the top text box. http://localhost:8881/that-service/swagger.json and then press enter. This will load your API in the web app and you should be able to see your API as shown in the image below.
NB: Web view of what it looks like once you have pointed it to your API. Just click the image below to enlarge it.


Conclusion


So there you go. A standalone service using Wildfly and some Java EE, similar way you would have it using Spring Boot. We have learned how to build one and the nice part was that fractions section which allowed us to hand pick which bits of wildfly we would want. Sometimes working with a full fledged application server is necessarily bloated and heavy. Incase you wondered how you can work with Java EE in Micro Service then this is another way you can do it.  
Note: Postman example of our API test, incase you were wondering. 



You may also find the GitHub Code Base incase you want to double check our exercise. I hope this has been helpful, leave comments in the section below.