This blog shows you how you can use Payara Micro to build a Java EE based microservice. It will leverage the following services from the Oracle Cloud (PaaS) stack


  • Developer Cloud service: to host the code (Git repo), provide Continuous Integration & Continuous Deployment capabilities (thanks to its integration with other Oracle PaaS services)
  • Application Container Cloud service: scalable aPaaS for running our Java EE microservice





Payara Micro?

Payara Micro is a Java EE based solution for building microservice style applications. Let’s expand on this a little bit


  • Java EE: Payara Micro supports the Java EE Web Profile standard along with additional support for other specifications which are not a part of the Web Profile (e.g. Batch, Concurrency Utilities etc.)
  • It’s a library: Available as a JAR file which encapsulates all these features


Development model

Payara Micro offers you the choice of multiple development styles…


  • WAR: package your Java EE application a WAR file and launch it with Payara Micro using java –jar payara-micro-<version>.jar --deploy mystocks.war
  • Embedded mode: because it’s a library, it can be embedded within your Java applications using its APIs
  • Uber JAR: Use the Payara Micro Maven support along with the exec plugin to package your WAR along with the Payara Micro library as a fat JAR


We will use the fat JAR technique in the sample application presented in the blog




Some of the potential benefits are as follows


  • Microservices friendly: gives you the power of Java EE as a library, which can be easily used within applications, packaged in flexible manner (WAR + JAR or just a fat JAR) and run in multiple environments such as PaaS , container based platforms
  • Leverage Java EE skill set: continue using your expertise on Java EE specifications like JAX-RS, JPA, EJB, CDI etc.


About the sample application


It is a vanilla Java EE application which uses the following APIs – JAX-RS, EJB, CDI and WebSocket. It helps keep track of stock prices of NYSE scrips.


  • Users can check the stock price of a scrip (listed on NASDAQ) using a simple REST interface
  • Real time price tracking is also available – but this is only available for Oracle (ORCL)


Here is a high level diagram and some background context


  • an EJB scheduler fetches (ORCL) periodically fetches stock price, fires CDI events which are recevied by the WebSocket component (marked as a CDI event observer) and connected clients are updated with the latest price
  • the JAX-RS REST endpoint is used to fetch price for any stock on demand - this is a typical request-response based HTTP interaction as opposed to the bi-directional, full-duplex WebSocket interaction







Let's briefly look at the relevant portions of the code (import statements omitted for brevity)


public class RealTimeStockTicker {

    //stores Session (s) a.k.a connected clients
    private static final List<Session> CLIENTS = new ArrayList<>();

