Invoking REST APIs in Java

PART 4. USING EVERYWARE™ CLOUD WITH REST APIs
Invoking REST APIs in Java

 

Invoking REST APIs in Java

·         Overview

·         Prerequisites

Import REST Client Project

·         Set Cloud Client Variables

Using Java REST Application

·         Starting Cloud Connection

·         Reading Data using REST

o   List Accounts

o   List Devices

o   List Topics

o   List Metrics

o   Count Messages

o   List Messages

·         Publish and Store Data with REST

o   Create Rule Using REST API

o   Publish Using REST API

o   Store Data Using REST API

o   Read Recent Messages

o   Delete Rule through REST

 

 


 

Invoking REST APIs in Java

Overview

While it is possible to use REST APIs as URLs in a Web browser, a more powerful use of REST comes from programmatic access to the Cloud data store.  In this section, we will demonstrate how to write a Java application to both send and receive data using REST APIs.

 

This document only gives some samples of REST APIs in use on the Everyware™ Cloud.  For more complete reference information on each of the supported APIs and their options, see the following API documentation: https://api-sandbox.everyware-cloud.com/docs/index.html

 

In this tutorial, you will:

  • Create sample Java project to demonstrate sample REST API calls
  • Query the cloud for Metric and other data
  • Publish data to the cloud
  • Push data directly into the data store
  • Create and delete Rules

 

This tutorial assumes you are using Eurotech’s “Sandbox” broker, which is used for customers with development systems, and uses Web URLs starting with: “https://api-sandbox.everyware-cloud.com/v2/”.  If you are using the Production broker, you will have a different URL, which should be substituted in place of the URLs described in this document. 

 

 

Prerequisites

The Everyware Cloud example code is available on the GitHub repository at https://github.com/eurotech/edc-examples/.  Make sure before continuing with this example that you have set up your Eclipse workspace, installed Maven, and downloaded the example code (see Setting up Eclipse Environment for Java). 

 

 


 

Import REST Client Project

 

In Eclipse, select File | Import if you have not already imported the “edc-rest” example project.  Select “General | Existing Projects into Workspace,” then click Next.  Click Browse for the root directory, and browse to the workspace location of the cloud examples that were downloaded in the Eclipse setup section.  Select the “edc-rest” project folder, but do not select the checkbox “Copy projects into workspace” (the projects are already in the workspace location).  (If you wish, you may import all projects, but this tutorial will only discuss the REST client.)  You may add the project to a working set if desired.  Then click Finish.

 

 

 

You should now have the “edc-rest” project in your workspace, and it should not show any build errors.

 

 

NOTE: If you delete the project out of the workspace later, you should not “Delete project contents on disk.”  This is because we have used the Maven install procedures to setup the projects directly into your Eclipse workspace location.  If you do delete the contents on disk, you would need to create a new workspace and re-download the source code from Eurotech’s software repository, as described in Setting up Eclipse Environment for Java.

 

 


 

Set Cloud Client Variables

Toward the top of the code example, there are several variables noted with comments, which are specific to your Cloud user account.  These variables need to be modified according to your Cloud account credentials, so the REST client can connect properly.  See the section Accessing your Cloud Account to set up an account in Everyware Cloud.

 

In the sample code, set the following variables with the proper settings of your Cloud broker account, and a valid TEST_EMAIL address at which you can receive e-mails.  The e-mail sent from the Cloud as a result of the REST rule will come from edc-alerts@eurotech.com, in case your e-mail filter needs to be configured.  Then save changes in the sample application.

 

 

    // >>>>>> Set these variables according to your Cloud user account

       public static final String API_URL = "https://api-sandbox.everyware-cloud.com/v2/";      // URL for API connection

       public static final String ACCOUNT = "myEdcAccount";                       // Cloud account name

       public static final String USERNAME = "myEdcUserName";               // Username in account, requires Administrative permissions

       public static final String PASSWORD = "myEdcPassword3#";                   // Password associated with Username

       public static final String CLIENT_ID = "EdcTest-Device";                   // Unique Client ID of this client device

       public static final String TEST_EMAIL = "my.name@domain.com";        // E-mail address to use for this sample application

       public static final String TEST_EMAIL2 = "rule.changed@domain.com"// E-mail address to test rule update

    // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

 

 

 


 

