Differences
This shows you the differences between two versions of the page.
hellocorelua [2014/03/22 21:45] mroriz [Execution] |
hellocorelua [2017/07/21 03:08] |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== HelloCoreLua ====== | ||
- | {{ : | ||
- | This tutorial will guide you through the basic concepts and programming involved in the communication between a mobile node (MN) in [[wp> | ||
- | |||
- | One of the key differences between programming in Java and Lua for SDDL is the need to define the exchanged messages in a language-independent format, such as XDR, JSON, Google Protocol Buffers, etc. In this sample, we opted for JSON to express the messages changed between the client and server. Note that both instances - client and server - need to serialize their message in this format. | ||
- | |||
- | Our sample application is composed of two components: a lua mobile client node and a stationary java node, as illustrated in the figure on the right. The MN creates a message, containing a random latitude, longitude and a custom id (expressed in uuid), which is sent to the SDDL core. Our processing node receives this message and execute a simple logic, keeps track on the number of messages received and prints them on the screen. To exemplify the other path of communication, | ||
- | |||
- | The tutorial will focus on the code of the lua mobile client application, | ||
- | |||
- | <WRAP tip> | ||
- | You do not need to copy the source code snippets shown in this tutorial. At the end of each section there is a link to download the entire | ||
- | </ | ||
- | |||
- | ===== LuaMobileClient ===== | ||
- | To create our Lua mobile client application, | ||
- | |||
- | <code lua> | ||
- | -- clientlib requires | ||
- | local logging | ||
- | local dispatcher = require(" | ||
- | local node = require(" | ||
- | local messages | ||
- | </ | ||
- | |||
- | In addition to these libraries, we will also import a set of Lua libraries to send messages in a language-independent format. For this sample, we choose JSON to describe the exchanged data because it is very flexible and has a direct mapping to Lua and Java. Note that the developer is free to choose any language-independent format to exchange messages between the mobile client and the processing node. The only requirement is that the both need to be able to understand the exchanged bytes. | ||
- | |||
- | <code Lua> | ||
- | -- app specific requires | ||
- | local math = require(" | ||
- | local uuid = require(" | ||
- | local json = require(" | ||
- | </ | ||
- | |||
- | In SDDL, nodes that are outside the core (either mobile or stationary) interact directly with the Gateway rather than the processing nodes, since it uses a different protocol ([[ClientLib]] and [[MRUDP]]) than the core ([[wp> | ||
- | |||
- | <code lua> | ||
- | -- server info | ||
- | local gw_ip = " | ||
- | local gw_port | ||
- | </ | ||
- | |||
- | After that, we specify our logging information. The logger shows ClientLib debug information; | ||
- | |||
- | <code lua> | ||
- | -- logger | ||
- | logging.console = require(" | ||
- | |||
- | -- dispatcher | ||
- | local disp = dispatcher.new() | ||
- | </ | ||
- | |||
- | After that, we specify a listener for our Lua MN client. The ClientLib Lua listener is a table that contains attributes that are functions. These functions are triggered by the library when an event happens, such as when the client receives a message, connects, disconnects or reconnects into a gateway. They receive the MN connection as argument and the message received or unsent. We will focus on the '' | ||
- | |||
- | Note that, we can also prefix the listeners functions arguments with a custom object, in this case we prefix with a '' | ||
- | |||
- | <code lua> | ||
- | -- listener | ||
- | local listener = { | ||
- | new_message_received = function(prefix_variable, | ||
- | print(" | ||
- | print(" | ||
- | |||
- | local json_content, | ||
- | for k, v in pairs(json_content) do | ||
- | print(k, v) | ||
- | end | ||
- | end, | ||
- | | ||
- | unsent_messages = function(prefix_variable, | ||
- | print(" | ||
- | end, | ||
- | | ||
- | connected = function(node) | ||
- | print(" | ||
- | end, | ||
- | |||
- | reconnected = function(node) | ||
- | print(" | ||
- | end, | ||
- | |||
- | disconnected = function(node) | ||
- | print(" | ||
- | end, | ||
- | } | ||
- | </ | ||
- | |||
- | Our client will send a table containing a random latitude, longitude and UUID. The following data displays this table: | ||
- | |||
- | <code Lua> | ||
- | -- content | ||
- | local client_data = { | ||
- | lat = -1 * math.random(22, | ||
- | lng = -1 * math.random(31, | ||
- | uuid = uuid.new() | ||
- | } | ||
- | </ | ||
- | |||
- | The data will be sent repeatedly by our client application to the Java server, which is the main logic of our program. We will specify the entry routine of our Lua mobile client in a function called '' | ||
- | |||
- | First we instantiate the logging feature and the minimum logging level to '' | ||
- | |||
- | node.new(scheduler, | ||
- | |||
- | The connection table, encapsulate the details and protocol involved in the physical connection with the gateway, for instance, it uses unique ids to identify the client and the connection when the node changes IPs. If we do not specify an argument in the connection instantiation, | ||
- | |||
- | After creating the node connection, we establish the connection calling the '' | ||
- | |||
- | The routine has a main loop that executes forever. We attribute random values to our client_data content. This content is encoded into a JSON so that we can communicate with the Java server. We create an application message, using the '' | ||
- | |||
- | The entire code of our lua client is displayed below: | ||
- | <file Lua helloclient.lua> | ||
- | --[[ | ||
- | Hello Core Lua Client | ||
- | Simple lua client that sends every 10s a table containig a random lat, lng and a custom ID (uuid). | ||
- | --]] | ||
- | |||
- | -- clientlib requires | ||
- | local logging | ||
- | local dispatcher = require(" | ||
- | local node = require(" | ||
- | local messages | ||
- | |||
- | -- app specific requires | ||
- | local math = require(" | ||
- | local uuid = require(" | ||
- | local json = require(" | ||
- | |||
- | -- server info | ||
- | local gw_ip = " | ||
- | local gw_port | ||
- | |||
- | -- logger | ||
- | logging.console = require(" | ||
- | |||
- | -- dispatcher | ||
- | local disp = dispatcher.new() | ||
- | |||
- | -- listener | ||
- | local listener = { | ||
- | new_message_received = function(prefix_variable, | ||
- | print(" | ||
- | print(" | ||
- | |||
- | local json_content, | ||
- | for k, v in pairs(json_content) do | ||
- | print(k, v) | ||
- | end | ||
- | end, | ||
- | | ||
- | unsent_messages = function(prefix_variable, | ||
- | print(" | ||
- | end, | ||
- | | ||
- | connected = function(prefix_variable, | ||
- | print(" | ||
- | end, | ||
- | |||
- | reconnected = function(prefix_variable, | ||
- | print(" | ||
- | end, | ||
- | |||
- | disconnected = function(prefix_variable, | ||
- | print(" | ||
- | end, | ||
- | } | ||
- | |||
- | -- content | ||
- | local client_data = { | ||
- | lat = -1 * math.random(22, | ||
- | lng = -1 * math.random(31, | ||
- | uuid = uuid.new() | ||
- | } | ||
- | |||
- | function main() | ||
- | local logger = logging.console() | ||
- | logger: | ||
- | |||
- | |||
- | local connection = node.new(disp, | ||
- | connection: | ||
- | | ||
- | -- we could pass a prefix variable, e.g.: | ||
- | -- add_listener(" | ||
- | connection: | ||
- | | ||
- | while true do | ||
- | -- random lat and lng and encode in json | ||
- | client_data.lat = -1 * math.random(22, | ||
- | client_data.lng = -1 * math.random(31, | ||
- | local lua_content_in_json = json.encode(client_data, | ||
- | |||
- | local appMSG = messages.new() | ||
- | appMSG.content_type = messages.content_types.JSON | ||
- | appMSG: | ||
- | connection: | ||
- | |||
- | disp: | ||
- | end | ||
- | |||
- | disp: | ||
- | connection: | ||
- | |||
- | disp: | ||
- | end | ||
- | |||
- | disp: | ||
- | </ | ||
- | ==== Processing Node ==== | ||
- | The core nodes establishes premises and protocols that are not suitable for mobile applications. To expand this processing power to mobile nodes, we added the concept of gateways that use our lightweight protocol to communicate with mobile nodes and translate their message to core messages. Developers can instantiate nodes to process the mobile nodes message. | ||
- | |||
- | To create our processing node application, | ||
- | |||
- | The main difference between the Processing Node of this version and the [[hellocore|Java Hello Core]] Server is the addition of the transformation of the response to JSON. We will send the number of messages and an attribute country to the client. The entire code of our server is displayed below. The difference exists on the '' | ||
- | |||
- | <file java HelloCoreServer.java> | ||
- | package br.pucrio.inf.lac.helloworld; | ||
- | |||
- | import java.util.logging.Level; | ||
- | import java.util.logging.Logger; | ||
- | |||
- | import org.json.simple.JSONObject; | ||
- | |||
- | import lac.cnclib.sddl.message.ApplicationMessage; | ||
- | import lac.cnclib.sddl.serialization.Serialization; | ||
- | import lac.cnet.sddl.objects.ApplicationObject; | ||
- | import lac.cnet.sddl.objects.Message; | ||
- | import lac.cnet.sddl.objects.PrivateMessage; | ||
- | import lac.cnet.sddl.udi.core.SddlLayer; | ||
- | import lac.cnet.sddl.udi.core.UniversalDDSLayerFactory; | ||
- | import lac.cnet.sddl.udi.core.listener.UDIDataReaderListener; | ||
- | |||
- | public class HelloCoreServer implements UDIDataReaderListener< | ||
- | SddlLayer | ||
- | int counter; | ||
- | |||
- | public static void main(String[] args) { | ||
- | Logger.getLogger("" | ||
- | |||
- | new HelloCoreServer(); | ||
- | } | ||
- | |||
- | public HelloCoreServer() { | ||
- | core = UniversalDDSLayerFactory.getInstance(); | ||
- | core.createParticipant(UniversalDDSLayerFactory.CNET_DOMAIN); | ||
- | |||
- | core.createPublisher(); | ||
- | core.createSubscriber(); | ||
- | |||
- | Object receiveMessageTopic = core.createTopic(Message.class, | ||
- | core.createDataReader(this, | ||
- | |||
- | Object toMobileNodeTopic = core.createTopic(PrivateMessage.class, | ||
- | core.createDataWriter(toMobileNodeTopic); | ||
- | |||
- | counter = 0; | ||
- | synchronized (this) { | ||
- | try { | ||
- | this.wait(); | ||
- | } catch (InterruptedException e) { | ||
- | e.printStackTrace(); | ||
- | } | ||
- | } | ||
- | } | ||
- | |||
- | @Override | ||
- | public void onNewData(ApplicationObject topicSample) { | ||
- | Message message = (Message) topicSample; | ||
- | System.out.println(Serialization.fromJavaByteStream(message.getContent())); | ||
- | |||
- | PrivateMessage privateMessage = new PrivateMessage(); | ||
- | privateMessage.setGatewayId(message.getGatewayId()); | ||
- | privateMessage.setNodeId(message.getSenderId()); | ||
- | |||
- | synchronized (core) { | ||
- | | ||
- | | ||
- | | ||
- | } | ||
- | | ||
- | String content = jsonObject.toJSONString(); | ||
- | ApplicationMessage appMsg = new ApplicationMessage(); | ||
- | appMsg.setContentObject(content); | ||
- | | ||
- | privateMessage.setMessage(Serialization.toProtocolMessage(appMsg)); | ||
- | core.writeTopic(PrivateMessage.class.getSimpleName(), | ||
- | } | ||
- | |||
- | } | ||
- | </ | ||
- | |||
- | ==== Execution ==== | ||
- | |||
- | To execute our application, | ||
- | |||
- | $ gateway 127.0.0.1 5500 | ||
- | |||
- | After that, we instantiate our processing node. To do that, run the '' | ||
- | |||
- | $ lua helloclient.lua | ||
- | |||