Microservice SDK for Java

Overview

This section describes how to develop and deploy microservices on top of Cumulocity using the Microservice SDK for Java.

To get started, check the Hello World example.

Info: You can develop Cumulocity with any IDE and any build tool that you prefer, but the examples focus on Maven and Eclipse.

After reviewing the "Hello world" you may continue with the section Developing Java clients.

Finally, here are some references for getting started with the basic technologies underlying the SDK:

  • The client libraries use the Cumulocity REST interfaces as underlying communication protocol as described in the section on REST.
  • All examples and libraries are open source, check https://bitbucket.org/m2m.

JavaDoc for the Java Microservice SDK can be found on our resources site.

General prerequisites

To use the Java SE client libraries, you need to have at least Version 6 of the Java Development Kit for your operating system. Some of the examples require Java 7. Java 8 is not supported and some features may not work correctly with Java 8. To verify the version of your Java Development Kit, type

$ javac -version

The output needs to show a version number later than "1.6.0_24" for the basic examples.

Hello microservice!

This section shows you how to create a microservice that can be run on cumulocity.com, using Cumulocity Microservice SDK.

Prerequisites

Create an account on cumulocity.com, for example by using a free trial. At this step you will be provided with a dedicated URL address.

Verify, that you have Maven 3 installed with Java (7+):

$ mvn -v
Apache Maven 3.1.1 (0728685237757ffbf44136acec0402957f723d9a; 2013-09-17 17:22:22+0200)
Maven home: /usr/local/Cellar/maven/3.1.1/libexec
Java version: 1.7.0_45, vendor: Oracle Corporation
Java home: /Library/Java/JavaVirtualMachines/jdk1.7.0_45.jdk/Contents/Home/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "mac os x", version: "10.9.4", arch: "x86_64", family: "mac"

Info: Maven can be downloaded from http://maven.apache.org.

Verify the docker installation:

Cumulocity hosts linux/amd64 docker containers and not Windows containers. The docker version must be >= 1.12.6

$ docker version
Client:
 Version:         1.12.6
 API version:     1.24
 OS/Arch:         linux/amd64

Server:
 Version:         1.12.6
 API version:     1.24
 OS/Arch:         linux/amd64

Developing the "Hello, world!" agent

To develop a very simple "Hello, world!" agent for Cumulocity, you need to

  • create a Maven project,
  • add a dependency to the Cumulocity Microservice SDK library to the Maven pom.xml,
  • create a Java application,
  • configure the microservice,
  • configure the build,
  • build and run the Java application.

Creating a Maven project

To create a plain Java project with Maven, run

$ mvn archetype:generate -DgroupId=c8y.example -DartifactId=hello-world-microservice -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

This will create a folder "hello-world-microservice" in the current directory with a skeleton structure for your project.

Adding the Java Microservice library

Edit the "pom.xml" in the "hello-world-microservice" folder. Add a repositories and a pluginRepositories element to point to the Cumulocity Maven repository, which stores the client libraries.

<repositories>
    <repository>
        <id>cumulocity</id>
        <layout>default</layout>
        <url>http://download.cumulocity.com/maven/repository</url>
    </repository>
</repositories>
<pluginRepositories>
    <pluginRepository>
        <id>public</id>
        <url>http://download.cumulocity.com/maven/repository</url>
    </pluginRepository>
</pluginRepositories>

Add dependency elements for the Java Microservice SDK library (microservice-autoconfigure) to the dependencies section.

<dependency>
    <groupId>com.nsn.cumulocity.clients-java</groupId>
    <artifactId>microservice-autoconfigure</artifactId>
    <version>${c8y.version}</version>
</dependency>

Edit the version elements to use the latest version of the client library. The version can be determined by checking the Announcements section of the Cumulocity Help Center. The full file after editing can be found here.

Creating a Java application

Edit the "App.java" file in the folder "hello-world-microservice/src/main/java/c8y/example" with the following content:

package c8y.example;

import com.cumulocity.microservice.autoconfigure.MicroserviceApplication;
import org.springframework.boot.SpringApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@MicroserviceApplication
@RestController
public class App{
  public static void main(String[] args) {
      SpringApplication.run(App.class, args);
  }

  @RequestMapping("hello")
  public String greeting(@RequestParam(value = "who", defaultValue = "world") String who) {
      return "hello " + who + "!";
  }
}

@MicroserviceApplication - is a simple way to add required behavior for Cumulocity Microservice, including:

  • security
  • subscription
  • health indicator
  • context
  • internal platform API
  • spring boot application