Using Java REST Application

The sample Java application tests several REST API calls to demonstrate what can be accomplished with the APIs through program calls.  After going through this tutorial, you can modify the Java code to understand more fully how the client application works, and to send different data to the broker.

 

Before running this sample application, it is recommended (although not required) that you have previously run an MQTT Client application (such as the EDC Java client or C++ client) on this account.  This will publish data and metrics to the account, which can then be queried using REST.

 

 


 

Starting Cloud Connection

After the client variables have been modified, make a connection to the Cloud by selecting the Run menu, and the option “Run” or “Run as...Java Application”.  You can also select the green Run button  in the Launch toolbar.

 

If the variables are not set correctly, there will be an error in the console:

 

Exception in thread "main" java.lang.Exception:

Unable to connect to the cloud -- check your URL, username, and password in a browser to make sure you can log in.

URL: https://api-sandbox.everyware-cloud.com/v2/accounts.xml

at com.eurotech.cloud.examples.EdcRestExample.main(EdcRestExample.java:82)

 

 


 

Reading Data using REST

 

List Accounts

Assuming you have a successful connection to the broker, the next step in the sample application is to invoke a REST API to read account data from the Eurotech Cloud data store.  The following examples are specific to the example code provided here, but you should see similar kinds of data returned.

 

First, the Account name is acquired.  Note that the “accounts.xml” is simply added as part of the URL in the Web client resource.  Note that the elements in the URL path are case-sensitive.

 

Your account name should be displayed in the Console window:

 

 

        String apiPath = "accounts.xml";

        WebResource apisWeb = client.resource(API_URL).path(apiPath);

        AccountsResult  result = apisWeb.get(AccountsResult.class);

        List<Account> accounts = result.getAccounts();

 

 

##############

 Beginning test of listAccounts()

Accounts.size(): 1

Account name: myEdcAccount

 


 

List Devices

The next REST API to be called gives a list of devices, which should be displayed in the Console window:

 

 

        String apiPath = "devices.xml";

        WebResource apisWeb = client.resource(API_URL).path(apiPath);

        DevicesResult result = apisWeb.get(DevicesResult.class);

        List<Device> devices = (List<Device>) result.getDevices();

 

 

##############

 Beginning test of listDevices()

Device.size(): 1

device- displayName:MyDisplayName lastEventOn:Tue Jun 12 13:40:13 CDT 2012

 


 

List Topics

The next REST API to be called lists the topics that have been published, and displays them in the Console window:

 

 

        String apiPath = "topics.xml";

        WebResource apisWeb = client.resource(API_URL).path(apiPath);

        TopicsResult result = apisWeb.get(TopicsResult.class);

        List<EdcTopicInfo> topics = (List<EdcTopicInfo>) result.getTopics();

 

 

##############

 Beginning test of listTopics()

 

TopicsResult.size(): 20

topic:myEdcAccount/+/# lastMessageOn:Tue Jun 12 16:44:20 CDT 2012

topic:myEdcAccount/+/apis/# lastMessageOn:Tue Jun 12 16:44:20 CDT 2012

topic:myEdcAccount/+/apis/test lastMessageOn:Tue Jun 12 16:44:20 CDT 2012

topic:myEdcAccount/+/pub/# lastMessageOn:Tue Jun 12 16:44:20 CDT 2012

topic:myEdcAccount/+/pub/test lastMessageOn:Tue Jun 12 16:44:20 CDT 2012

topic:myEdcAccount/+/rule/# lastMessageOn:Tue Jun 12 16:44:20 CDT 2012

topic:myEdcAccount/+/rule/test lastMessageOn:Tue Jun 12 16:44:20 CDT 2012

topic:myEdcAccount/+/sample/# lastMessageOn:Tue Jun 12 13:09:30 CDT 2012

topic:myEdcAccount/+/sample/data lastMessageOn:Tue Jun 12 13:09:30 CDT 2012

topic:myEdcAccount/MyEclipseClient/# lastMessageOn:Tue Jun 12 16:44:20 CDT 2012

