The JavaEE Message of the Day App is a Gluon code sample. Refer to the Gluon website for a full list of Gluon code samples.

In this tutorial, we’ll explain how to create an app that receives messages from a web application using a Java EE container and Gluon CloudLink, and deploy it on Android and iOS devices. Before you start, be sure that you have checked the list of prerequisites, and you have installed the Gluon plugin for your IDE. Otherwise follow these instructions.

Note: This tutorial will use the plugin for NetBeans, but it works as well on IntelliJ and Eclipse.

Code: The code for this project can be found in the samples repository at GitHub. The sample is located under the directory javaeemotd. The reader can clone this repository or create the entire project from scratch, based on the following steps.

Creating the client project

Let’s create a new project using the Gluon plugin. In NetBeans, click File→New Project…​ and select Gluon on the left. Select Gluon Mobile - Glisten-Afterburner Project from the list of available Projects:

Plugins Window

Add a proper name to the application (client), find a proper location, add the package name and change the main class name if required.

Name and Location

Press Next and change the name of the primary view to Main.

Name of Views

Press Finish and the project will be created and opened.

Project

Modifying the Project

For this sample we don’t need the secondary view, so we can just leave it there for a possible future use, or we can get rid of the related files (SecondaryPresenter.java, secondary.css, secondary.properties and secondary.fxml), and remove the AppView instance from the AppViewManager.

The FXML files can be edited with Scene Builder. Since the version 8.3.0, the Gluon Charm dependencies are included, and you can easily design Gluon Mobile views.

We’ll modify the default main.fxml file, just to leave a Label for the incoming message.

fxml file

and update its presenter:

MainPresenter.java
public class MainPresenter extends GluonPresenter<MessageOfTheDay> {

    @FXML
    private View main;

    @FXML
    private Label lblMotd;

    @FXML
    private ResourceBundle resources;

    public void initialize() {
        main.showingProperty().addListener((obs, oldValue, newValue) -> {
            if (newValue) {
                AppBar appBar = getApp().getAppBar();
                appBar.setNavIcon(MaterialDesignIcon.MENU.button(e ->
                        getApp().getDrawer().open()));
                appBar.setTitleText(resources.getString("message.text"));
            }
        });
    }
}

and css file:

main.css
.label {
    -fx-text-fill: #666666;
    -fx-font-size: 1.2em;
}

.icon > .label {
    -fx-text-fill: -primary-swatch-700;
    -fx-font-size: 3em;
}

The service

We’ll add a service that takes care of retrieving data from Gluon CloudLink.

Gluon Dashboard

First of all, you need a valid subscription to Gluon CloudLink. If you don’t have it yet, get it from here (there is also a 30-day free trial). Sign up and get a valid account on Gluon CloudLink and then access the Gluon CloudLink Dashboard at https://gluon.io. Sign in using your Gluon account credentials (those provided when creating the account).

Dashboard

Go to the Credentials link, Client tab, and you will find a pair of key/secret tokens. Click on the download button to download the file gluoncloudlink_config.json, and then store it under your project src/main/resources/ folder.

Configuration File

The content of the file is a JSON object with the key and secret that will grant access to Gluon CloudLink:

src/main/resources/gluoncloudlink_config.json
{
  "gluonCredentials": {
    "applicationKey" : "f88XXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
    "applicationSecret": "7fbXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
  }
}

Service class

We can now build a new DataClient, which is the access point to the Data Storage service of Gluon CloudLink. We add a method that we annotate with @PostContruct. This method will be called by the Afterburner framework, immediately after the class has been constructed.

Service.java
public class Service {

    private DataClient dataClient;

    @PostConstruct
    public void postConstruct() {
        dataClient = DataClientBuilder.create()
                .operationMode(OperationMode.CLOUD_FIRST)
                .build();
    }
}

Based on the DataClient instance, we can retrieve a GluonObservableObject, using the method DataClient.createObjectDataReader(). We define an identifier for this object and the type of class that we want to retrieve, in this case String.class.

Service.java
public class Service {

    private static final String MOTD = "javaee-motd-v1";

    public GluonObservableObject<String> retrieveMOTD() {
        GluonObservableObject<String> motd = DataProvider
                .retrieveObject(dataClient.createObjectDataReader(MOTD, String.class, SyncFlag.OBJECT_READ_THROUGH));
        motd.initializedProperty().addListener((obs, ov, nv) -> {
            if (nv && motd.get() == null) {
                motd.set("This is the first Message of the Day!");
            }
        });
        return motd;
    }
}

Injecting the Service