     * Connection callback method. Stores connected client info
     * @param s WebSocket session
    public void open(Session s) {
        Logger.getLogger(RealTimeStockTicker.class.getName()).log(Level.INFO, "Client connected -- {0}", s.getId());

     * pushes stock prices asynchronously to ALL connected clients
     * @param tickTock the stock price
    public void broadcast(@Observes @StockDataEventQualifier String tickTock) {
        Logger.getLogger(RealTimeStockTicker.class.getName()).log(Level.INFO, "Event for Price {0}", tickTock);
        for (final Session s : CLIENTS) {
            if (s != null && s.isOpen()) {
                 * Asynchronous push
                s.getAsyncRemote().sendText(tickTock, new SendHandler() {
                    public void onResult(SendResult result) {
                        if (result.isOK()) {
                            Logger.getLogger(RealTimeStockTicker.class.getName()).log(Level.INFO, "Price sent to client {0}", s.getId());
                        } else {
                            Logger.getLogger(RealTimeStockTicker.class.getName()).log(Level.SEVERE, "Could not send price update to client " + s.getId(),



     * Disconnection callback. Removes client (Session object) from internal
     * data store
     * @param s WebSocket session
    public void close(Session s) {
        Logger.getLogger(RealTimeStockTicker.class.getName()).log(Level.INFO, "Client discconnected -- {0}", s.getId());



 * Custom CDI qualifier to stamp CDI stock price CDI events
public @interface StockDataEventQualifier {


 * Periodically polls the Google Finance REST endpoint using the JAX-RS client
 * API to pull stock prices and pushes them to connected WebSocket clients using
 * CDI events
public class StockPriceScheduler {

    private TimerService ts;
    private Timer timer;

     * Sets up the EJB timer (polling job)
    public void init() {
         * fires 5 secs after creation
         * interval = 5 secs
         * non-persistent
         * no-additional (custom) info
        timer = ts.createIntervalTimer(5000, 5000, new TimerConfig(null, false)); //trigger every 5 seconds
        Logger.getLogger(StockPriceScheduler.class.getName()).log(Level.INFO, "Timer initiated");

    private Event<String> msgEvent;

     * Implements the logic. Invoked by the container as per scheduled
     * @param timer the EJB Timer object
    public void timeout(Timer timer) {
        Logger.getLogger(StockPriceScheduler.class.getName()).log(Level.INFO, "Timer fired at {0}", new Date());
         * Invoked asynchronously
        Future<String> tickFuture = ClientBuilder.newClient().

         * Extracting result immediately with a timeout (3 seconds) limit. This
         * is a workaround since we cannot impose timeouts for synchronous
         * invocations
        String tick = null;
        try {
            tick = tickFuture.get(3, TimeUnit.SECONDS);
        } catch (InterruptedException | ExecutionException | TimeoutException ex) {
            Logger.getLogger(StockPriceScheduler.class.getName()).log(Level.INFO, "GET timed out. Next iteration due on - {0}", timer.getNextTimeout());
        if (tick != null) {
             * cleaning the JSON payload
            tick = tick.replace("// [", "");
            tick = tick.replace("]", "");



     * purges the timer
    public void close() {
        Logger.getLogger(StockPriceScheduler.class.getName()).log(Level.INFO, "Application shutting down. Timer will be purged");


 * JAX-RS configuration class
public class RESTConfig extends Application{


 * A simple utility class which leverages the JSON Processing (JSON-P) API to filter the JSON 
 * payload obtained from the Google Finance REST endpoint and returns useful data in a custom format
public class StockDataParser {
    public static String parse(String data){
        JsonReader reader = Json.createReader(new StringReader(data));
                JsonObject priceJsonObj = reader.readObject();
                String name = priceJsonObj.getJsonString("t").getString();
                String price = priceJsonObj.getJsonString("l_cur").getString();
                String time = priceJsonObj.getJsonString("lt_dts").getString();

        return (String.format("Price for %s on %s = %s USD", name, time, price));


A note on packaging

A mentioned earlier, from a development perspective, it is a typical WAR based Java EE application which is packaged as a fat JAR along with the Payara Micro container


Notice how the container is being packaged with the application rather than the application being deployed into a container

The Java EE APIs are only needed for compilation (scope = provided) since they are present in the Payara Micro library





Using the Maven plugin to produce a fat JAR





Setting up Continuous Integration & Deployment

The below sections deal with the configurations to made within Oracle Developer Cloud service


Project & code repository creation

Please refer to the Project & code repository creation section in the Tracking JUnit test results in Developer Cloud service blog or check the product documentation for more details


Configure source code in Git repository

Push the project from your local system to your Developer Cloud Git repo you just created. We will do this via command line and all you need is Git client installed on your local machine. You can use Git or any other tool of your choice


cd <project_folder> 
git init  
git remote add origin <developer_cloud_git_repo>  
git add .  
git commit -m "first commit"  
git push -u origin master  //Please enter the password for your Oracle Developer Cloud account when prompted


Configure build


Create a New Job



Select JDK




Continuous Integration (CI)


Choose Git repository




Set build trigger - this build job will be triggered in response to updated within the Git repository (e.g. via git push)



Add build steps


  • A Maven Build step – to produce the WAR and the fat JAR
  • An Execute Shell step – package up the application JAR along with the required deployment descriptor (manifest.json required by Application Container cloud)





Here is the command for your reference


zip -j target/mystocks.jar manifest.json


The manifest.json is as follows


    "runtime": {
        "majorVersion": "8"
    "command": "java -jar mystocks.jar --port $PORT --noCluster",
    "release": {
        "build": "23022017.1202",
        "commit": "007",
        "version": "0.0.1"
    "notes": "Java EE on ACC with Payara Micro"


Activate a post build action to archive deployable zip file




Execute Build

Before configuring deployment, we need to trigger the build in order to produce the artifacts which can be referenced by the deployment configuration




After the build is complete, you can

  • Check the build logs
  • Confirm archived artifacts









Continuous Deployment (CD) to Application Container Cloud


Create a New Confguration for deployment




  • Enter the required details and configure the Deployment Target
  • Configure the Application Container Cloud instance
  • Configure Automatic deployment option on the final confirmation page


You’ll end up with the below configuration



Confirmation screen




Check your application in Application Container Cloud




Test the CI/CD flow


Make some code changes and push them to the Developer Cloud service Git repo. This should


  • Automatically trigger the build, which once successful will
  • Automatically trigger the deployment process, and
  • Redeploy the new application version to Application Container Cloud


Test the application



I would recommend using the client which can be installed into Chrome browser as a plugin – Simple WebSocket Client


That's all for this blog post..


**The views expressed in this post are my own and do not necessarily reflect the views of Oracle