topic:myEdcAccount/MyEclipseClient/apis/# lastMessageOn:Tue Jun 12 16:44:20 CDT 2012

topic:myEdcAccount/MyEclipseClient/apis/test lastMessageOn:Tue Jun 12 16:44:20 CDT 2012

topic:myEdcAccount/MyEclipseClient/pub/# lastMessageOn:Tue Jun 12 16:44:20 CDT 2012

topic:myEdcAccount/MyEclipseClient/pub/test lastMessageOn:Tue Jun 12 16:44:20 CDT 2012

topic:myEdcAccount/RulesAssistant/# lastMessageOn:Tue Jun 12 16:44:20 CDT 2012

topic:myEdcAccount/RulesAssistant/rule/# lastMessageOn:Tue Jun 12 16:44:20 CDT 2012

topic:myEdcAccount/RulesAssistant/rule/test lastMessageOn:Tue Jun 12 16:44:20 CDT 2012

topic:myEdcAccount/my-Device/# lastMessageOn:Tue Jun 12 13:09:30 CDT 2012

topic:myEdcAccount/my-Device/sample/# lastMessageOn:Tue Jun 12 13:09:30 CDT 2012

topic:myEdcAccount/my-Device/sample/data lastMessageOn:Tue Jun 12 13:09:30 CDT 2012

 


 

List Metrics

The next REST API to be called lists the metrics that have been published on a specified topic, and displays them in the Console window.  In this case, the “metrics/searchByTopic” is added to the URL, but then the “topic” query parameter is also added before invoking the API.

 

 

        String apiPath = "metrics/searchByTopic.xml";

        WebResource apisWeb = client.resource(API_URL).path(apiPath);

        apisWeb = apisWeb.queryParam("topic", topic);

        MetricsResult result = apisWeb.get(MetricsResult.class);

        List<EdcMetric> metrics = (List<EdcMetric>) result.getMetrics();

 

 

##############

 Beginning test of listMetrics(), search by topic: myEdcAccount/+/sample/data

MetricsResult.size(): 17

metric: arr base64Binary

metric: bool boolean

metric: counter int

metric: dbl double

metric: flt float

metric: int int

metric: long long

metric: position_altitude double

metric: position_heading double

metric: position_latitude double

metric: position_longitude double

metric: position_precision double

metric: position_satellite int

metric: position_speed double

metric: position_status int

metric: position_timestamp long

metric: str string

 


 

Count Messages

The next REST API to be called counts how many messages that have been received:

 

 

        String apiPath = "messages/count.xml";

        WebResource apisWeb = client.resource(API_URL).path(apiPath);

        CountResult result = apisWeb.get(CountResult.class);

 

 

##############

 Beginning test of getMessageCount()

Messages Count: 23

 


 

List Messages

