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, make sure to check the list of prerequisites for each platform, and you have installed the Gluon plugin for your IDE.
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:
Add a proper name to the application (client
), find a proper location, add the package name and change the main class name if required.
Press Next
and change the name of the primary view to Main
.
Press Finish
and the project will be created and opened.
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.
and update its presenter:
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:
.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).
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.
The content of the file is a JSON object with the key and secret that will grant access to Gluon CloudLink:
{
"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.
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
.
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.
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.
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:
Name the project server
and specify com.gluonhq.javaee.motd.server.MotdApplication
as the main class:
Now, we configure the gradle project which the required dependencies:
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:
@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
.
@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:
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.
@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:
@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.
<!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">×</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:
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.
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.
If we run the client application, the exact same message should appear there as well:
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
.
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.