Back to MainPresenter, we can inject a singleton instance of the Service by using the @Inject annotation. We then call service.retrieveMOTD() to retrieve the object from Gluon CloudLink, binding the returned observable object to the text property of the label.

MainPresenter.java
public class MainPresenter extends GluonPresenter<MessageOfTheDay> {

    @Inject
    private Service service;

    public void initialize() {
        ...
        lblMotd.textProperty().bind(service.retrieveMOTD());
    }
}

Testing the Client

Time to test the client application on Desktop, before deploying to mobile.

Client App

Since we don’t have the web application to send messages yet, there is no object available and we return the default message.

If everything works as expected, run Tasks→android→androidInstall to deploy on Android, or Tasks→launch→launchIOSDevice to deploy on iOS.

The server project

To create the web application with Java EE we first create a regular gradle project with NetBeans:

Server gradle project

Name the project server and specify com.gluonhq.javaee.motd.server.MotdApplication as the main class:

Name and location

Now, we configure the gradle project which the required dependencies:

build.gradle
buildscript {
    repositories {
        jcenter()
    }
}

apply plugin: 'war'

repositories {
    jcenter()
}

dependencies {
    // Java EE api
    providedCompile 'javax:javaee-api:7.0'

    // Gluon CloudLink Enterprise SDK
    compile 'com.gluonhq:cloudlink-enterprise-sdk-javaee:1.2.0'
    runtime 'org.eclipse:yasson:1.0'

    // jersey framework
    providedCompile 'org.glassfish.jersey.containers:jersey-container-servlet:2.22.2'
    compile 'org.glassfish.jersey.ext:jersey-mvc:2.22.2'
    compile 'org.glassfish.jersey.ext:jersey-mvc-freemarker:2.22.2'

    // Webjars
    compile "org.webjars:bootstrap:3.3.7-1"
    compile "org.webjars:jquery:3.1.1"
}

// omit the version from the war file name
war {
    baseName = 'motd-server'
    version = null
}

Application class

The server project will be a web application, so we configure a JAX-RS application that will server as the main endpoint:

MotdApplication.java
@ApplicationPath("/jaxrs")
public class MotdApplication extends ResourceConfig {

    public MotdApplication() {
        // scan com.gluonhq package for jax-rs classes
        packages(true, "com.gluonhq");

        // everything inside /webjars should not be handled by the jax-rs application
        property(ServletProperties.FILTER_STATIC_CONTENT_REGEX, "/webjars/.*");

        // use freemarker for web templating
        register(FreemarkerMvcFeature.class);
        property(FreemarkerMvcFeature.TEMPLATE_BASE_PATH, "freemarker");
    }
}

REST Services

To deal with the REST requests from the web application, we’ll add the FrontHandler class. It contains two methods, one for serving a web page and POST method to update the data object in Gluon CloudLink that stores the message of the day.

The FrontHandler will listen for requests made to the path named /front.

FrontHandler.java
@Path("front")
public class FrontHandler {

    @GET
    @Produces(MediaType.TEXT_HTML + "; charset=UTF-8")
    @Template(name = "/index.ftl")
    public String get() {
        return "";
    }

    @POST
    @Produces(MediaType.TEXT_PLAIN + "; charset=UTF-8")
    public Response set(@FormParam("motd") String motd) {
        return Response.ok("").build();
    }
}

Now to implement those methods, we create a service class that connects to Gluon CloudLink, to get or set the object.

The GluonService

To pull or push data from CloudLink we’ll use the Gluon CloudLink Enterprise SDK. This client API is a Java wrapper that calls into the Gluon CloudLink Enterprise SDK REST endpoints.

A valid Server Key is required for authenticating each request. From the Gluon Dashboard, navigate to the Credentials page and select the Server tab to access the Server Key for your application:

Server Key

We can now create the GluonService class that will take care of the logic of retrieving and updating the message of the day object in Gluon CloudLink. The class will contain two methods, one for retrieving the current value for the object with identifier javaee-motd-v1 and one for updating the value. If the object did not yet exist, it will be initialized with an default message of the day.

GluonService.java
@ApplicationScoped
public class GluonService {

    private static final String MOTD = "javaee-motd-v1";

    @Inject
    @CloudLinkConfig(serverKey = "MHwwDQXXXXXXXXXXX...")
    private CloudLinkClient gclClient;

    public String getMotd(String objectIdentifier) {
        String motd = gclClient.getObject(MOTD, String.class);

        if (motd == null) {
            // instantiate with initial motd
            motd = gclClient.addObject(MOTD, "Initial Message of the Day!");
        }

        return motd;
    }