The next REST API to be called lists a number of messages that have been published, and displays them in the Console window.  This method allows for several different types of queries for messages:

 

 

    /**

     * REST query for messages

     * @param topic            Enter a <code>String</code> to searchByTopic, or an empty String

     * @param limit            Enter non-zero int to limit number of messages to read

     * @param recentSeconds    Enter non-zero int to use startDate of number of seconds prior to current time

     */

    private static void listMessages(String topic, int limit, int recentSeconds) {

 

 

The printMessageMetric() method uses the built-in methods of the EdcMetric() object to display the contents of each metric contained within the message.

 

 

    private static void printMessageMetric(EdcMetric m) {

***

            System.out.println("metric: " + m.getName() + " " + m.getType() + " " + m.getValue());

***

    }

 

 

 

##############

 Beginning test of listMessages()

Message topic(): myEdcAccount/my-Device/sample/data

Received on: Tue Jun 12 13:39:03 CDT 2012

metric: str string this is a string

metric: arr base64Binary MTIz

metric: int int 100

metric: counter int 9

metric: flt float 0.0232339

metric: dbl double 0.7127557437880724

metric: bool boolean true

metric: long long 200000

(etc.)

 

 


 

Publish and Store Data with REST

The next section of the sample application uses REST APIs to create a rule.  The rule looks for a published message on a given topic, and upon matching the topic, it takes two actions: sends an e-mail to a specified e-mail account, and publishes a new message back to the Cloud using MQTT.  Then it uses an API to publish a message on the given topic, causing the rule to be triggered, stores another message directly into the message archive using a store API, and then reads back all messages thus created.  Finally, the rule that was created earlier is deleted.

 

The following sections describe these actions in a little more detail and give an example Console output of the sample application.

 

 

Create Rule Using REST API

In the Cloud Web console, rules can be created through the user interface.  However, the REST APIs allow all aspects of the Cloud account to be managed from a different application, apart from the Web console. 

 

First, the Java application uses the createRule() method to create the basic rule, including the query statement.  This is the same Statement as described in the Console user interface, and uses the Esper syntax.  Note that when coding the query statement in Java, double quotes  "   need to be escaped by using a leading backslash  \  character.

 

 

        // Create the rule

        RuleCreator ruleCreator = new RuleCreator();

        ruleCreator.setAccountId(accountID);

        ruleCreator.setName("APIs Test Rule Name");

        ruleCreator.setEnabled(true);

        ruleCreator.setDescription("APis Test Rule Description");

        ruleCreator.setQuery("select *, doubleMetric('pub_double_metric') as dbl from EdcMessageEvent where semanticTopic = \"pub/test\"");

 

 

After creating the rule, other Java methods are used to create one or more rule actions and add them to the rule configuration. 

 

To add an e-mail action to the rule, the parameters are set similarly to the user interface, using an array of name/value pairs.

 

 

        // Create e-mail action for the rule

        RuleActionConfiguration emailActionConfig = new RuleActionConfiguration();

        emailActionConfig.setRuleActionInfoName("email");

 

        List<Parameter> emailParams = new ArrayList<Parameter>();

        Parameter emailParam1 = new Parameter();

        emailParam1.setName("to");

        emailParam1.setValue(TEST_EMAIL);

        emailParams.add(emailParam1);

 

        Parameter emailParam2 = new Parameter();

        emailParam2.setName("subject");

        emailParam2.setValue("E-mail from REST rule");

        emailParams.add(emailParam2);

 

        Parameter emailParam3 = new Parameter();

        emailParam3.setName("body");

        emailParam3.setValue("This e-mail was generated in response to receiving a publish message on topic $semanticTopic, " + "containing metric pub_double_metric= $dbl");

        emailParams.add(emailParam3);

 

        ParametersMapType emailParamsMap = new ParametersMapType();

        emailParamsMap.setParameters(emailParams);

 

        emailActionConfig.setParameterValues(emailParamsMap);

 

 

However, to add an MQTT or REST action to a rule, the format is a little different.  With these actions, the list of metrics and values to include in the action are selected in the Web console using a tabular list.  When using this action in Java, the parameter argument takes the form of a JSON statement.  One easy way to code this is to create the rule in the Web console first.  Then use a Web browser to query the rules API.  This will show the proper form of the JSON statement for the ‘metrics’ parameter, which can then be copied into the Java code.  Again, any double quotes  "   need to be escaped by using a leading backslash  \  character.

 

 

        // Create publish action for the rule

        RuleActionConfiguration publishActionConfig = new RuleActionConfiguration();

        publishActionConfig.setRuleActionInfoName("mqtt");

 

        List<Parameter> publishParams = new ArrayList<Parameter>();

        Parameter publishParam1 = new Parameter();

        publishParam1.setName("topic");

        publishParam1.setValue("$account/RulesAssistant/rule/test");

        publishParams.add(publishParam1);

 

        Parameter publishParam2 = new Parameter();

        publishParam2.setName("metrics");

        publishParam2.setValue("{\"metrics\":[{\"name\":\"rule_string_metric\", \"value\":\"new_string\", \"type\":\"String\"},{\"name\":\"rule_double_metric\", \"value\":\"$dbl\", \"type\":\"Double\"}]}");

        publishParams.add(publishParam2);

 

        ParametersMapType publishParamsMap = new ParametersMapType();

        publishParamsMap.setParameters(publishParams);

 

        publishActionConfig.setParameterValues(publishParamsMap);

 

 

Then, add each of the actions to the RuleActionConfiguration(), and the rules API is invoked.

 

 

        // Add all actions to the rule

        List<RuleActionConfiguration> actionConfigs = new ArrayList<RuleActionConfiguration>();

        actionConfigs.add(emailActionConfig);

        actionConfigs.add(publishActionConfig);

        ruleCreator.setRuleActionConfigurations(actionConfigs);

 

        WebResource rulesWeb = client.resource(API_URL).path("rules.xml");

        rule = rulesWeb.accept(MediaType.APPLICATION_XML).type(MediaType.APPLICATION_XML).post(Rule.class, ruleCreator);

 

 

 

When the sample application is run in Eclipse, the rule is created, then it is read back to ensure that the rule was created correctly, which is indicated in the Console window:

 

##############

 Beginning test of createRule()

Created rule ID 10

Rule verified with ID, 10 and Query: select *, doubleMetric('pub_double_metric') as dbl from EdcMessageEvent where semanticTopic = "pub/test"

 

 


 

Publish Using REST API

Next, the Java application calls the restPublish() method.  This invokes a REST API to publish a message on a given topic.  The createPayload() method builds a payload with several metrics of different data types, including the metric named ‘pub_double_metric’.  The ‘publish’ resource of the ‘messages’ API is invoked to publish the message. 

 

 

        // PUBLISH a message to the broker

        String pubTopic = "/pub/test";

        WebResource apisWeb = client.resource(API_URL);

        EdcPayload payload = createPayload("pub");

        payload.setBody("PUBLISH - store data".getBytes());

 

        EdcMessage msg = new EdcMessage();

        msg.setTopic(ACCOUNT + "/" + ASSET_ID + pubTopic);

        msg.setTimestamp(new Date());

        msg.setEdcPayload(payload);

 

        WebResource messagesWebStore = apisWeb.path("messages").path("publish");

 

 

Here it is worthwhile to note the use of the ErrorBean().  If there is an error in an API call, the ErrorBean() class can be used to output additional diagnostic information on the cause of the API exception.

 

 

        try {

            messagesWebStore.type(MediaType.APPLICATION_XML).accept(MediaType.APPLICATION_XML).post(msg);

        }

        catch (UniformInterfaceException uie) {

            ErrorBean errorBean = uie.getResponse().getEntity(ErrorBean.class);

            System.out.println(errorBean.getMessage());

            throw uie;

        }

 

 

 

##############

 Beginning test of restPublish()

Created payload with metric 'pub_double_metric': 0.9302776398550006

Published message using REST on topic: /pub/test

 

This published message, once received in the Cloud account, triggers the actions contained in the rule that we created earlier.  The e-mail address specified in the variable TEST_EMAIL should receive a message sent automatically from the Cloud, and a new message with topic “$account/RulesAssistant/rule/test” will be published into the Cloud account.

 

 


 

Store Data Using REST API

The Java application then calls the restStore() method, which invokes a REST API to store a message directly into the database.  An EdcPayload() is created and added to the EdcMessage().  The ‘store’ resource of the ‘messages’ API is invoked to store the message.  The createPayload() method builds a payload with several metrics of different data types, including the metric named ‘api_double_metric’.

 

 

        // POST a message to the data store

        String storeTopic = "/apis/test";

        WebResource apisWeb = client.resource(API_URL);

        EdcPayload payload = createPayload("api");

        payload.setBody("POST - store data".getBytes());

 

        EdcMessage msg = new EdcMessage();

        msg.setTopic(ACCOUNT + "/" + ASSET_ID + storeTopic);

        msg.setTimestamp(new Date());

        msg.setEdcPayload(payload);

 

        WebResource messagesWebStore = apisWeb.path("messages").path("store");

        messagesWebStore.type(MediaType.APPLICATION_XML).accept(MediaType.APPLICATION_XML).post(msg);

 

 

 

##############

 Beginning test of restStore()

Created payload with metric 'api_double_metric': 0.09659309107437453

Stored message using REST on topic: /apis/test

 


 

Update Rule Using REST API

The updateRule() method is called, which invokes the REST API to update a rule.  Originally, the rule was created using the HTTP POST operation.  In this case, the rule is retrieved from the existing set of rules and the e-mail address is changed to the second test e-mail (TEST_EMAIL2).  Then the updated rule is saved using the “/rules/{ruleId}.xml” API resource and the HTTP PUT operation.  Note that it would have been easier to use the rule ID created earlier in the program, but this example illustrates searching for the rule by name, which doesn’t require any prior knowledge of the rule ID.

 

 

        WebResource apisWeb = client.resource(API_URL);

        WebResource rulesWeb = apisWeb.path("rules.xml");

        RulesResult result = rulesWeb.get(RulesResult.class);

       

        //find the rule that was created earlier

        Rule localRule = null;

        for (Rule rule : result.getRules()) {

            if (ruleName.equals(rule.getName())) {

              localRule = rule;

            }

        }

       

        // change email address

        RuleActionConfiguration config = localRule.getRuleActionConfigurations().get(0);

        for (Parameter param : config.getParameterValues().getParameters()) {

            if ("to".equals(param.getName())) {

                System.out.println("Change "+param.getValue()+" to "+TEST_EMAIL2);

                param.setValue(TEST_EMAIL2);

            }

        }

        Rule updatedRule = null;

        WebResource rulesUpdateWeb = apisWeb.path("rules/"+localRule.getId()+".xml");

        try {

           

            updatedRule = rulesUpdateWeb.accept(MediaType.APPLICATION_XML)       

                                        .type(MediaType.APPLICATION_XML)

                                        .put(Rule.class, localRule);

 

 

 

##############

Beginning test of updateRule()

Change my.name@domain.com to rule.changed@domain.com

Rule updated

email = rule.changed@domain.com

 


 

Read Recent Messages

We have just published a message using REST, which in turn triggered a rule that published a new message.  We have also stored a message directly to the message archive using REST.  Therefore, the sample application has caused three new messages to be added to the data store.  The next method, restRead(), reads back all messages created in the last 30 seconds, and displays them in the Eclipse console window.  This uses the listMessages() method, already discussed above, to read back messages published in the previous 30 seconds:

 

 

        listMessages("", 0, 30);

 

 

 

##############

 Beginning test of restRead()

Waiting several seconds, to make sure all published messages have reached the account.

 

Read messages using startDate of: Tue Jun 12 16:45:51 CDT 2012 (long=1339537551679)

 

Message topic(): myEdcAccount/RulesAssistant/rule/test

Received on: Tue Jun 12 16:46:11 CDT 2012

metric: rule_string_metric string new_string

metric: rule_double_metric double 0.9302776398550006

 

Message topic(): myEdcAccount/MyEclipseClient/apis/test

Received on: Tue Jun 12 16:46:11 CDT 2012

metric: api_double_metric double 0.09659309107437453

metric: api_boolean_metric boolean true

metric: api_string_metric string This is a String

metric: api_int_metric int 123456789

 

Message topic(): myEdcAccount/MyEclipseClient/pub/test

Received on: Tue Jun 12 16:46:11 CDT 2012

metric: pub_int_metric int 123456789

metric: pub_string_metric string This is a String

metric: pub_boolean_metric boolean true

metric: pub_double_metric double 0.9302776398550006

 


 

Delete Rule through REST

Finally, the sample application uses a REST API to delete the rule created earlier.

 

 

        rulesWeb = client.resource(API_URL).path("rules/" + ruleID + ".xml");

        Rule deleteRule = rulesWeb.accept(MediaType.APPLICATION_XML).type(MediaType.APPLICATION_XML).delete(Rule.class);

 

 

 

##############

 Beginning test of deleteRule()

Rule ID 10 deleted.

 

 Done.

 

Note: if you experiment with the sample application by trying to create other Rules definitions, you can comment out the call to deleteRule(), so that you can go into the Everyware Cloud Web console to troubleshoot the rule query or its actions.  However, the sample application will then be unable to add the rule because one already exists with the same name.  You should manually delete the rule using the Cloud Web console, and then you can successfully re-run the Java application.

 

 


 

This is the end of this REST Java example code.  For more information on developing Java code using the Jersey and JAX-RS APIs, see http://jersey.java.net/nonav/documentation/latest/user-guide.html for more documentation.