· Overview
· Publish and Store Data with REST
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:
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.
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).
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.
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 // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
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.
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)
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
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
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
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
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
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.)
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.
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"
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.
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
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
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
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.