@RequestMapping - opens an endpoint for greeting.

Configuring the microservice

Add an "application.properties" file to the "src/main/resources" directory with the following properties:

application.name=hello-world
server.port=80

Add a "cumulocity.json" file to the "src/main/configuration" directory with the following content:

{
"apiVersion":"1",
"version":"@project.version@",
"provider": {
  "name":"Cumulocity GmbH"
  },
  "isolation":"MULTI_TENANT",
  "requiredRoles": [
  ],
  "roles":[
  ]
}

This file is required to deploy the microservice in the Cumulocity infrastructure.

Configuring the build

To create a deployable ZIP file, you need to add the following to your .pom file:

<properties>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
    <spring-boot-dependencies.version>1.5.7.RELEASE</spring-boot-dependencies.version>
    <c8y.version>9.8.0</c8y.version>
</properties>

<dependencies>
    <dependency>
        <groupId>com.nsn.cumulocity.clients-java</groupId>
        <artifactId>microservice-autoconfigure</artifactId>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <!-- microservice api -->
        <dependency>
            <groupId>com.nsn.cumulocity.clients-java</groupId>
            <artifactId>microservice-dependencies</artifactId>
            <version>${c8y.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>${spring-boot-dependencies.version}</version>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>com.nsn.cumulocity.clients-java</groupId>
            <artifactId>microservice-package-maven-plugin</artifactId>
            <version>${c8y.version}</version>
            <executions>
                <execution>
                    <id>package</id>
                    <phase>package</phase>
                    <goals>
                        <goal>package</goal>
                    </goals>
                    <configuration>
                        <name>hello-world</name>
                        <image>hello-world</image>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>    

Building the microservice

To build the ZIP file, use the following command:

$mvn clean install

After a successful build you will be provided with a ZIP file in the target directory. The ZIP can be deployed to the platform as described in the Deployment section.

Running microservice locally

In order to test the microservice for the calls from the microservice to Cumulocity, you can run the docker container locally.

To verify calls from Cumulocity to the microservice, the microservice must be deployed.

To run a microservice which uses Cumulocity API locally you need the following:

  • URL address of the Cumulocity host of your tenant
  • Authorization header = "Basic {Base64({username}:{password})}"
  • Tenant - tenant ID

Step 1 - Create application

If the application does not exist, create a new application on a platform:

POST {URL}/application/applications

HEADERS:

"Authorization": "{AUTHORIZATION}"
"Content-Type": "application/vnd.com.nsn.cumulocity.application+json"
"Accept: application/vnd.com.nsn.cumulocity.application+json"

BODY:

{
        "name": "{APPLICATION_NAME}",
        "type": "MICROSERVICE",
        "key": "{APPLICATION_NAME}-microservice-key"
}

Example:

$curl -X POST -s \
  -d "{"name":"hello-microservice-1","type":"MICROSERVICE","key":"hello-microservice-1-key"}" \
  -H "Authorization: {AUTHORIZATION}" \
  -H "Content-Type: application/vnd.com.nsn.cumulocity.application+json" \
  -H "Accept: application/vnd.com.nsn.cumulocity.application+json" \
  "{URL}/application/applications"

Example response:

{
    "availability": "PRIVATE",
    "id": "{APPLICATION_ID}",
    "key": "{APPLICATION_NAME}-microservice-key",
    "manifest": {
        "imports": [],
        "noAppSwitcher": true
    },
    "name": "{APPLICATION_NAME}",
    "owner": {
        "self": "...",
        "tenant": {
            "id": "..."
        }
    },
    "requiredRoles": [],
    "roles": [],
    "self": "..",
    "type": "MICROSERVICE"
}      

If the application has been created correctly, you can get the application ID from the response.

Step 2 - Acquire microservice bootstrap user

GET {URL}/application/applications/{APPLICATION_ID}/bootstrapUser

HEADERS:

"Authorization": {AUTHORIZATION}
"Content-Type": application/vnd.com.nsn.cumulocity.user+json

Example response:

HTTP/1.1 200 Ok
Content-Type: application/vnd.com.nsn.cumulocity.user+json
{
  "tenant": "...",
  "name": "...",
  "password": "..."
}

Step 3 - Run microservice locally

The image is already added to the local docker repository during the build. List all the docker repository images available:

$ docker images

After you find the image in the list, run the docker container for the microservice by providing the baseurl and the bootstrap user credentials:

$ docker run -e C8Y_BASEURL={URL} -e C8Y_BOOTSTRAP_TENANT={BOOTSTRAP_TENANT} -e C8Y_BOOTSTRAP_USER={BOOTSTRAP_USERNAME} -e C8Y_BOOTSTRAP_PASSWORD={BOOTSTRAP_USER_PASSWORD} -e C8Y_MICROSERVICE_ISOLATION=MULTI_TENANT -i -t {DOCKER_REPOSITORY_IMAGE}:{TAG}

Step 4 - Subscribe to microservice

POST {URL}/tenant/tenants/{TENANT_ID}/applications

HEADERS:

"Authorization": "{AUTHORIZATION}"

BODY:

{"application":{"id": "{APPLICATION_ID}"}}

Example:

curl -X POST -d "{"application":{"id": "{APPLICATION_ID}"}}"  \
-H "Authorization: {AUTHORIZATION}" \
-H "Content-type: application/json" \
 "{URL}/tenant/tenants/{TENANT_ID}/applications"

Deployment

To deploy a microservice application on an environment you need the following:

  • URL address of the Cumulocity host of your tenant
  • Authorization header = "Basic {Base64({username}:{password})}"
  • Tenant - tenant ID
  • ZIP build from previous step for deployment

Step 1 - Create application

If the application does not exist, create a new application on a platform. For details, refer to the "Create application" step in Run microservice locally.

Step 2 - Upload ZIP file

POST {URL}/application/applications/{APPLICATION_ID}/binaries

HEADERS:

"Authorization": "{AUTHORIZATION}"
"Content-Type": "multipart/form-data"

Example:

  curl -F "data=@{PATH_TO_ZIP}" \
  -H "Authorization: {AUTHORIZATION}" \
  "{URL}/application/applications/{APPLICATION_ID}/binaries"

Step 3 - Subscribe to microservice

For details, refer to the "Subscribe to microservice" step in Run microservice locally.

Step 4 - Verify if microservice is running

Now you can verify if your application is running by executing

curl -H "Authorization: {AUTHORIZATION}" \
  {URL}/service/hello-world/hello?who=me

The expected result is:

hello me!

Improving the microservice

Now that you have done your first step, check out the section Developing Java Microservice.

Developing Microservices

This document describes microservice SDK features, including annotations, services, configuration files, logging and maven build plugin.

Overview

There are two possible deployment types on the platform:

  • Hosted deployment - the default for microservices. For typical use cases the hosted deployment is the suggested one.
  • External/legacy deployment - requires custom installation of the platform and agent.

For development and testing purposes one can deploy a microservice on a local docker.

Annotations

The simplest way to add required behavior to your application is to annotate a main class with @MicroserviceApplication.

This is a collective annotation consisting of:

  • @SpringBootApplication - comes from spring boot auto configure package
  • @EnableContextSupport - is required to use @UserScope, or @TenantScope scopes for method invocations
  • @EnableHealthIndicator - provides standard health endpoint used by the platform to monitor microservice availability
  • @EnableMicroserviceSecurity - provides standard security mechanism, verifying user and roles against the platform
  • @EnableMicroserviceSubscription - is responsible for subscribing microservices to the platform, updating metadata and listen to tenant subscription change events
  • @EnableMicroservicePlatformInternalApi - injects the platform API services into spring context for a microservice to use

Context support

The following section describes context support as utility tool for the user management described in General aspects of microservices in Cumulocity.

@UserScope and @TenantScope at type level annotation indicate that a bean created from class will be created in the scope defined. The user scope implies using tenant platform user credentials for platform calls. The tenant scope implies using service user credentials.

Example of injecting a bean into the tenant scope is available in the platform API module as follows:

@TenantScope
public EventApi eventApi(Platform platform) throws SDKException {
    return platform.getEventApi();
}  

And then sample utilization of the bean can be as follows:

@Autowired
private PlatformProperties platformProperties;
@Autowired
private ContextService<MicroserviceCredentials> contextService;
@Autowired
private EventApi eventApi;

public PagedEventCollectionRepresentation get10Events() {
    return contextService.callWithinContext(
            (MicroserviceCredentials) platformProperties.getMicroserviceBoostrapUser()
            , new Callable<PagedEventCollectionRepresentation>(){
        public PagedEventCollectionRepresentation call(){
            return eventApi.getEvents().get(10);
        }
    });
}

Microservice security

The @EnableMicroserviceSecurity annotation sets up the standard security configuration for microservices, which requires basic authorization for all endpoints (except for health check endpoint configured using @EnableHealthIndicator). A developer can secure its endpoints using standard spring security annotations e.g. @PreAuthorize("hasRole('ROLE_A')") and user's permissions will be validated against user's roles stored on the platform.

Microservice subscription

The microservice subscription module is responsible for two main features:

  • registration
  • tenant subscription event listening

The default behavior for the package is self-registration, which means that after you run the application it will try to register and use generated credentials for the communication with the platform. The self-registration is required to correctly deploy the microservice on the platform.

The other way to register an application to the platform is to do it manually by creating a new application on the platform with the same application name and providing the following properties into the microservice:

application.name={application_name}
C8Y.bootstrap.register=false
C8Y.bootstrap.tenant={tenant}
C8Y.bootstrap.user={user}
C8Y.bootstrap.password={password}

To create an application and acquire credentials, refer to:

The subscription package provides means to monitor and act upon changes in tenant subscriptions to a microservice. To add a custom behavior a developer can add an event listener for MicroserviceSubscriptionAddedEvent and MicroserviceSubscriptionRemovedEvent like in the following example:

@EventListener
public void onAdded(MicroserviceSubscriptionAddedEvent event{
    log.info("subscription added for tenant: " + event.getCredentials().getTenant());
}

On application startup the MicroserviceSubscriptionAddedEvent is triggered for all subscribed tenants.

Platform API

The package consists of a number of services that are build and injected into spring context. A developer can use them to perform basic operations against the platform. The beans are built based on properties read from a file. For hosted deployment, most of the properties are provided by the platform.

The API provides the following services:

  • Alarm - AlarmApi
  • AuditRecord - AuditRecordApi
  • CepModule - CepApi
  • Operation - DeviceControlApi
  • Event - EventApi
  • ExternalID - IdentityApi
  • Binary - BinariesApi
  • ManagedObject - InventoryApi
  • Measurement - MeasurementApi

The API provides basic CRUD methods, see alarm interface example below:

AlarmRepresentation create(final AlarmRepresentation alarm)
Future createAsync(final AlarmRepresentation alarm)

AlarmRepresentation getAlarm(final GId gid)
AlarmCollection getAlarms()
AlarmCollection getAlarmsByFilter(final AlarmFilter filter)

AlarmRepresentation update(final AlarmRepresentation alarm)

Sample usage:

@Autowired
private AlarmApi alarms;

public AlarmRepresentation addHelloAlarm(){
      AlarmRepresentation alarm = new AlarmRepresentation();
      alarm.setSeverity("CRITICAL");
      alarm.setStatus("Hello");
      return alarms.create(alarm);
}

Configuration files

The property file used by the hosted deployment must be located in src/main/resources/application.xml.

For external/legacy deployment, the following paths will be searched in order to find a property file specific for the environment the application is run on:

  • {UPPERCASE(application_name)}_CONF_DIR/.{application_name}
  • {UPPERCASE(application_name)}_CONF_DIR/{application_name}
  • {user/home}/.{application_name}
  • {user/home}/{application_name}
  • {CONF_DIR}/.{application_name}
  • {CONF_DIR}/{application_name}
  • /etc/{application_name}

Properties used by a microservice are:

application.name - Application name
C8Y.bootstrap.register - Indicates whether microservice should follow self-registration process. True by default
C8Y.baseURL - Address of the platform. Provided by the deployment process
C8Y.baseURL.mqtt - Address of the MQTT service. Provided by the platform
C8Y.bootstrap.tenant - Microservice owner tenant
C8Y.bootstrap.user - User used by microservice, or by microservice registration process
C8Y.bootstrap.password - Password used by microservice, or by microservice registration process
C8Y.bootstrap.delay - Subscription refresh delay
C8Y.bootstrap.initialDelay - Initial subscription delay
C8Y.microservice.isolation - Microservice isolation. Only PER_TENANT or MULTI_TENANT values are available. MULTI_TENANT by default

Logging

For hosted deployment the standard output should be used.

For external/legacy deployment logging into the application implies using spring logging described in this article.

The following locations are searched for log-back file:

  • {UPPERCASE(application_name)}_CONF_DIR/.{application_name}/logging.xml
  • {UPPERCASE(application_name)}_CONF_DIR/{application_name}/logging.xml
  • {user/home}/.{application_name}/logging.xml
  • {user/home}/{application_name}/logging.xml
  • {CONF_DIR}/.{application_name}/logging.xml
  • {CONF_DIR}/{application_name}/logging.xml
  • /etc/{application_name}/logging.xml

Maven plugin

The package module provides a maven plugin to prepare a ZIP file required by the microservice deployment, with simple configuration. The build requires an executable jar. To create one, a developer can use spring-boot-maven-plugin.

An example with minimum configuration is presented below:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <executions>
        <execution>
            <goals>
                <goal>repackage</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <mainClass>${main.class}</mainClass>
    </configuration>
</plugin>
<plugin>
    <groupId>com.nsn.cumulocity.clients-java</groupId>
    <artifactId>microservice-package-maven-plugin</artifactId>
    <version>9.0.0</version>
    <executions>
        <execution>
            <id>package</id>
            <phase>package</phase>
            <goals>
              <goal>package</goal>
            </goals>
            <configuration>
              <name>hello-world</name>
              <encoding>UTF-8</encoding>
              <rpmSkip>true</rpmSkip>
              <containerSkip>false</containerSkip>
            </configuration>
        </execution>
        <execution>
            <id>microservice-package</id>
            <phase>package</phase>
            <goals>
              <goal>microservice-package</goal>
            </goals>
            <configuration>
              <name>hello-world</name>
              <image>hello-world</image>
              <encoding>UTF-8</encoding>
              <skip>false</skip>
            </configuration>
        </execution>
    </executions>
</plugin>

Package goal

The package plugin is responsible for creation of a docker container, rpm file and for creating a ZIP file, that can be deployed on the platform. It can be configured with the following parameters:

  • name (alias package.name) - defaults to project.artifactId
  • description (alias package.description) - defaults to project.description
  • jvmArgs (alias agent-package.jvmArgs) - jvm-gc arguments. The default value is -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+ScavengeBeforeFullGC -XX:+CMSScavengeBeforeRemark". Will be overwritten if other options are provided.
  • arguments (alias agent-package.arguments) - arguments passed on Java application startup
  • encoding (alias project.build.sourceEncoding) - defaults to UTF-8
  • heap (alias agent-package.heap) - defaults to min = 128MB max = 384MB
  • perm (alias agent-package.perm) - defaults to min = 64MB max = 128MB
  • skip (alias skip.agent.package) - to skip the whole packaging part
  • rpmSkip (alias skip.agent.package.rpm) - to skip rpm file creation. False by default
  • containerSkip (alias skip.agent.package.container) - to skip docker image creation. True by default
  • manifestFile - points to a manifest file location. Default value: ${basedir}/src/main/configuration/cumulocity.json

Example configuration:

<configuration>
  <name>hello-world</name>
  <encoding>UTF-8</encoding>
  <rpmSkip>true</rpmSkip>
  <containerSkip>false</containerSkip>
  <manifestFile>${basedir}/src/main/microservice/cumulocity.json</manifestFile>
</configuration>

Push goal

The push plugin is responsible for pushing the docker image to a registry. The registry can be configured by:

  • containerSkip (alias skip.agent.package.container) - prevents the push to execute. True by default
  • registry (alias agent-package.container.registry) - docker registry address

Example configuration:

    <configuration>
      <registry>http://{yourregistry.com}</registry>
      <containerSkip>false</containerSkip>
    </configuration>

Upload goal

Microservice upload goal is responsible for deploying the microservice to a server.

We have three options to configure server url and credentials:

  • settings.xml - maven global configuration placed at ~/.m2/settings.xml
  • pom.xml - maven project configuration file
  • command line

All three ways can be used together, i.e. goal partially can be configured in settings.xml and partially in pom.xml. In case of conflicts the command line configuration has the highest priority and settings xml configuration the lowest.

To upload a microservice to the server you need to configure the following properties:

  • url - Mandatory URL that will be used for deployment. Empty by default.
  • username - Mandatory tenant name and user name used for authorization. Empty by default.
  • password - Mandatory password used for authorization. Empty by default.
  • name - Optional name of uploaded application. By default the same as "package.name" property or "artifactId" if "package.name" is not provided.

settings.xml

To configure the goal in the settings.xml file we need to add the server configuration as follows:

<server>
    <id>microservice</id>
    <username>demos/username</username>
    <password>******</password>
    <configuration>
        <url>https://demos.cumulocity.com</url>
    </configuration>
</server>

pom.xml

To configure the plugin in the pom.xml file we need to add the server configuration as follows.

<plugin>
    <groupId>com.nsn.cumulocity.clients-java</groupId>
    <artifactId>microservice-package-maven-plugin</artifactId>
    <configuration>
        <application>
            <name>cep</name>
        </application>

        <!-- please note that the credentials are optional if they are already configured in settings.xml -->
        <credentials>
            <url>https://demos.cumulocity.com</url>
            <username>demos/username</username>
            <password>******</password>
        </credentials>
    </configuration>
</plugin>
Command line

To pass the configuration only to the particular build, run

mvn microservice:upload -Dupload.application.name=cep -Dupload.url=https://demos.cumulocity.com -Dupload.username=demos/username -Dupload.password=******

Deployment

Hosted deployment

**Info**: For your convenience we have prepared a utility deployment script available [here](/guides/reference/microservice-package).

To deploy an application on an environment you need the following:

  • URL address of your tenant
  • Authorization header = "Basic {Base64({username}:{password})}"
  • Tenant - tenant ID
  • ZIP build from previous step

Step 1 - Create application

If the application does not exist, create a new application on the platform:

POST /application/applications
Host: ...
Authorization: Basic xxxxxxxxxxxxxxxxxxx
Content-Type: "application/json"

BODY:

{
        "name": "{APPLICATION_NAME}",
        "type": "MICROSERVICE",
        "key": "{APPLICATION_NAME}-microservice-key"
}

Example:

$curl -X POST -s \
  -d "{"name":"hello-microservice-1","type":"MICROSERVICE","key":"hello-microservice-1-key"}" \
  -H "Authorization: {AUTHORIZATION}" \
  -H "Content-type: application/json" \
  "{URL}/application/applications"

If the application has been created correctly, you can get the application ID by invoking:

GET /application/applicationsByName/{APPLICATION_NAME}
Host: ...
Authorization: Basic xxxxxxxxxxxxxxxxxxx
Accept: "application/json"

Example:

curl -H "Authorization:{AUTHORIZATION}" \
 {URL}/application/applicationsByName/hello-world

Step 2 - Upload zip file

POST /application/applications/{APPLICATION_ID}/binaries
Host: ...
Authorization: Basic xxxxxxxxxxxxxxxxxxx
Content-Type: "multipart/form-data"

Example:

  curl -F "data=@{PATH_TO_ZIP}" \
  -H "Authorization: {AUTHORIZATION}" \
  "{URL}/application/applications/{APPLICATION_ID}/binaries"

Step 3 - Subscribe to microservice

POST /tenant/tenants/$TENANT/applications
Host: ...
Authorization: Basic xxxxxxxxxxxxxxxxxxx
Content-Type: "multipart/form-data"

BODY:

{"application":{"id": "{APPLICATION_ID}"}}

Example:

curl -X POST -d "{"application":{"id": "{APPLICATION_ID}"}}"  \
-H "Authorization: {AUTHORIZATION}" \
-H "Content-type: application/json" \
 "{URL}/tenant/tenants/{TENANT}/applications"

Local docker deployment

To deploy the application on a local docker, one needs to inject the environment variables into a container. This is done via the docker run -e parameter. The full description of available parameters is available in Microservice runtime > Environment variables in the Reference guide.

An example execution could be:

docker run -e "C8Y_BASEURL={C8Y_BASEURL}" -e "C8Y_BASEURL_MQTT={C8Y_BASEURL_MQTT}" {IMAGE_NAME}

Monitoring

To check if a hosted microservice is running successfully, the microservice's health endpoint can be checked. This endpoint is enabled by default for all microservices that are developed using Java Microservice SDK.

GET {URL}/service/{APPLICATION_NAME}/health

Example response:

HTTP/1.1 200 
{
  "status":"UP"
}

or

HTTP/1.1 503
{
  "status":"DOWN"
}

Developing Java clients for services

This section describes the Cumulocity Email and SMS API and shows how to access them using the Cumulocity Java Client.

Using the services platform

The "services platform interface" is responsible for connecting to the Services (SMS) API from Java.

ServicesPlatform platform = new ServicesPlatformImpl("<<URL>>", new CumulocityCredentials("<<tenant>>", "<<user>>", "<<password>>", "<application key>"));

The URL pointing to the platform must be of the form {tenant}.cumulocity.com, for example https://demos.cumulocity.com, which will process all the API requests.

Info: You need to have appropriate credentials to be able to access the Services API from outside, see example above.

Accessing the SMS Messaging API

In the following section you will learn how to send and receive SMS messages via the Java Client API.

The following code snippet shows how to obtain a handle to the SMS API from Java:

SmsMessagingApi smsMessagingApi = platform.getSmsMessagingApi();

Using this handle, you can send and retrieve the SMS messages from Java by calling its functions.

Prerequisites

Assigning required roles

To use the SMS messaging API the user should have the required roles such as 'SMS_ADMIN' for sending and 'SMS_READ' for receiving messages.

Refer to Administration > Managing permissions in the User guide.

Choosing a SMS provider

OpenIT

OpenIT credentials can be assigned using the Administration application. Click OpenIT credentials in the navigator and save these credentials for your tenant.

OpenIT Credentials

Note that receiving messages and receiving specific messages are not supported for this provider.

Jasper Control Center

Refer to Jasper Control Center for information about how to set the credentials.

Ericsson

For Ericsson, use our Rest API to store tenant options separately for each key:

POST /tenant/options
Host: ...
Authorization: Basic ...

Provider:

  {
    "category": "messaging",
    "key": "provider",
    "value": "ericsson-dcp"
  }

Base URL:

  {
    "category": "messaging",
    "key": "ericsson-dcp.baseUrl",
    "value": "<url>"
  }

Username:

  {
    "category": "messaging",
    "key": "ericsson-dcp.username",
    "value": "<username>"
  }

Password:

  {
    "category": "messaging",
    "key": "ericsson-dcp.password",
    "value": "<password>"
  }

Sender address:

  {
    "category": "messaging",
    "key": "sms.senderAddress",
    "value": "<The phone number all SMS will be sent from (provided by Ericsson DCP)>"
  }

Sender name:

  {
    "category": "messaging",
    "key": "sms.senderName",
    "value": "<The name associated with the phone number>"
  }

Note that receiving specific messages is not supported for this provider.

Telia Sonera

For Telia Sonera, use our Rest API to store tenant options separately for each key:

POST /tenant/options
Host: ...
Authorization: Basic ...

Provider:

  {
    "category": "messaging",
    "key": "provider",
    "value": "soneraoma"
  }

Username of Telia Sonera Client Application:

  {
    "category": "messaging",
    "key": "soneraoma.username",
    "value": "<username>"
  }

Password assigned for Telia Sonera Client Application:

  {
    "category": "messaging",
    "key": "soneraoma.password",
    "value": "<password>"
  }

Telia Sonera OAUTH Service Endpoint:

  {
    "category": "messaging",
    "key": "soneraoma.authUrl",
    "value": "<OAUTH Service endpoint url as appears in TS Application Profile, e. g., https://api.sonera.fi/autho4api/v1>"
  }

Telia Sonera Messaging OMA v1 Endpoint:

  {
    "category": "messaging",
    "key": "soneraoma.messagingUrl",
    "value": "<Messaging endpoint url as appears in TS Application Profile, e. g., https://api.sonera.fi/sandbox/messaging/v1>"
  }

Note that receiving messages and receiving specific messages is not supported for this provider.

Tropo

For Tropo, use our Rest API to store tenant options separately for each key

POST /tenant/options
Host: ...
Authorization: Basic ...

Provider:

  {
    "category": "messaging",
    "key": "provider",
    "value": "tropo"
  }

Base URL:

  {
    "category": "messaging",
    "key": "tropo.baseUrl",
    "value": "<url>"
  }

Credentials:

  {
    "category": "messaging",
    "key": "tropo.credentials",
    "value": "<credentials>"
  }

Sender address:

  {
    "category": "messaging",
    "key": "sms.senderAddress",
    "value": "cumulocity"
  }

Sender name:

  {
    "category": "messaging",
    "key": "sms.senderName",
    "value": "cumulocity"
  }

Note that receiving messages and receiving specific message is not supported for this provider.

Sending a message

To send a SMS message using the API, prepare the message with the "send message request builder" and call the "send message" function of the API with the message.

SendMessageRequest smsMessage = SendMessageRequest.builder()
        .withSender(Address.phoneNumber("<phone number>"))
        .withReceiver(Address.phoneNumber("<phone number>"))
        .withMessage("<message text>")
        .build();

smsMessagingApi.sendMessage(smsMessage);

Receiving all messages

Not every SMS provider supports receiving messages.

To receive all SMS messages you can use the API as follows:

smsMessagingApi.getAllMessages(Address.phoneNumber("<phone number>"));

Receiving a specific message

Not every SMS provider supports receiving messages.

To receive a specific SMS message you can use the API as follows:

smsMessagingApi.getMessage(Address.phoneNumber("<phone number>"), "<message id>");

SMS management endpoints

To accomplish the same behaviour, Rest API can be used.

Sending message:

POST /service/messaging/smsmessaging/outbound/tel:<sender phone number>/requests
Host: ...
Authorization: Basic ...
Content-Type: application/json
{
    "outboundSMSMessageRequest": {
    "address": ["tel:<phone number>"],
    "senderAddress": "tel:<phone number>",
    "outboundSMSTextMessage": {
        "message": "<message text>"
    },
    "receiptRequest": {
        "notifyUrl": <notify url>,
        "callbackData": <callback data>
    },
    "senderName": <sender name>
    }
}

Receiving all messages:

GET /service/messaging/smsmessaging/inbound/registrations/tel:<receiver phone number>/messages
Host: ...
Authorization: Basic ...

HTTP/1.1 200 OK
{
     "inboundSMSMessageList": [
        {
            "inboundSMSMessage": {
            "dateTime": "<date>",
            "destinationAddress": "<destination address>",
            "messageId": "<message id>",
            "message": "<message>",
            "resourceURL": "<resource url>",
            "senderAddress": "<sender address>"
        }
     ]
}

Receiving a specific message:

GET /service/messaging/smsmessaging/inbound/registrations/tel:<receiver phone number>/messages/<message id>
Host: ...
Authorization: Basic ...

HTTP/1.1 200 OK
{
    "inboundSMSMessage": {
        "dateTime": "<date>",
        "destinationAddress": "<destination address>",
        "messageId": "<message id>",
        "message": "<message>",
        "resourceURL": "<resource url>",
        "senderAddress": "<sender address>"
    }
}

Troubleshooting

This section describes common problems and their solutions.

SSL or certificate errors

You can use both HTTP and HTTPS from the Java client libraries. To use HTTPS, you may need to import the Cumulocity production certificate into your Java runtime environment. Download the certificate and import it using the following command on the command line:

$JAVA_HOME/bin/keytool -import -alias cumulocity -file cumulocity.com.crt -storepass changeit

Answer "yes" to the question "Trust this certificate? [no]:".

Use the following argument to run Java:

-Djavax.net.ssl.trustStore=<<home directory>>/.keystore

If you use Eclipse/OSGi, open the Run Configurations... dialog in the Run menu. Double-click OSGi Framework, then open the Arguments tab on the right side. In the VM arguments text box, add the above parameter.

Since Java ships with its own set of trusted root certificates, you might still get the error message:

java.security.cert.CertificateException: Certificate Not Trusted

In this case, make sure that the Go Daddy Certificate Authority (CACert) is available for your JAVA environment using:

keytool -import -v -trustcacerts -alias root -file gd_bundle.crt -keystore $JAVA_HOME/lib/security/cacerts

gd_bundle.crt can be downloaded directly from the GoDaddy repository.

When I install the SDK, Eclipse complains about compatibility problems

Make sure that you use the "Target Platform" preferences page to install the SDK as described in the instructions. "Install New Software" installs software into your running Eclipse IDE, but we need to install the SDK as a separate server software.

"Expected to find an object at table index" when running an agent or application

This error occurs due to a bug in particular Eclipse versions. As a workaround, select Run from the main menu and then Run Configurations .... On the left, select the launch configuration that you have been using, e.g. OSGi Framework. On the right, click the Arguments tab. Append a " -clean" to the Program Arguments and click Apply.

The agent or application won't start

Check if all required plug-ins are checked in your launch configuration. Go to Run > Run Configurations and select the OSGi Framework launch configuration. Click Select All and try running again.

Check if the required plug-ins are started. While the application or agent is running, type "ss" into the console and hit the return key. All listed plug-ins should be either in the ACTIVE or RESOLVED state.

Check if you are using the correct target platform. Go to the Target Platform page in the preferences and check if "Cumulocity runtime" is checked.

The agent will not compile, I get "Access Restriction" messages

This error may be caused because of a missing package import. Navigate to the Dependencies tab of the project manifest file and check if the package of the type that contains the method giving the access restriction is present in the Import-Package section.

You can find the package by opening the declaration of the method (right-click and select Open Declaration from the context menu).

When starting an application, I get "address already in use" messages

Check if you are running another instance of the application. Click on the Display Selected Console icon in the console toolbar (the terminal icon) to browse through your consoles. Terminate other running instances by clicking the red Stop icon in the toolbar.

Under Unix/MacOSX you can also use the lsof command to see which process is using a particular port. For example, to see which process is using TCP port 8080 enter:

lsof -i tcp:8080

which will return something like

COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME java 12985 pitchfor 45u IPv6 0x077c76d0 0t0 TCP *:8080 (LISTEN)

so process 12985 is using that port which can then be killed if necessary.