Gluon CloudLink enables enterprise and mobile developers to easily connect their disparate services and applications together, enabling bi-directional communications between mobile apps, enterprise infrastructure, and cloud systems.

cloudlink and sdks

Gluon CloudLink is a Mobile Back-end as a Service (MBaaS) providing:

  • Data storage, synchronization (to the back-end or across devices) and connectors to other back-ends.

  • User management, including login methods for popular identity providers.

  • Usage analytics

  • Push notifications to Android and iOS devices.

2. Application Registration

The first step in enabling Gluon CloudLink in your application is to sign up for a Gluon CloudLink account. If you already have a Gluon CloudLink subscription you can safely skip this part. If not, go to the Gluon CloudLink Product page and choose a subscription that matches your needs. There is also an option to sign up for a 30-day trial account. Enter your billing information or login with your existing account when you have signed up for one of our other products before.

Once you are successfully signed up, a Gluon CloudLink application will be created for you automatically. You will also receive an email that contains a link to access the Gluon Dashboard.

2.1. Gluon Dashboard

The Gluon Dashboard is a web application from which you can configure and monitor your Gluon CloudLink application. Point your browser to https://gluon.io and sign in with the same account credentials that you used when subscribing for Gluon CloudLink at gluonhq.com.

login

Select any of the items from the menu on the left to begin configuring your Gluon Application.

Login method

2.2. Before you begin

The chapters that follow below will describe all the functional components that are provided by Gluon CloudLink. Each component talks about the required steps on how to set up, configure and use them from the perspective of your enterprise application as well as from the mobile client application. To be able to use Gluon CloudLink you will need to make sure everything is set up correctly.

2.2.1. Server Configuration

Communication between your enterprise application and Gluon CloudLink is done by using the designated Gluon CloudLink Enterprise REST endpoints. Each of these endpoints is described in the appropriate sections below. For your convenience, we also provide a Java Client that calls on these same endpoints. The Java Client currently has two implementations that you can choose from. The Java EE client is most suited when your enterprise application is running inside a Java EE application container. The Spring client is more suited for enterprise applications that are running inside the Spring framework.

JavaDocs for the Gluon CloudLink Enterprise SDK can be found at the following URL:

Content Encoding

All data that is written to Gluon CloudLink by using the enterprise REST endpoints, either directly or by use of the Java Client must be encoded in UTF-8. This is the only encoding that is supported by Gluon CloudLink. If your data you sent looks garbled, please verify that you correctly applied UTF-8 encoding.

Dependencies

The following maven dependencies should be added to your enterprise project to make use of the Gluon CloudLink Enterprise SDK. Note that the Eclipse Yasson dependency is only required when you are running inside a Java EE 7 container. Java EE 8 containers should automatically ship with an implementation of the JSON-Binding API.

Java EE
Maven
<dependencies>
    <dependency>
        <groupId>com.gluonhq</groupId>
        <artifactId>cloudlink-enterprise-sdk-javaee</artifactId>
        <version>1.2.1</version>
    </dependency>
    <!-- only required when running inside a Java EE 7 container -->
    <dependency>
        <groupId>org.eclipse</groupId>
        <artifactId>yasson</artifactId>
        <version>1.0</version>
        <scope>runtime</scope>
    </dependency>
</dependencies>
gradle
repositories {
    mavenCentral()
}

dependencies {
    compile 'com.gluonhq:cloudlink-enterprise-sdk-javaee:1.2.1'

    // only required when running inside a Java EE 7 container
    runtime 'org.eclipse:yasson:1.0'
}
Spring
Maven
<dependencies>
    <dependency>
        <groupId>com.gluonhq</groupId>
        <artifactId>cloudlink-enterprise-sdk-spring</artifactId>
        <version>1.2.1</version>
    </dependency>
</dependencies>
gradle
repositories {
    mavenCentral()
}

dependencies {
    compile 'com.gluonhq:cloudlink-enterprise-sdk-spring:1.2.1'
}
Authentication

The REST endpoints themselves require an HTTP Authorization header that is used to authenticate the requests to Gluon CloudLink. The value of the Authorization header is as follows:

Authorization: Gluon MHwwXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

The SERVER_KEY needs to be replaced with the actual server key of your Gluon CloudLink application and can be found in the Gluon Dashboard, in the Server tab of the Credentials section.

credentials server
JavaEE

When using the Java Client, authentication is done by providing the server key when you create an instance of the Java Client:

Manual instantiation
CloudLinkClientConfig config = new CloudLinkClientConig("MHwwXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
CloudLinkClient client = new CloudLinkClient(config);

Alternatively, when running inside a CDI aware environment, you can inject an instance of the JavaEE client as follows:

Using injection
@Inject
@CloudLinkConfig(serverKey = "MHwwXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
private CloudLinkClient client;
Spring

Authentication with the Spring Client is done in the same way as the JavaEE Client:

Manual instantiation
CloudLinkClientConfig config = new CloudLinkClientConig("MHwwXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
CloudLinkClient client = new CloudLinkClient(config);

When you are using Spring Boot, you can make use of autowiring to inject an instance of the Spring Client. An application property is then required that contains the server key of your Gluon CloudLink Application.

application.properties
gluon.cloudlink.serverKey=MHwwXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Using autowiring
private CloudLinkClient client;

@Autowired
public MyService(CloudLinkClient client) {
    this.client = client;
}

2.2.2. Client Configuration

The Gluon Mobile CloudLink Client is the component that is used for handling the communication between your Mobile Client application and Gluon CloudLink. It is automatically added as a dependency to the main Gluon Mobile artifact, but can also be added separately.

Gradle Configuration

Gluon Mobile projects use gradle as the build tool for building and provisioning a Gluon Mobile application. The gradle project makes use of the JavaFX Mobile plugin and the associated build.gradle file needs to be configured with the following dependencies and Charm Down configuration.

repositories {
    maven {
        url 'http://nexus.gluonhq.com/nexus/content/repositories/releases/'
    }
}

dependencies {
    compile 'com.gluonhq:charm:4.3.7'
}

jfxmobile {
    downConfig {
        plugins 'device', 'push-notifications', 'storage'
    }
}
Authentication

Gluon Mobile uses the application specific credentials to sign all requests that are made to Gluon CloudLink. This allows Gluon CloudLink to know on behalf of which application the request is initiated.

To apply the client credentials to your Gluon Mobile project, create a JSON configuration file called gluoncloudlink_config.json and save it under the directory src/main/resources. This file will automatically be picked up by Gluon Mobile when needed. Insert the content below, making sure that you replace the values for the applicationKey and applicationSecret with the correct credentials for your application:

{
  "gluonCredentials": {
    "applicationKey": "b916XXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
    "applicationSecret": "9c11XXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
  }
}

From the Gluon Dashboard, select the Credentials item from the menu on the left. You will find the key and secret tokens of your Gluon CloudLink application inside the Client tab. You can either manually copy and paste them in the configuration file or you can directly download the configuration file by clicking the download button.

credentials client

3. Data Storage

Applications often use data that needs to be stored. Some data is only relevant to a specific instance of the application (i.e. local settings), other data is relevant to all instances of the application (i.e. chat data) and some data is relevant to some instances (i.e. user preferences for a user who has a number of devices).

Gluon CloudLink Client is the component that manages data on the client. It provides an API that allows users to store and synchronize data and provides a number of options for developers to choose from for each data entity:

  • should the data be stored on the device only?

  • should the data be stored in Gluon CloudLink?

  • should changes to data on the device propagate to Gluon CloudLink?

  • in case the data in Gluon CloudLink changes, does the local device copy needs to be synchronized immediately?

Gluon CloudLink Client communicates via an efficient protocol with Gluon CloudLink to achieve the different goals. Gluon CloudLink provides a scalable and persistent data store that is used to store data and to update clients when data changes.

Communication between your Gluon Mobile application and Gluon CloudLink works in two directions:

  • your mobile data is stored in the cloud when you want to, and

  • your mobile data is updated on the device whenever it is updated in the cloud.

In addition, Gluon CloudLink provides the ability to link your Gluon Mobile application with another back-end or cloud infrastructure by configuring one or more Connectors.

Gluon CloudLink makes sure your data is consistent across the different devices. Depending on your preferences, changes on one device propagate immediately to other devices. Or they might only be stored in Gluon CloudLink and the devices will manually request the latest version whenever they want.

3.1.1. DataClient

The DataClient class is the access point to the Data Storage. You can get a reference to a DataClient instance by using the DataClientBuilder:

DataClient dataClient = DataClientBuilder.create().build();
Operation Mode

When working with the DataClient, there are currently three operation modes you can choose from:

  • CLOUD_ONLY: data will only be persisted on and retrieved from the Gluon CloudLink service

  • LOCAL_ONLY: data will only be persisted on and retrieved from the local file system of the device where the application is running on

  • CLOUD_FIRST: data will be persisted on and retrieved from the Gluon CloudLink service as the primary data source, but a local copy will be kept in sync

The default operation mode is CLOUD_FIRST, but can be explicitly specified when creating the DataClient instance:

// specify LOCAL_ONLY operation mode
DataClient dataClient = DataClientBuilder.create()
        .operationMode(OperationMode.LOCAL_ONLY)
        .build();
Authentication

You can configure the DataClient to link data with an authenticated user. The following authentication methods are currently available:

  • Facebook: authenticate users with Facebook Login

  • GitHub: authenticate users with GitHub

  • Google: authenticate users with Google Sign-In

  • Twitter: authenticate users with Twitter

  • Email and Password: authenticate users by letting them sign up and sign in with their personally chosen email address and password

See the documentation on User Management to read more about configuring user authentication.

To enable user authentication on the client, you need to provide a UserClient instance when building the DataClient. The provided UserClient will ensure that an authenticated user is present when the DataClient tries to access underlying data. Authentication is done by presenting the user with an authentication view from which one of the configured login methods can be chosen.

// enable user authentication
UserClient authenticationClient = new UserClient();
DataClient dataClient = DataClientBuilder.create()
        .authenticateWith(authenticationClient)
        .build();

// the next statement will trigger the authentication view
GluonObservableList<Note> notes = DataProvider.retrieveList(dataClient.createListDataReader("notes", Note.class));

3.1.2. Data Storage

Once you have a DataClient reference, you can start storing and retrieving data. There are two different types of data that can be managed in Gluon CloudLink:

  • single objects, and

  • lists of objects

Because these objects and lists are maintained remotely, we will call them remote entities. Every remote entity is identified by a unique string identifier.

Retrieving lists

For example, retrieving a remote list with the identifier notes can be done with the following code:

GluonObservableList<Note> notes = DataProvider.retrieveList(dataClient.createListDataReader("notes", Note.class));
ListView<Note> notesListView = new ListView<>(notes);

In its simplest form the createListDataReader method returns an instance of GluonObservableList without any synchronization flags.

You may have noticed that DataClient doesn’t provide a method for creating a new list. That is because a Gluon CloudLink list always exists. When a list is retrieved the first time, an empty list will automatically be created for you.

Retrieving objects

A remote object works a bit differently than a list, because in contrast to a list, an object does have the notion of existence. This explains why we have three methods for managing remote objects: createObjectDataReader, createObjectDataWriter and createObjectDataRemover.

// store the object
Note note = new Note();
note.setContent("This is the content for the note.");
GluonObservableObject<Note> gluonNote = DataProvider.storeObject(note, dataClient.createObjectDataWriter("a-single-note", Note.class));

// retrieve the object
GluonObservableObject<Note> gluonNote = DataProvider.retrieveObject(dataClient.createObjectDataReader("a-single-note", Note.class));

// remove the object
DataProvider.removeObject(gluonNote, dataClient.createObjectDataRemover());
GluonObservable ConnectState

All the operations on the DataProvider are asynchronous in nature and are executed in a separate background thread. You can listen for changes on the stateProperty of the returned GluonObservable object to monitor the progress of the background operation. To know when your object or list is ready to be used, you can also listen for the initializedProperty instead. Listed below you’ll find a number of common use cases when working with remote entities.

Create a remote object when it does not yet exist

When retrieving an object from Gluon CloudLink, you can detect if this object was already stored previously by using the following pattern:

GluonObservableObject<Note> gluonNote = DataProvider.retrieveObject(dataClient.createObjectDataReader("a-single-note", Note.class));
gluonNote.initializedProperty().addListener((observable, ov, nv) -> {
    if (nv) {
        if (gluonNote.get() == null) {
            // object not yet stored, initiate it now with a new object and store it
            gluonNote.set(new Note("This is some text for the note"));
            dataClient.push(gluonNote);
        } else {
            // object already stored previously
            Note note = gluonNote.get();
            System.out.println("Stored note: " + note.getContent());
        }
    }
});

Initialize an empty list with default objects

When you retrieve a list for the first time, an empty list will be created for you by the Gluon CloudLink service. Sometimes you wish to populate this empty list with default objects. You can do that with the following pattern:

GluonObservableList<Note> gluonNotes = DataProvider.retrieveList(dataClient.createListDataReader("notes", Note.class));
gluonNotes.initializedProperty().addListener((observable, ov, nv) -> {
    if (nv && gluonNotes.isEmpty()) {
        // initialize the list with some default notes
        gluonNotes.addAll(
                new Note("Text for note number 1."),
                new Note("Text for note number 2.")
        );
        dataClient.push(gluonNotes);
    }
});

Detecting failures when working with remote entities

If you notice that data isn’t stored or retrieved correctly, it might be that an exception occurred during the process. You can check the exceptionProperty on the GluonObservable object to see what exactly went wrong.

GluonObservableObject<Note> gluonNote = DataProvider.retrieveObject(dataClient.createObjectDataReader("a-single-note", Note.class));
gluonNote.stateProperty().addListener((observable, oldState, newState) -> {
    if (newState == ConnectState.FAILED) {
        if (gluonNote.getException() != null) {
            gluonNote.getException().printStackTrace();
        }
    }
});

3.1.3. Supported Data Types

The second parameter of the createListDataReader, createObjectDataReader and createObjectDataWriter methods on DataClient specifies the type of data that is stored in the remote entity. Gluon CloudLink supports three different data types: String, Map and custom classes. Inside a Map and for the fields of a custom class, the following field types can be used:

The JavaFX Property types are a requirement when a remote entity is retrieved in combination with the OBJECT_WRITE_THROUGH synchronization flag. See the Data Synchronization section for more information on these flags.

String

The String data type is the most basic of the three supported types. It simply stores and retrieves instances of string.

Map

The Map represents a convenient key/value store in which you can store arbitrary data. It is the most flexible data type, but is less type safe. The keys of the map must be strings, while the value can be any of the supported field types that are listed above. If the map contains a value that is not supported, those values will be ignored when storing or retrieving data.

Custom Class

As a final option, you can define your data structure inside a Custom Class. The DataClient will inspect the provided class for all declared fields of which the type matches any of the supported field types. Note that only non-static fields and non-final primitive fields will be considered. All other field declarations will be ignored when storing or retrieving data.

3.1.4. Data Synchronization

By default, no synchronization flags are configured when calling any of the methods we mentioned above. To enable synchronization, you can pass any of the SyncFlag enum constants to the method. There are four different types of SyncFlag:

  • OBJECT_READ_THROUGH: changes that occur on an object in Gluon CloudLink will be reflected to the fields on the local object

  • OBJECT_WRITE_THROUGH: changes on JavaFX Property fields will be automatically written to the object in Gluon CloudLink

  • LIST_READ_THROUGH: adding and removing objects on a list in Gluon CloudLink will be reflected to the local list

  • LIST_WRITE_THROUGH: adding and removing objects locally will automatically add and remove them to the list in Gluon CloudLink

Note that the OBJECT_READ_THROUGH and LIST_READ_THROUGH flags don’t have any effect when used in combination with the LOCAL_ONLY operation mode.

Also note that the OBJECT_WRITE_THROUGH flag will only work on non-static Observable fields of a Custom Class.

As an example, the code snippet below retrieves an instance of GluonObservableList that is configured with the list read through and list write through synchronization flags. This means that any changes that are done on the client, either adding or removing items, are propagated back to Gluon CloudLink. The reverse is true as well: all changes that occur in Gluon CloudLink will be reflected back to the local list on the device. Changes that occur on the objects inside the list won’t be propagated.

GluonObservableList<Note> notes = DataProvider.retrieveList(dataClient.createListDataReader("notes", Note.class, SyncFlag.LIST_READ_THROUGH, SyncFlag.LIST_WRITE_THROUGH));

3.2. Integration with Enterprise and Cloud Systems

One of the features of Gluon CloudLink is to link it with an existing back end infrastructure. There are two main ways for linking Gluon CloudLink with such a back end infrastructure.

  1. Call into the Gluon CloudLink REST endpoints from an enterprise system to retrieve and manage data. You can either directly call the REST endpoints or use an implementation of the Gluon CloudLink Enterprise SDK that best suits your existing enterprise environment.

  2. Use Connectors to let Gluon CloudLink automatically push and/or pull data to and from an enterprise system.

3.2.1. REST endpoints

Get object

Retrieve an object from the data service.

Path Parameters
Name Description

objectIdentifier

The unique identifier of the object to retrieve.

Curl sample
curl -X GET "https://cloud.gluonhq.com/3/data/enterprise/object/sample-object" \
     -H "Authorization: Gluon YOUR_SERVER_KEY"
Java Client
CloudLinkConfig config = new CloudLinkConfig(YOUR_SERVER_KEY);
CloudLinkClient client = new JavaEECloudLinkClient(config);

SampleType sampleObject = client.getObject("sample-object", SampleType.class);
Add object

Add a new object into the data service with the defined payload.

Path Parameters
Name Description

objectIdentifier

The unique identifier of the object to add.

Body

The body of the request must be a UTF-8 encoded JSON string and will be used as the payload for the newly added object.

Curl sample
curl -X POST "https://cloud.gluonhq.com/3/data/enterprise/object/sample-object/add" \
     -H "Authorization: Gluon YOUR_SERVER_KEY" \
     -H "Content-Type: application/json; charset=utf-8" \
     --data '{"text":"someField","number":123}'
Java Client
CloudLinkConfig config = new CloudLinkConfig(YOUR_SERVER_KEY);
CloudLinkClient client = new JavaEECloudLinkClient(config);

SampleType sampleObject = new SampleType("someField", 123);
SampleType storedObject = client.addObject("sample-object", sampleObject);
Update object

Update an existing object in the data service with the defined payload.

Path Parameters
Name Description

objectIdentifier

The unique identifier of the object to update.

Body

The body of the request must be a UTF-8 encoded JSON string and will be used as the payload for the object that is being updated.

Curl sample
curl -X POST "https://cloud.gluonhq.com/3/data/enterprise/object/sample-object/update" \
     -H "Authorization: Gluon YOUR_SERVER_KEY" \
     -H "Content-Type: application/json; charset=utf-8" \
     --data '{"text":"someOtherText","number":321}'
Java Client
CloudLinkConfig config = new CloudLinkConfig(YOUR_SERVER_KEY);
CloudLinkClient client = new JavaEECloudLinkClient(config);

SampleType sampleObject = new SampleType("someField", 123);
SampleType storedObject = client.addObject("sample-object", sampleObject);
storedObject.setText("someOtherText");
storedObject.setNumber(321);
SampleType updateObject = client.updateObject("sample-object", storedObject);
Remove object

Remove an existing object from the data service.

Path Parameters
Name Description

objectIdentifier

The unique identifier of the object to remove.

Curl sample
curl -X POST "https://cloud.gluonhq.com/3/data/enterprise/object/sample-object/remove" \
     -H "Authorization: Gluon YOUR_SERVER_KEY"
Java Client
CloudLinkConfig config = new CloudLinkConfig(YOUR_SERVER_KEY);
CloudLinkClient client = new JavaEECloudLinkClient(config);

client.removeObject("sample-object");
Get list

Retrieve a list of objects from the data service.

Path Parameters
Name Description

listIdentifier

The unique identifier of the list to retrieve.

Curl sample
curl -X GET "https://cloud.gluonhq.com/3/data/enterprise/list/sample-list" \
     -H "Authorization: Gluon YOUR_SERVER_KEY"
Java Client
CloudLinkConfig config = new CloudLinkConfig(YOUR_SERVER_KEY);
CloudLinkClient client = new JavaEECloudLinkClient(config);

List<SampleType> sampleList = client.getList("sample-list", SampleType.class);
Add object to list

Add an object to a list in the data service.

Path Parameters
Name Description

listIdentifier

The unique identifier of the list to add the object into.

objectIdentifier

The unique identifier of the object to add to the list.

Body

The body of the request must be a UTF-8 encoded JSON string and will be used as the payload for the object that is being added into the list.

Curl sample
curl -X POST "https://cloud.gluonhq.com/3/data/enterprise/list/sample-list/add/sample-object-1" \
     -H "Authorization: Gluon YOUR_SERVER_KEY" \
     -H "Content-Type: application/json; charset=utf-8" \
     --data '{"text":"someField","number":123}'
Java Client
CloudLinkConfig config = new CloudLinkConfig(YOUR_SERVER_KEY);
CloudLinkClient client = new JavaEECloudLinkClient(config);

SampleType sampleObject1 = new SampleType("someField", 123);
SampleType addedSampleObject1 = client.addToList("sample-list", "sample-object-1", sampleObject1);
Update object in list

Update an object in a list in the data service.

Path Parameters
Name Description

listIdentifier

The unique identifier of the list where the object to update is stored.

objectIdentifier

The unique identifier of the object to update in the list.

Body

The body of the request must be a UTF-8 encoded JSON string and will be used as the payload for the object that is being updated in the list.

Curl sample
curl -X POST "https://cloud.gluonhq.com/3/data/enterprise/list/sample-list/update/sample-object-1" \
     -H "Authorization: Gluon YOUR_SERVER_KEY" \
     -H "Content-Type: application/json; charset=utf-8" \
     --data '{"text":"someOtherText","number":321}'
Java Client
CloudLinkConfig config = new CloudLinkConfig(YOUR_SERVER_KEY);
CloudLinkClient client = new JavaEECloudLinkClient(config);

SampleType sampleObject1 = new SampleType("someField", 123);
SampleType addedSampleObject1 = client.addToList("sample-list", "sample-object-1", sampleObject1);
addedSampleObject1.setText("someOtherText");
addedSampleObject1.setNumber(321);
SampleType updatedSampleObject1 = client.updateInList("sample-list", "sample-object-1", addedSampleObject1);
Remove object from list

Remove an object from a list in the data service.

Path Parameters
Name Description

listIdentifier

The unique identifier of the list where the object to remove is stored.

objectIdentifier

The unique identifier of the object to remove from the list.

Curl sample
curl -X POST "https://cloud.gluonhq.com/3/data/enterprise/list/sample-list/remove/sample-object-1" \
     -H "Authorization: Gluon YOUR_SERVER_KEY"
Java Client
CloudLinkConfig config = new CloudLinkConfig(YOUR_SERVER_KEY);
CloudLinkClient client = new JavaEECloudLinkClient(config);

client.removeFromList("sample-list", "sample-object-1");

3.2.2. Connectors

A Connector can be used for automatic pushing and pulling of data from Gluon CloudLink to an enterprise back end system.

  • push: data that is updated in Gluon CloudLink is sent through to the enterprise back end

  • pull: data is requested from the enterprise back end by Gluon CloudLink

Different connector implementations are provided by Gluon CloudLink out of the box. Depending on the configured Connector, some extra code will be required on the back end application as well. E.g. when linking to Gluon CloudLink with the REST Connector, a handler must exist on the back end application that listens for HTTP requests that are called by Gluon CloudLink.

Configuring a Connector for a Gluon CloudLink Application is done in the Gluon Dashboard. The following Connectors are available for use within Gluon CloudLink. If you have a specific requirement for a custom Connector, please let us know.

Connector name

Description

REST Connector

This is the most generic connector and allows synchronization data to any enterprise or cloud system that can talk REST.

Couchbase Connector

This connector specifically synchronizes data from and to your Couchbase server. Ideally suited if you have an existing Couchbase installation that you want to unlock to mobile devices.

REST Connector

The REST Connector sends and receives data over a network connection using the standard HTTP protocol.

The connector can be set with the Gluon Dashboard application, Data Management, Connectors tab.

Data Storage - rest connector
Data Storage - rest connector

When using the REST Connector to link to a back end system, the Gluon CloudLink Application only needs to be configured with the URL where the requests from Gluon CloudLink need to be sent to.

Push endpoints

When a client application requests data to be added, updated or removed from Gluon CloudLink, those requests will be mapped with the REST Controller by making an HTTP request to one of the following six endpoints. Each of them should be implemented on the back end application to be able to handle the request.

Table 1. A new object is added

URL

/object/{objectIdentifier}/add

Method

POST

Request Body

JSON payload of the new object. If the object is a String, the payload will use a key named v.

Description

A new object is added to Gluon CloudLink. The objectIdentifier is the identifier that is passed in from the application client when retrieving or storing the object.

Table 2. An existing object is updated

URL

/object/{objectIdentifier}/update

Method

POST

Request Body

JSON payload of the updated object

Description

An existing object is updated in Gluon CloudLink. The objectIdentifier is the identifier that is passed in from the application client when retrieving or storing the object.

Table 3. An existing object is removed

URL

/object/{objectIdentifier}/remove

Method

POST

Request Body

The request body is empty

Description

An existing object is removed from Gluon CloudLink. The objectIdentifier is the identifier that is passed in from the application client when retrieving or storing the object.

Table 4. A new object is added to a list

URL

/list/{listIdentifier}/add/{objectIdentifier}

Method

POST

Request Body

JSON payload of object that is being added to the list

Description

A new object is added to a list. The objectIdentifier is an identifier that is assigned to the object specific to Gluon CloudLink, i.e. the client application is not aware of this identifier. This is in contrast to the listIdentifier, which is the identifier that is passed in from the application client when retrieving the list.

Table 5. An existing object is updated in a list

URL

/list/{listIdentifier}/update/{objectIdentifier}

Method

POST

Request Body

JSON payload of object that is being updated in the list

Description

An existing object in the list is updated. The objectIdentifier is an identifier that is assigned to the object specific to Gluon CloudLink, i.e. the client application is not aware of this identifier. This is in contrast to the listIdentifier, which is the identifier that is passed in from the application client when retrieving the list.

Table 6. An existing object is removed from a list

URL

/list/{listIdentifier}/remove/{objectIdentifier}

Method

POST

Request Body

The request body is empty

Description

An existing object is removed from a list. The objectIdentifier is an identifier that is assigned to the object specific to Gluon CloudLink, i.e. the client application is not aware of this identifier. This is in contrast to the listIdentifier, which is the identifier that is passed in from the application client when retrieving the list.

Pull endpoints

When a client application requests an object or a list that is not yet known inside Gluon CloudLink, Gluon CloudLink calls one of the following two endpoints on the back end application to retrieve the initial object or list information.

Table 7. An object is requested

URL

/object/{objectIdentifier}

Method

GET

Response Body

JSON payload of the object to retrieve

Description

A new object is being requested from the client application with the specified objectIdentifier.

Table 8. A list is requested

URL

/list/{listIdentifier}

Method

GET

Response Body

JSON payload of the list to retrieve. The payload is a JSON array containing a list of zero or more JSON objects. Each JSON object in the array defines two keys: id that defines the object identifier and payload which is the JSON payload of the object, represented as a JSON string.

Description

A new list is being requested from the client application with the specified listIdentifier.

Couchbase Connector

The Couchbase Connector is able to send data to an existing Couchbase Server. The only requirement on the Couchbase Server is an existing bucket that will hold the lists and/or objects from Gluon CloudLink.

couchbase server bucket

When activating the Couchbase Connector inside the Dashboard, you will need to provide the following information to let Gluon CloudLink be able to setup a connection with the Couchbase Server:

  • Nodes: a list of nodes that the Couchbase Client on Gluon CloudLink uses to setup the connection to a Couchbase Cluster. You can specify more than one node, by separating them with a semicolon.

  • Bucket Name: the name of the Couchbase bucket that will hold the lists and/or objects

  • Bucket Password: the password of that Couchbase bucket

Data Storage - couchbase connector
Pushing Objects

Objects are stored in the Couchbase bucket using a key named objects/{objectIdentifier}, where objectIdentifier is the identifier that is passed in by the client application when storing or retrieving the object.

The document itself will be a JSON document that represents the JSON payload of the object. An example of such an object can be seen below:

objects/notes-settings
{
  "fontSize": 10,
  "sortingId": 2,
  "ascending": true,
  "showDate": false
}
Pushing Lists

Lists are also stored as a document with a key named lists/{listIdentifier}, where listIdentifier is the identifier that is passed in by the client application when retrieving the list.

For each object in the list, the document will contain a key that matches the identifier of the object. The value that is mapped to that key is a JSON document that represents the JSON payload of the object. Below is an example of a list that contains two objects:

lists/notes
{
  "af52f4c6-a64b-4823-b9fb-3cbef79d7577": {
    "creationDate": 1463062055,
    "title": "new note",
    "text": "sample 2"
  },
  "f880774a-20e9-11e6-b67b-9e71128cae77": {
    "creationDate": 1463054952,
    "title": "another note",
    "text": "and also another sample text"
  }
}
Pulling Data

Gluon CloudLink can also pull data from the same Couchbase Server when a list and/or object is retrieved that is not yet known within the Gluon CloudLink data store. It will try to retrieve a list or object from the configured bucket, by using the same identifiers as described in the push section above: lists/{listIdentifier} for lists and objects/{objectIdentifier} for objects. The format of the documents stored inside the Couchbase bucket must also follow the same format as described in the previous section.

4. Remote Functions

Almost all mobile applications that exist today interact with a back end infrastructure for managing their data. In theory, an application can directly make requests to these back ends, but there are a number of drawbacks for doing this:

  • Mobile devices are not always connected to the internet. It takes lots of boilerplate code to check connectivity and handle rescheduling of requests when connectivity is restored.

  • Applications on mobile devices have specific lifecycles and need to behave according to specific policies. Some resources are conditionally available. The battery might be low, the application might be running in the background, the device is connected with a paid cellular network, etc. Depending on those conditions, an application must behave differently.

  • Mobile devices have less resources than the regular server, and those resources need to shared with other applications.

CloudLink provides Remote Functions to give the application a reliable and secure way for linking with existing back end systems.

4.1. Managing Remote Functions

Managing remote functions is done in the API Management section of the Gluon Dashboard. Each remote function is uniquely identified by a name. This name will be used in the client application when it makes a call to the defined remote function.

Sign in to the Gluon Dashboard and navigate to API Management. You will find the following sections:

  • Functions: this is where the remote functions are configured

  • Authentication: in here different authentication schemes can be created that are used when authentication is required by a remote function

  • Call Log: logging information for calls that are made to a remote function

Api Management - overview

4.1.1. Remote Function Types

We currently support the following types to choose from when creating a new remote function:

  • HTTP Request: executes an HTTP request based on the configured parameters

  • Amazon AWS Lambda: calls an Amazon AWS Lambda function

  • Azure Function: calls a Microsoft Azure Function

  • Fn Project Function: invoke a function on Fn

  • Gluon Function: invoke a function that is running on Gluon CloudLink

4.1.2. Create Remote Functions - HTTP Request

Click the + button to add a new remote function and choose HTTP Request. A dialog will be shown where the following components can be configured:

Api Management - remote function http request
Function Name

The function name is a unique identifier for the remote function. The name is used in the client application when a call needs to be triggered to the remote function.

Enable Mock Response

Mock responses can be enabled for testing purposes. When mocking is enabled, a call to the remote function will not create a request to the actual configured endpoint, but respond directly with the data that is defined for the mock response.

Method

The method defines what HTTP method to use when creating the request. The following methods are supported: GET, POST, PUT and DELETE.

Endpoint

The endpoint is the URI to use when creating the request.

Read Timeout

Specify the timeout, in milliseconds, for reading from the remote function endpoint. If the value is zero, the default timeout will be used.

Connect Timeout

Specify the timeout, in milliseconds, for connecting to the remote function endpoint. If the value is zero, the default timeout will be used.

Authentication Method

Specifies the authentication method that must be used when executing the request to the remote function. The authentication method can be selected from a list of authentication methods that are configured in the Authentication section.

Body Type

The body type can be specified when the POST or PUT method is selected. The body type defines what kind of data will be sent to the remote function. The following types are supported:

  • none: the request will be sent without a request body

  • x-www-form-urlencoded: for sending form url encoded requests

  • form-data: for sending form data multipart requests

  • raw: for sending raw text, i.e a json string

When the raw body type is chosen, two extra fields will be available to specify the data and the media type of the raw body content.

4.1.3. Create Remote Functions - Amazon AWS Lambda

Before you can create a remote function for an AWS Lambda function, you need to add customer credentials that point to a valid Amazon AWS access key. Navigate to the Credentials section in Gluon Dashboard and choose the Customer tab. Add new credentials by clicking the + button and choose AWS Access Key. Enter the required information.

Credentials - aws access key

Navigate back to the API Management section and click the + button to add a new remote function while choosing Amazon AWS Lambda. A dialog will be shown where the following components can be configured:

Api Management - remote function aws lambda
Function Name

The function name is a unique identifier for the remote function. The name is used in the client application when a call needs to be triggered to the remote function.

Enable Mock Response

Mock responses can be enabled for testing purposes. When mocking is enabled, a call to the remote function will not create a request to the actual configured endpoint, but respond directly with the data that is defined for the mock response.

AWS Credentials

The AWS Access Key to use when listing the available AWS Lambda functions.

AWS Region

The AWS region where the AWS Lambda functions must be listed from.

AWS Lambda Function

The actual AWS Lambda function to link with this remote function.

AWS Lambda Version

An optional specific version of the AWS Lambda function that must be executed. Leaving this empty will use the default $LATEST version of the chosen AWS Lambda function.

Payload Type

An optional payload that should be sent along when executing the AWS Lambda function. The following types are supported:

  • none: no payload will be sent with the call

  • byte array: sends an array of raw bytes encoded as a Base64 string, useful when sending binary data from the client

  • string: useful for sending plain text

Payload Variable Name

When the selected payload type is string or byte array, you can specify the variable name of the payload. The payload is passed down to the AWS Lambda function as a JSON object containing the variable name as a key. When the payload type is string, the value mapped with the key will be the JSON value that is loaded from the Payload string that can be specified in the text area below. If the payload type is byte array, then the JSON value will be a Base64 encoded string of the passed in array of bytes.

Payload

When the string payload type is chosen, an extra text area will be available to specify the data for the string content. The resulting data string must be valid JSON. If this is not the case, the request to the remote function will be aborted with a Bad Request status.

Output Media Type

Defines the expected media type of the response from the AWS Lambda function. If left empty, the default value of text/plain will be used instead.

Read Timeout

Specify the timeout, in milliseconds, for reading from the remote function endpoint. If the value is zero, the default timeout will be used.

Connect Timeout

Specify the timeout, in milliseconds, for connecting to the remote function endpoint. If the value is zero, the default timeout will be used.

4.1.4. Create Remote Functions - Azure Function

Configure a remote function that can invoke a Microsoft Azure function with an http trigger. Click the + button to add a new remote function and choose Azure Function. A dialog will be shown in which the following components can be configured:

Api Management - remote function azure
Function Name

The function name is a unique identifier for the remote function. The name is used in the client application when a call needs to be triggered to the remote function.

Enable Mock Response

Mock responses can be enabled for testing purposes. When mocking is enabled, a call to the remote function will not create a request to the actual configured endpoint, but respond directly with the data that is defined for the mock response.

Method

The method defines what HTTP method to use when creating the request. The following methods are supported: GET, POST, PUT and DELETE.

Function URL

The Function URL that points to the Azure function.

API Key

Define the Function Key to use for authorizing the invocation to the Azure function. The key is passed down to the function using the x-functions-key HTTP header. Make sure that you copy the value of the Function Key and not its name. Azure functions using Anonymous authorization can leave this field empty.

Read Timeout

Specify the timeout, in milliseconds, for reading from the remote function endpoint. If the value is zero, the default timeout will be used.

Connect Timeout

Specify the timeout, in milliseconds, for connecting to the remote function endpoint. If the value is zero, the default timeout will be used.

Body Type

The body type can be specified when the POST or PUT method is selected. The body type defines what kind of data will be sent to the remote function. The following types are supported:

  • none: the request will be sent without a request body

  • x-www-form-urlencoded: for sending form url encoded requests

  • raw: for sending raw text, i.e a json string

When the raw body type is chosen, two extra fields will be available to specify the data and the media type of the raw body content.

4.1.5. Create Remote Functions - Fn Project Function

These are remote functions that are configured to run on the Fn Project platform. Your Fn function must be available from a public registry on Docker Hub. Click the + button to add a new remote function and choose Fn Project Function. A dialog will be shown in which the following components can be configured:

Api Management - remote function fn project function
Function Name

The function name is a unique identifier for the remote function. The name is used in the client application when a call needs to be triggered to the remote function.

Enable Mock Response

Mock responses can be enabled for testing purposes. When mocking is enabled, a call to the remote function will not create a request to the actual configured endpoint, but respond directly with the data that is defined for the mock response.

Docker Registry

The name of the docker image as it has been pushed to Docker Hub. You can optionally specify a tag for the image, for instance: gluonhq/helloworld:0.0.2.

Enable Input

Enabling input reveals a text area. The content of the text area will be passed down to the Fn Function during invocation.

Timeout

Specify the timeout, in seconds, for executing the remote function on the Fn Project platform. If the value is zero, the default timeout will be used.

4.1.6. Create Remote Functions - Gluon Function

Gluon Functions allow you to run Java functions inside a serverless platform that is managed by Gluon CloudLink itself. All you need is a zip file that bundles all the runtime jar files that are needed for running the function. The Gluon IDE plugins assist you with creating and deploying of your Gluon Remote Functions.

Click the + button to add a new remote function and choose Gluon Function. A dialog will be shown in which the following components can be configured:

Api Management - remote function gluon function
Function Name

The function name is a unique identifier for the remote function. The name is used in the client application when a call needs to be triggered to the remote function.

Enable Mock Response

Mock responses can be enabled for testing purposes. When mocking is enabled, a call to the remote function will not create a request to the actual configured endpoint, but respond directly with the data that is defined for the mock response.

Entrypoint

The entrypoint defines what method should be invoked when the Gluon Function is triggered. The syntax consists of the fully qualified class name and the method name to be invoked, separated with a double colon, i.e.: com.gluonhq.sample.function.GluonFunction::methodName

Java Runtime

Specify the Java Runtime environment that must be used for running the Gluon Function. You can choose between Java 8 and Java 9.

Memory

Define the maximum amount of memory that should be provided when running the Gluon Function. You can choose a value between 128MB and 1GB with intervals of 128MB.

Bundle

The bundle contains the actual classes that are needed for executing the Gluon Function. The bundle is a zip file containing one or more jar files that will be added to the classpath of the Gluon Function.

Read Timeout

Specify the timeout, in milliseconds, for reading from the remote function endpoint. If the value is zero, the default timeout will be used.

Connect Timeout

Specify the timeout, in milliseconds, for connecting to the remote function endpoint. If the value is zero, the default timeout will be used.

4.1.7. Parameters

Each remote function can be configured with additional parameters. Each parameter consists of a type, a name and optional default and test values. The name is used by the client application to define the value for the parameter that will be passed on when building the request for the remote function. In the image below, a query parameter is configured with the name tagged.

Double clicking inside the grid will activate the edit view for the selected function parameter.

Api Management - parameters

Four different types of parameters are currently supported.

Query

A query parameter will be sent as part of the query string. The query string is the part of the URI that comes after the question mark.

Note: only supported for remote functions of type HTTP Request

Form

A form parameter can be chosen for remote functions that are configured with the POST method. Form parameters are sent as form url encoded parameters in the body of the request.

Note: only supported for remote functions of type HTTP Request

Header

A header parameter can be used to send custom HTTP request headers when building the request for the remote function.

Note: only supported for remote functions of type HTTP Request

Variable

Variable parameters can be used to add custom variables to certain fields of a remote function. Remote functions of type HTTP Request can have custom variables in the Endpoint and Raw Data fields; Remote functions of type Amazon AWS Lambda can have custom variables in the Payload field. Also, each custom variable that is added to an Amazon AWS Lambda Remote Function will be passed along with the JSON payload as well.

For example, the following URI endpoint contains a single variable called userIdentifier: https://foo.bar/user/$userIdentifier. The variable will be replaced with the value that was passed on by the client application, before the actual request is executed.

4.2. Authentication

The endpoint of a remote function sometimes requires that the request is authenticated. The Authentication section provides three different authentication mechanisms that can be used together with a remote function.

Api Management - authentication

4.2.1. Basic Authentication

This will add a basic Authorization HTTP header when creating the request to the remote function. The username and password are both required.

4.2.2. OAuth 1.0 with Consumer Credentials

This authentication method will sign each request with the provided consumer key and secret using the HMAC-SHA1 signature method. See the OAuth 1.0 documentation on signing requests for more details: https://oauth.net/core/1.0a/#signing_process.

A token key and secret can be provided as well when necessary, but can be left empty if the endpoint only requires that the request must be signed with consumer credentials.

4.2.3. OAuth 2.0 with Password Credentials Grant

This authentication method will apply the Resource Owner Password Credentials authorization grant as defined in the OAuth 2.0 specificiation: https://tools.ietf.org/html/rfc6749#section-4.3.

When making a request to the defined endpoint of the remote function, it will first try to get an access token using the configuration details of the authentication method. The access token will then be passed along with the actual request to the endpoint of the remote function.

4.3. Calling Remote Functions

4.3.1. Testing

Each remote function can be tested from within Gluon Dashboard to ensure the configuration is valid. Each configured parameter has an optional test value that will be used when testing the remote function. When no test value is provided, the default value will be used instead.

When testing the remote function, the response of the endpoint will be printed so it can be verified against the expected value.

4.3.2. Call Log

Useful information from each call that is being invoked by a remote function is stored in the Call Log and can be accessed in Gluon Dashboard. Each request records the response code, the request and response timestamps and the body of the request and response. The body is capped at 8k.

Api Management - call log

For calling a remote function from the client application we use the RemoteFunctionBuilder. The RemoteFunctionBuilder can generate three different implementations of a RemoteFunction, each handling the response of the call to the remote function in their own way:

  • RemoteFunctionObject: the response is converted and wrapped into a GluonObservableObject

  • RemoteFunctionList: the response is converted into a list of objects, contained in a GluonObservableList

  • RemoteFunctionChunkedList: the response of the function is a continuous stream of chunks, where each chunk is converted and added to a GluonObservableList

Basic Remote Functions

To start calling remote functions, we first need to build an instance by using the RemoteFunctionBuilder builder class. Each built RemoteFunction instance can then be triggered by calling the call method.

// create an instance of remote function
RemoteFunctionList remoteFunction = RemoteFunctionBuilder.create("myFunction")
        .param("myParameter", "parameterValue")
        .list();

// call the remote function to fetch an observable list
GluonObservableList<MyResponse> responses = remoteFunction.call(MyResponse.class);
Local Caching

Every response that is returned by a call to a remote function will by default be cached locally in the private storage of the device. The next time the remote function is called, it will first load and return the cached data before making the actual call to the remote function in Gluon CloudLink. This allows the application to already present the user with data from the last time the remote function was called. When the response from the call to the actual remote function in Gluon CloudLink is completed, it will overwrite the cached data with the data from the new response.

Caching can be explicitly disabled when building the remote function:

// create an instance of remote function without caching locally
RemoteFunctionObject remoteFunction = RemoteFunctionBuilder.create("anotherFunction")
        .cachingEnabled(false)
        .object();

The cached data itself can also be cleared by using the clearCache() method:

// clear the locally cached data
remoteFunction.clearCache();

// the GluonObservableObject instance will no longer receive
// the cached data as it was cleared
GluonObservableObject<Sample> sample = remoteFunction.call(Sample.class);
Chunked Remote Functions

By default, Gluon CloudLink will close the call to the endpoint that is configured for a remote function after 60 seconds. However, the connection will be kept open when the remote function uses chunked transfer encoding. This is handled automatically, when the remote function specifies the Transfer-Encoding response header with the value chunked in its response. In other words, there is nothing special that needs to be configured in your Remote Function definition on Gluon Dashboard.

At the client side, you do need to use a different implementation of RemoteFunction that is able to handle chunked encoding: RemoteFunctionChunkedList.

// create an instance of a chunked remote function
RemoteFunctionChunkedList chunkedFunction = RemoteFunctionBuilder.create("chunkedFunction")
        .param("myParameter", "parameterValue")
        .chunkedList();

// call the remote function to fetch an observable list. Gluon CloudLink will add a
// new item to this list, for each chunk it receives from the remote function
GluonObservableList<MyChunk> responses = chunkedFunction.call(MyChunk.class);
Remote Functions with binary data

Writing binary data with a remote function can be done by defining the remote function in Gluon Dashboard with the raw body type. In the client application, a byte array is provided as the raw body when building the remote function.

// retrieve bytes from a classpath resource
byte[] rawBody = {};
try (ByteArrayOutputStream os = new ByteArrayOutputStream();
     InputStream is = Main.class.getResourceAsStream("/sample.wav")) {
    byte[] bytes = new byte[4096];
    int read;
    while ((read = is.read(bytes)) != -1) {
        os.write(bytes, 0, read);
    }
    rawBody = os.toByteArray();
} catch (IOException e) {
    // handle exception
}

// create an instance of remote function with raw bytes
RemoteFunctionObject playSoundFunction = RemoteFunctionBuilder.create("playSound")
        .rawBody(rawBody)
        .object();

// call the remote function passing on the raw bytes
GluonObservableObject<Void> response = playSoundFunction.call(Void.class);
response.stateProperty().addListener((obs, ov, nv) -> {
    if (nv == ConnectState.SUCCEEDED) {
        System.out.println("Sound uploaded successfully.");
    }
});

4.4. End to End Guide

You can find end to end guides on working with different cloud servers with Gluon Cloudlink below:

5. User Management

The User Management service enables user authentication in your Gluon Mobile application. It supports email and password based authentication and signing in with most popular identity providers like Facebook, Google and more. Each of these authentication types is called a Login Method in Gluon CloudLink.

Here is an overview of the login methods that are currently supported by Gluon CloudLink:

  • Facebook Login

  • Google Sign-In

  • Twitter

  • GitHub

  • Email and Password

5.1. Enabling Login Methods

Enabling the login methods that should be available for your application can be done from the Gluon Dashboard. Navigate to the User Management link, and select the Login Methods tab. From here you can add and configure one or more login methods.

View configured login methods

The login methods for identity providers all need a key and a secret from an application that is created on the respective identity provider. We provide a step-by-step guide to creating and configuring an application for each of the supported identity providers.

5.2. Applying Login Methods

5.2.1. UserClient

The UserClient class is the access point to the User Management service. It contains various methods for managing the authentication process. When a new instance is constructed, it will load the Login Methods that are enabled for the Gluon Mobile application and present them to the user when the authentication process is started.

Initiate authentication

A typical workflow to authenticate a user would be coded as follows:

UserClient userClient = new UserClient();
userClient.authenticate(user -> {
    System.out.println("User authenticated successfully: " + user.getName());
});

When no authenticated user exists yet, the authentication process will be started. This is handled by taking the user to the implementation of the AuthenticationView. The default AuthenticationView implementation looks like this:

App Sign in Methods

The user can select one of the presented login methods which will start the authentication flow for the selected login method. When a user was successfully authenticated, or when an authenticated user was already present, the provided consumer in the authenticate method will be called, passing in the authenticated user.

Handling failed or aborted authentication

In case the user aborted the authentication process or when an unexpected error occurred, you can use the authenticate variant which takes an extra failure consumer.

userClient.authenticate(user -> System.out.println("User authenticated successfully!"),
    failure -> System.out.println("Authentication failed or aborted: " + failure));
Signing out

Once a user is successfully authenticated, that user will not need to authenticate again the next time the application is started. To be able to restart the authentication process , you will first need to call the signOut method.

5.2.2. User

The authenticated user can be retrieved from the UserClient by calling the getAuthenticatedUser method. This returns an instance of User that has the following fields available:

  • key: the unique identifier of the user within the entire application

  • name: the full name of the user

  • nick: an optional nick name for the user

  • picture: an optional URL to the profile picture of the user

  • networkId: the identifier of the user at the identity provider that was used for authentication

5.2.3. Data Authentication

As mentioned in the Data Storage section, you can also use a UserClient to make sure that only authenticated users have access to data that is loaded by a DataClient. To enable this, you need to pass in an instance of UserClient when building the DataClient:

UserClient userClient = new UserClient();
DataClient dataClient = DataClientBuilder.create()
        .authenticateWith(userClient)
        .operationMode(OperationMode.CLOUD_FIRST)
        .build();

The first time that DataClient instance is used to access data, the authentication process will be initiated when an authenticated user was not yet present on the provided UserClient instance.

6. Media Management

The Media Management service is a central place to manage media resources that are used inside your mobile application. We distinguish the following different media types:

  • Media: refers to images, video and audio that can be used in the mobile application

  • Resource Bundles: refers to i18n resource bundle property files for translating application copy

6.1. Media

Each media resource is defined by a unique name. The client application will request the media resource by specifying that name. Each media is further made up of one or more media variants. The variant contains the actual media file, together with metadata to define for which platform the media should be made available. That way, it is for instance possible to define a different version of a media resource for Android and iOS.

6.1.1. Uploading Media

From the Gluon Dashboard, selecting the Media Management link will present you with a view that is divided into two grids. The top grid holds the media, while the bottom grid will show the media variants that are linked with the selected media from the top grid.

Add a new media resource by clicking the plus button from the top grid. This will create the media container as well as the first associated media variant. The following fields can be defined in the form dialog:

Media Name

This defines the unique name for the media resource. The client application will use this name to get a reference to the media resource.

Platform

Associates the media variant with a specific platform. When the client application requests a media resource and a specific variant exists that matches the platform where the application is running at, that media variant will be returned. Leave the platform empty to define the fallback resource that will be returned when no variant was found for a specific platform and/or platform version.

Platform Version

You can further specialize the media variant by defining a matching platform version. This media resource will only be returned when both the platform and the version of the platform where the application is running on match with the specified values.

Media File

This is the ultimate resource file that is linked with the media variant. It’s also this file that is returned to the client application in the form of an InputStream.

6.1.2. Loading Media Resources on the Mobile Client

The MediaClient is the class that you need to load media resources on the mobile client application. You only need to know the name of the media resource to load and call one of the two available functions:

  • loadMedia: loads an arbitrary media resource and returns it’s data as an InputStream

  • loadImage: loads an image media resource into a JavaFX Image

The following code snippet shows an example of how to show a media resource into a Glisten View:

public void initialize() {
    MediaClient mediaClient = new MediaClient();
    Image image = mediaClient.loadImage("backgroundImage");

    StackPane pane = new StackPane();
    pane.getChildren().add(image);

    setCenter(pane);
}

6.2. Resource Bundles

Resource Bundles are the standard way for providing i18n functionality in Java. Resources bundles are typically provided by one properties file or class for each supported language. These properties files or classes are then shipped together with your application package. With Gluon CloudLink we add the possibility to provide the resource bundles as an internet resource.

The resource bundle consists of a resource file for each supported locale. When adding a new resource bundle, you specify the locale that defines the associated language, country, script, etc. When the client application requests the resource bundle, it also passes down a locale so that Gluon CloudLink can return the resource bundle that matches the given locale.

6.2.1. Uploading Resource Bundles

Resource Bundles can be uploaded from the Gluon Dashboard. Navigate to Media Management and choose the Resource Bundles tab. Click the + button to add a new resource bundle. The resource bundles are grouped by their bundle name. The most common scenario is to create a resource bundle for each view in your mobile application.

Note: it is best practice to always provide a version of the resource bundle with an empty locale. This way, when no matching resource bundle could be found for a given locale, the resource bundle with the empty locale will be used as a fallback.

6.2.2. Loading Resource Bundles on the Mobile Client

We call the method loadResourceBundle on an instance of MediaClient to load a resource bundle from Gluon CloudLink. You can use the returned Resource Bundle to load it into your View.

public void initialize() {
    MediaClient mediaClient = new MediaClient();
    ResourceBundle resourceBundle = mediaClient.loadResourceBundle("com.gluonhq.sample.BasicView",
            Locale.getDefault());

    Label label = new Label(resourceBundle.getString("greeting"));

    StackPane pane = new StackPane();
    pane.getChildren().add(label);

    setCenter(pane);
}

7. Usage Analytics

The Usage Analytics service is responsible for gathering statistics on the devices that are running your Gluon Mobile application. That information can then be visualised and analysed from within the Gluon Dashboard web application.

The data that is being gathered contains information about the requests that the Gluon Mobile application makes to the Gluon CloudLink services. It also contains general information about the device itself, like the platform, the model, the version of the application, etc.

7.1. Applying Usage Analytics

7.1.1. UsageClient

To enable usage analytics in your Gluon Mobile application, you will need to call the enable method on the UsageClient. The method can be called at any time, but ideally it should be called as soon as the application is launched.

UsageClient usageClient = new UsageClient();
usageClient.enable();

This will trigger a call to the Gluon CloudLink Usage service that stores the general device information. The trigger will only be sent the first time, so any subsequent calls to the enable method will do nothing.

7.1.2. build.gradle

Don’t forget to add the Charm Down device plugin in the build.gradle file of your Gluon Mobile project.

...
jfxmobile {
    downConfig {
        version '3.6.0'
        plugins 'device', 'display', 'lifecycle', 'statusbar', 'storage'
    }
    ...
}

7.2. Gluon Dashboard

The Gluon Dashboard can be used to inspect the usage information that is being logged by the devices that are running your Gluon Mobile application. When the UsageClient is enabled as shown in the previous section, there is nothing else to configure in the Gluon Dashboard. By default, the data that is shown is gathered from the devices that were active during the past two weeks.

Usage Analytics Graph

8. Push Notifications

The Push Notifications service enables sending push notifications to the devices that installed your Gluon Mobile application. A push notification is a notification message that can be sent to the device, even when the application is not running. This can be used to unobtrusively notify a user that an application specific event has triggered.

8.1. Enabling Push Notifications

Gluon CloudLink uses Google Cloud Messaging (GCM) for handling push notifications over to Android devices and Apple Push Notification service (APNs) to get push notifications delivered to iOS devices. Both GCM and APNs require credentials for accessing their services.

8.1.1. Google Cloud Messaging

For GCM you will need to enable Google services for your Google application. You will then need both the Server API Key and the Sender ID of the application. The Server API Key is required to allow Gluon CloudLink to deliver push notifications to your Gluon Mobile application on Android devices. The Sender ID is needed inside your Gluon Mobile application when it registers the device to GCM to notify that it wants to receive push notifications.

You can follow a step-by-step guide for configuring GCM in a Google Application.

8.1.2. Apple Push Notification service

For APNs you will need to configure the push notifications capability for your iOS application. You will need the final signing key, exported as a p12 certificate. The certificate is required to allow Gluon CloudLink to communicate with the APNs service to deliver push notifications to your Gluon Mobile application on iOS devices.

You can follow a step-by-step guide for configuring APNs in the Apple Developer Center.

8.1.3. Gluon Dashboard

When you’ve managed to prepare your application for both GCM and APNs, you can configure your Gluon Mobile application in the Gluon Dashboard. Select the Push Notifications link from the menu, go the Configuration tab, where you can enter the GCM Server API key and upload your APNs certificate.

Push Notifications Configuration

With the proper certificates, the Push Notifications tab can be used to send a push notification. Clicking on the + button will pop up a dialog from which you can enter the details of the notification.

Push Notifications Dialog

The checkbox labelled invisible can be selected to send silent push notifications to the user, without a visible notification. The Runtime Args service will be able to process it and execute certain action.

8.2. Using Push Notifications from Enterprise

8.2.1. REST endpoint

Send Push Notification

Send a new push notification to the defined target devices.

Form Parameters
Name Type Description Default

body

string

the body of the push notification

deliveryDate

long

Note: this parameter is currently ignored

0

expirationAmount

integer

the amount used in conjunction with the expiration type

4

expirationType

DAYS, HOURS, MINUTES, WEEKS

the type of the expiration amount

WEEKS

identifier

string

a custom identifier to be sent along with the push notification

invisible

boolean

specify true to send a silent push notification

false

priority

HIGH, NORMAL

The priority for the push notification.

HIGH

targetDeviceToken

string

The device token to use as the target for the push notification. Only used when the target type is SINGLE_DEVICE

targetTopic

string

The name of the topic to use as the target for the push notification. Only used when the target type is TOPIC.

targetType

ALL_DEVICES, SINGLE_DEVICE, TOPIC

The target of the push notification.

ALL_DEVICES

title

string

the title of the push notification

Curl sample
curl -X POST "https://cloud.gluonhq.com/3/push/enterprise/notification" \
     -H "Authorization: Gluon YOUR_SERVER_KEY"
     --data "body=Sample%20Body" \
     --data "title=Sample%20Title" \
     --data "expirationType=HOURS" \
     --data "expirationAmount=1" \
     --data "priority=HIGH" \
     --data "invisible=false" \
     --data "targetType=TOPIC" \
     --data "targetTopic=Topic1"

8.2.2. Java Client

CloudLinkConfig config = new CloudLinkConfig(YOUR_SERVER_KEY);
CloudLinkClient client = new CloudLinkClient(config);

PushNotification pushNotification = new PushNotification();
pushNotification.setBody("Sample Body");
pushNotification.setTitle("Sample Title");
pushNotification.setExpirationType(PushNotification.ExpirationType.HOURS);
pushNotification.setExpirationAmount(1);
pushNotification.setPriority(PushNotification.Priority.HIGH);
pushNotification.getTarget().setType(PushNotificationTarget.Type.TOPIC);
pushNotification.getTarget().setTopic("Topic1");
client.sendPushNotification(pushNotification);

8.3. Applying Push Notifications in Mobile Client

8.3.1. PushClient

To activate push notifications on your Gluon Mobile application, you will need a reference to the PushClient and call the enable method. The method takes one parameter, which is the Sender ID of the GCM application from Google. iOS doesn’t need any specific identifiers because identification will be done by specifying a correctly configured Apple provisioning profile.

PushClient pushClient = new PushClient();
pushClient.enable("123456789012"); // enable push notifications

This will trigger a message on an iOS device asking the user to confirm that push notifications are allowed for the application. On Android, if the user has not yet installed or activated Google Play services, a message will be shown to ask for permission to install and/or activate Google Play services on the device.

8.3.2. build.gradle

Don’t forget to add the Charm Down device, push-notifications and runtime-args plugins in the build.gradle file of your Gluon Mobile project.

...
jfxmobile {
    downConfig {
        version '3.6.0'
        plugins 'device', 'display', 'lifecycle', 'push-notifications', 'runtime-args', 'statusbar', 'storage'
    }
    ...
}

8.3.3. Android configuration

For Android, we need to update the Android Manifest configuration file to add the required permissions and register the services for handling push notifications.

Permissions

The following permissions must be configured for the application to be able to receive notifications from GCM:

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <uses-permission android:name="YOUR_PACKAGE_NAME.permission.C2D_MESSAGE" />
    <permission android:name="YOUR_PACKAGE_NAME.permission.C2D_MESSAGE" android:protectionLevel="signature" />

Change YOUR_PACKAGE_NAME above to the package name that you defined for your application at the top of the Android Manifest.

The WAKE_LOCK permission is optional and is used to prevent the processor from going to sleep while listening for incoming messages from GCM.

Receivers, services and activity

Add the receiver, services and activity listed below inside the application section of the Android Manifest. Again, replace YOUR_PACKAGE_NAME in the receiver category to the package name of your application.

<receiver android:name="com.google.android.gms.gcm.GcmReceiver"
          android:exported="true"
          android:permission="com.google.android.c2dm.permission.SEND">
    <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
        <category android:name="YOUR_PACKAGE_NAME" />
    </intent-filter>
</receiver>

<service android:name="com.gluonhq.impl.charm.down.plugins.android.PushGcmListenerService"
         android:exported="false">
    <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
    </intent-filter>
</service>

<service android:name="com.gluonhq.impl.charm.down.plugins.android.PushInstanceIDListenerService"
         android:exported="false">
    <intent-filter>
        <action android:name="com.google.android.gms.iid.InstanceID" />
    </intent-filter>
</service>

<service android:name="com.gluonhq.impl.charm.down.plugins.android.RegistrationIntentService"
         android:exported="false" />

<activity android:name="com.gluonhq.impl.charm.down.plugins.android.PushNotificationActivity"
                android:parentActivityName="javafxports.android.FXActivity">
    <meta-data android:name="android.support.PARENT_ACTIVITY"
                       android:value="javafxports.android.FXActivity"/>
</activity>
<meta-data android:name="com.google.android.gms.version" android:value="9452000"/>
Update launch mode

The main activity declaration should have the android:launchMode attribute set to singleTop. This ensures that the same activity is being used when a push notification is delivered to the device when the application is running in the foreground.

...
<activity android:name="javafxports.android.FXActivity"
          android:label="PushNotes"
          android:launchMode="singleTop"
          android:screenOrientation="portrait"
          android:configChanges="screenSize">
...

8.3.4. iOS configuration

First make sure to configure your app so it can use Push notifications in the Apple Developer Center. You can follow this step-by-step guide.

Update build.gradle

Change your project’s build.gradle file

  • to make sure it uses the correct provisioning profile for your app:

  • to enable the Push notification entitlement

jfxmobile {
    ios {
        iosSignIdentity = 'iPhone Developer: ...'
        iosProvisioningProfile = 'Push Notes Provisioning Profile'
        apsEnvironment = 'development'
    }
}

As signing identity, use the certificate selected during the provisioning profile generation.

When deploying to your iOS device, the provisioning profile will be downloaded. If this is not the case, you still can install it manually: Open XCode, connect your device, go to Window → Device, and at the bottom left there is a small engine icon, click to see the installed provisioning profiles, and then click on the + button to add this one.

Note that this provisioning profile contains the entitlements that match those installed within the app, required to enable push notifications.

The apsEnvironment property needs to match the match the used environment (development or production)

Build your app

When you’ve configured your build.gradle, all you have to do is building your app as usual. Alternatively, you can skip changes in build.gradle and provide the necessary option from the command-line:

 ./gradlew \
      -Pjfxmobile.ios.apsEnvironment="production" \
      -Probovm.iosSignIdentity="iPhone Distribution: ..." \
      -Probovm.iosProvisioningProfile="your-provisioning-profile-name" \
      createIpa