    public void setMotd(String motd) {
        gclClient.updateObject(MOTD, motd);
    }
}

Now we can inject the service in our FrontHandler class and finish the implementation of both methods:

FrontHandler.java
@Path("front")
public class FrontHandler {

    @Inject
    private GluonService service;

    @GET
    @Produces(MediaType.TEXT_HTML + "; charset=UTF-8")
    @Template(name = "/index.ftl")
    public String get() {
        return service.getMotd();
    }

    @POST
    @Produces(MediaType.TEXT_PLAIN + "; charset=UTF-8")
    public Response set(@FormParam("motd") String motd) {
        service.setMotd(motd);
        return Response.ok(motd).build();
    }
}

Webpage

We’ll add a web page with a basic form where you can set a text message that will be used as the value for the message object in Gluon CloudLink. Whenever the message is being updated, all active clients will automatically receive the updated value.

We are using Freemarker as the template engine.

index.ftl
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" class="en">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <meta name="description" content="Gluon CloudLink demo for Java EE - Message of the Day">
        <meta name="title" content="Gluon Java EE MOTD">
        <title>Java EE Message of the Day</title>

        <link rel="stylesheet" type="text/css" href="/motd-server/webjars/bootstrap/3.3.7-1/css/bootstrap.min.css">
    </head>

    <body>
        <div class="container">
            <div id="body" class="row">
                <div class="page-header">
                    <h1>Message of the Day</h1>
                    <h4>An application demonstrating Gluon CloudLink and Java EE.</h4>
                </div>
                <div id="messages" class="row hide">
                    <div role="alert">
                        <button type="button" class="close" data-hide="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                        <div id="messages_content"></div>
                    </div>
                </div>
                <div class="row">
                    <form id="add-form" class="form-inline">
                        <div class="form-group">
                            <input type="text" class="form-control" placeholder="Type a message" value="${model}" name="motd" id="motd" style="width: 100%;"/>
                        </div>
                        <button type="button" class="btn btn-default" id="add-item">Update Message</button>
                    </form>
                </div>
            </div>
        </div>
        <script type="text/javascript" src="/webjars/jquery/3.1.1/jquery.min.js"></script>
        <script type="text/javascript" src="/webjars/bootstrap/3.3.7-1/js/bootstrap.min.js"></script>
        <script type="text/javascript">
            $(function() {
                $('#add-item').click(function(e) {
                    $.post("/motd-server/jaxrs/front", { motd: $("#motd").val()}, function(data) {
                        $('#messages_content').html('<h4>Message updated: ' + data + '</h4>');
                        $('#messages').children().first().addClass('alert alert-success alert-dismissable');
                        $('#messages').removeClass('hide').slideDown().show();

                        e.preventDefault();
                    });
                });
            });
        </script>
    </body>
</html>

Running the server application

Time for a test. We’ll use Payara Micro as our Java EE application container. You can download it from the Payara Micro website.

Run Tasks→build→war or ./gradlew war to build the web archive. Then run Payara Micro from the command line, passing the location of the war file as the archive to deploy:

java -jar payara-micro-4.1.2.172.jar --deploy build/libs/motd-server.war

You can now open a browser and navigate to http://localhost:8080/motd-server to verify that everything is in place:

webpage

The first time the text field will contain the initial value that was set in GluonService. We can update the value by chaning the message in the text field and clicking the Update Message button.

set value

We can verify that the value has been stored correctly by using the Object browser in the Gluon Dashboard. Navigate to the Objects tab in the Data Management page to see the latest value that has been assigned to the javaee-motd-v1 object.

set value

If we run the client application, the exact same message should appear there as well:

client app

If we set a new message in the web form, it will be immediately updated in the client application, all because of the JavaFX binding to the GluonObservableObject.

client app updated

Conclusion

During this tutorial we have accomplished several tasks:

  • We have created a client project that can be deployed on Desktop, Android and iOS, with a DataClient to retrieve the value of a single observable object from Gluon CloudLink.

  • We have created a web application using Java EE that, by using the Gluon CloudLink Enterprise SDK, can retrieve that same value and update it as well.

  • When the value is updated from the web application, the active client applications are updated instantly.

If you have made it this far, congratulations, we hope this sample and the documentation was helpful to you! In case you have any questions, your first stop should be the Gluon support page, where you can access the CloudLink latest documentation. Gluon also recommends the community to support each other over at the Gluon StackOverflow page. Finally, Gluon offers commercial support as well, to kick start your projects.