Big Data Analytics in M2M

WHITE PAPER

Big Data Analytics In M2M

Bidirectional Event Based Communication With Java

WebSocket WHITE PAPER

Table of Contents

Introduction ...... 3 What is WebSocket? ...... 3 Project Tyrus ...... 3 Uses for ...... 3 How It Works ...... 3 Architect and Developer Perspective ...... 4 Sample Machine Interaction WebSocket Application ...... 9 Conclusion ...... 14 References ...... 14

2 | © 2015, HCL Technologies. Reproduction Prohibited. This document is protected under Copyright by the Author, all rights reserved.

Introduction When we hear the phrase, ‘Full Duplex communication’, the first thing that comes to mind is a telephone call, and then, software TCP communication over plain sockets. As the web gets richer and more interactive, clients and servers can communicate and send notifications in real-time. Users are demanding for information as soon as it is made available. If one has to refresh a page to get new information, it is already too late. Luckily, a protocol that supports direct data exchange is now available; it is none other than WebSocket. WebSockets are designed to be implemented in web browsers and web servers. WebSockets can also be useful for standalone client-server applications, a subject covered in this white paper. To highlight this, I will use plain Java for both client and server.

What is WebSocket? WebSocket is an advanced technology that makes it possible to open an interactive communication session between clients and a server. With this API, you can send messages to a server and receive event-driven responses. It provides full-duplex communication over a single TCP connection. This is an independent TCP-based protocol. Its only relationship to HTTP is that HTTP servers interpret its handshake as an upgrade request.

Project Tyrus Tyrus is the open source JSR 356 - Java API for WebSocket reference implementation, for easy development of WebSocket applications. It is a Java project that has been released separately. It is the only API that gives a java based WebSocket client and provides separated containers for those servers that do not use GlassFish. In this paper, I use this API to highlight the non-browser WebSocket client and the ability to run a WebSocket server as a plain Java program.

Uses for WebSockets

• Live, event-based machine interaction • Financial tickers • Social feeds • Sports updates • Multiplayer games • Multimedia chat • Collaborative editing/coding • Location-based apps • Clickstream data • Online education

How It Works The client establishes a WebSocket connection through a process known as the WebSocket handshake. This process starts with the client sending a regular HTTP request to the server. An upgrade header is included in the request that informs the server that the client wishes to establish a WebSocket connection.

3 | © 2015, HCL Technologies. Reproduction Prohibited. This document is protected under Copyright by the Author, all rights reserved.

This is a simplified example of the initial request headers.

GET ws://WebSocket.example.com/ HTTP/1.1 101 WebSocket Protocol HTTP/1.1 Handshake Origin: http://example.com Handshake Date: Wed, 16 Oct 2013 10:07:34 GMT Connection: Upgrade Connection: Upgrade Host: WebSocket.example.com Upgrade: WebSocket Upgrade: WebSocket

If the server provisions the WebSocket protocol, it agrees to the upgrade and communicates this through an upgrade header in the response. After handshake success by the HTTP, a TCP/IP connection will take care of sending and receiving messages by both the client and the server.

Architect and Developer Perspective

Server-Client Implementation Options

• C++ : libWebSockets • Ruby : em-WebSocket • Errlang : Shirasu.ws • Python : Tornado, pyWebSocket • Java : JettyWebSocket, • PHP : Ratchet, phpws jWebSocket, Tyrus, • DotNET : Fleck, ASP.NET 4.5, Spring STOMP SuperWebSocket, • Node.JS : ws, Socket.IO, XSocket.NET WebSocket-Node

Security in WebSocket

1. Header level security HTTPS’ header field is included in the client’s opening handshake for WebSocket. This is used to inform the server about the script’s origin while generating the WebSocket connection request. The server may then decide to accept or reject the handshake request accordingly. This allows the server to protect against unauthorized cross-origin use of a WebSocket server by scripts using the WebSocket API in a browser. Non-browser clients may use the origin header to specify the origin of the request. WebSocket servers should be careful about receiving such requests. The WebSocket opening handshake from the client must include Sec-WebSocket-Key and Sec-WebSocket-Version HTTP header fields. To make HTTP requests, use XMLHttpRequest that allows the setting of headers as a part of that request. Therefore, to be better secured, we can send our own Sec-WebSocket-Key and Sec-WebSocket-Version HTTP header fields and validate them in our server filter.

2. URL security

4 | © 2015, HCL Technologies. Reproduction Prohibited. This document is protected under Copyright by the Author, all rights reserved.

Some servers provide credential authentication and Servlet Security mechanisms; for example, JBoss (WildFly). This provides a basic level of authentication, using a username and password. The following steps are required to set up client authentication before the WebSocket handshake is initiated from the client.

Download WildFly 8.1, unzip, and add a new user by invoking the following script: ./bin/add-user.sh -a -u u1 -p p1 -g g1 This will add user “u1″ with password “p1″ in group “g1″. The group specified here needs to match as defined in in the deployment descriptor.

Deploy the sample by giving the command: mvn wildfly:deploy

Write your deployment descriptor as below: WebSocket Endpoint /* GET g1 BASIC file g1

Some key points to understand about this descriptor:

5 | © 2015, HCL Technologies. Reproduction Prohibited. This document is protected under Copyright by the Author, all rights reserved.

indicates that any request made to this application will be prompted for authentication  defines the security role that can access this resource  shows that file-based realm is used with basic authentication  defines the security roles referenced by this application  In this case, the page that creates the WebSocket connection is protected by basic authentication.

Now, when the application is accessed at localhost:8080/endpoint-security, a security dialog box pops up, as shown below:

Enter “u1″ as the username and “p1″ as the password to authenticate. These credentials are defined in the group “g1″ which is referenced in the deployment descriptor. Any other credentials will keep bringing the dialog box back. As soon as the request is successfully authenticated, the WebSocket connection is established. If you are interested in securing only the WebSocket URL, then change the URL pattern from /* to /WebSocket.

In MotorClientEndpoint.java, change the URL to create WebSocket endpoint from client.connectToServer(WordgameClientEndpoint.class, new URI("ws://localhost:8025/ motorServer/motor")); to client.connectToServer(WordgameClientEndpoint.class, new URI("ws://u1:p1@localhost:8025/ motorServer/motor"));

Securing WebSocket using WSS and HTTPS/TLS: The steps below describe how to set up a secure WebSocket connection between the server and a standalone WebSocket client using SSL. Like HTTPS, we have WSS for WebSocket. Here, I use Tomcat server to demonstrate. Create keystore using Java keytool: Open the command prompt and run the following command. This will generate a keystore file in current location. Use the command as below: keytool -genkey -alias tomcat -dname "CN=test, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown" -keyalg RSA -ext san=dns:testserver.com,ip: 10.144.1.100  Added hostname and system ip to host file:  Navigate to “C:\Windows\System32\drivers\etc” and open host file.  Add new entry as “Ipaddress“ “hostname”. For Example : 10.144.1.100 motorserver.com  Restart the machine and start the tomcat.  Download InstallCert java file from web.

6 | © 2015, HCL Technologies. Reproduction Prohibited. This document is protected under Copyright by the Author, all rights reserved.

 Create a folder and copy the InstallCert.java and .keystore to it.  Compile the InstallCert.java : javac InstallCert.java and run as java InstallCert motorserver.com:8443  Run the command below keytool -exportcert -alias 10.144.1.100-1 -keystore jssecacerts -storepass changeit -file 10.144.1.100.cer and keytool -importcert -alias 192.168.1.149 -keystore "C:\Program Files\Java\jdk1.7.0_45\jre\lib\security\cacerts" -storepass changeit -file 192.168.1.149.cer  Now run the WebSocket standalone client as java -Djavax.net.ssl.trustStore="c:/test keystore /test.keystore" - Djavax.net.ssl.trustStorePassword=changeit -jar / MotorClient.jar

High Traffic Volumes - Single point failure It is possible to use a single WebSocket server, but application performance is limited by the capacity of the server, which is also a single point of failure. Many real-time applications are developed with the hope of seeing widespread adoption, but it can be difficult to predict the rate of growth. As of now, it is taken care of by some third party servers that are not open source. When we compare WebSocket with some old technologies like long pooling, RMI, etc., WebSocket has very little overheads, which makes more sense in adopting it in all applications over the web, in terms of data traffic.

Object Encode-Decode The WebSocket protocol makes no assumptions about the format of each message - a single bit tracks whether the message contains text or binary data, such that the client and server can efficiently decode it, but otherwise the message contents are opaque. We can add an encoder and decoder for our messages so that the client and server can agree upfront on a fixed message format.

WebSocket WebSocket Encoder Client Decoder Server

Server representation for WebSocket with sup protocol is provided below: @ServerEndpoint(value = "/motor", decoders = { MotorMessageDecoder.class,}, encoders = { MotorMessageEncoder.class }) public class MotorServerEndpoint { @OnMessage public MotorCommand onMessage(MotorCommand motorCommand, Session session) { ...

7 | © 2015, HCL Technologies. Reproduction Prohibited. This document is protected under Copyright by the Author, all rights reserved.

}

The Message Decoder will be public class MotorMessageDecoder implements Decoder.Text { @Override public MotorCommand decode(String s) { System.out.println("Incoming XML " + s); MotorCommand motorCommand = null; try { Gson gson = new Gson(); motorCommand = gson.fromJson(cmdString, MotorCommand.class); } catch (JsonSyntaxException e) { System.out.println(e.fillInStackTrace()); } return motorCommand; } @Override public boolean willDecode(String s) { try { // Check if incoming message is valid JSON Json.createReader(new StringReader(cmdString)).readObject(); return true; } catch (Exception e) { return false; } } @Override public void init(EndpointConfig endpointConfig) { // do nothing. } @Override public void destroy() { // do nothing. }

The Message Encoder will be public class MotorMessageEncoder implements Encoder.Text { @Override public String encode(MotorCommand object) throws EncodeException { Gson gson = new Gson(); String encoded = gson.toJson(motorCommand); System.out.println(encoded);

8 | © 2015, HCL Technologies. Reproduction Prohibited. This document is protected under Copyright by the Author, all rights reserved.

return encoded; } @Override public void init(EndpointConfig endpointConfig) { // do nothing. } @Override public void destroy() { // do nothing. } }

Sample Machine Interaction WebSocket Application

Setting up the Java WebSocket Server

Environment required 1. Eclipse J2EE IDE 2. Maven 3. JDK 7 or later

Dependent Artifacts javax.WebSocket javax.WebSocket- 1.0 org.glassfish.tyrus tyrus-server 1.1 org.glassfish.tyrus tyrus-container-grizzly 1.1

WebSocket Server Endpoint @ServerEndpoint(value = "/motor", decoders = {

9 | © 2015, HCL Technologies. Reproduction Prohibited. This document is protected under Copyright by the Author, all rights reserved.

MotorMessageDecoder.class,}, encoders = { MotorMessageEncoder.class }) public class MotorServerEndpoint { private Logger logger = Logger.getLogger(this.getClass().getName()); private Motor motor = Motor.getInstant(); private MotorCommand motorReply = new MotorCommand(); @OnOpen public void onOpen(Session session) { logger.info("Connected ... " + session.getId()); } @OnMessage public MotorCommand onMessage(MotorCommand motorCommand, Session session) { switch (motorCommand.action()) { case "start": logger.info("Starting the motor"); try { Motor.start(); motorReply.setMessage(“motorStarted”); return motorCommand; } catch (MotorException e) { motorCommand.setMessage(“motorStarFailed”); return motorCommand; } case "speed1": logger.info("Motor Speed Increasing to 1"); try { Motor.speed1(); motorReply.setMessage(“motorspeed1”); return motorReply; } catch (MotorException e) { motorReply.setMessage(“motorSpeed1Failed”); return motorReply; } case "speed2": logger.info("Motor Speed Increasing to 2"); try { Motor.speed2(); motorReply.setMessage(“motorspped2”); return motorReply; } catch (MotorException e) {

10 | © 2015, HCL Technologies. Reproduction Prohibited. This document is protected under Copyright by the Author, all rights reserved.

motorReply.setMessage(“motorSpeed2Failed”); return motorReply; } case "reverse": logger.info("Motor starting reverse rotate"); try { Motor.reverse(); motorReply.setMessage(“motorReverse”); return motorReply; } catch (MotorException e) { motorReply.setMessage(“motorReverseFailed”); return motorReply; } case "stop": logger.info("Motor Stopping"); try { Motor.stop(); motorReply.setMessage(“motorStoped”); return motorReply; } catch (MotorException e) { motorReply.setMessage(“motorStopFailed”); return motorReply; } } } @OnClose public void onClose(Session session, CloseReason closeReason) { logger.info(String.format("Session %s closed because of %s", session.getId(), closeReason)); } }

Start the MotorWebSocket Server public class MotorWebSocketServer {

public static void main(String[] args) { runMotorServer(); } public static void runMotorServer() { Server server = new Server("localhost", 8080, "/motorServer", WordgameServerEndpoint.class); try {

11 | © 2015, HCL Technologies. Reproduction Prohibited. This document is protected under Copyright by the Author, all rights reserved.

server.start(); BufferedReader reader = new BufferedReader( new InputStreamReader(System.in)); System.out.print("Please press a key to stop the server."); reader.readLine(); } catch (Exception e) { throw new RuntimeException(e); } finally { server.stop(); } } }

We can see that the server is running by checking the log below: June 15, 2015 1:39:37 PM org.glassfish.tyrus.server.ServerContainerFactory create INFO: Provider class loaded: org.glassfish.tyrus.container.grizzly.GrizzlyEngine June 15, 2015 1:39:38 PM org.glassfish.grizzly.http.server.NetworkListener start INFO: Started listener bound to [0.0.0.0:8025] June 15, 2015 1:39:38 PM org.glassfish.grizzly.http.server.HttpServer start INFO: [HttpServer] Started. June 15, 2015 1:39:38 PM org.glassfish.tyrus.server.Server start INFO: WebSocket Registered apps: all start with ws://localhost:8080 Please press a key to stop the server. June 15, 2015 1:39:38 PM org.glassfish.tyrus.server.Server start INFO: Starting the motor

Setting up the Java WebSocket Client Environment required 1. Eclipse J2EE IDE. 2. Maven. 3. JDK 7 or later.

Dependent Artifacts org.glassfish.tyrus.bundles tyrus-standalone-client 1.10

WebSocket Client Endpoint @ClientEndpoint( decoders = {

12 | © 2015, HCL Technologies. Reproduction Prohibited. This document is protected under Copyright by the Author, all rights reserved.

MotorMessageDecoder.class,}, encoders = { MotorMessageEncoder.class }) public class MotorClientEndpoint {

private Logger logger = Logger.getLogger(this.getClass().getName()); private MotorCommand motorCommand = new MotorCommand(); @OnOpen public void onOpen(Session session) { logger.info("Connected ... " + session.getId()); try { motorCommand.setAction(“start”); session.getBasicRemote().sendObject(motorCommand); } catch (IOException e) { throw new RuntimeException(e); } } @OnMessage public String onMessage(MotorCommand motorReply, Session session) { BufferedReader bufferRead = new BufferedReader( new InputStreamReader(System.in)); try { logger.info("Received ...." + motorReply.getMessage()); String userInput = bufferRead.readLine(); motorCommand.setAction(userInput); return motorCommand; } catch (IOException e) { throw new RuntimeException(e); } } @OnClose public void onClose(Session session, CloseReason closeReason) { logger.info(String.format("Session %s close because of %s", session.getId(), closeReason)); } public static void main(String[] args) { latch = new CountDownLatch(1); ClientManager client = ClientManager.createClient(); try { client.connectToServer(WordgameClientEndpoint.class, new URI("ws://localhost:8025/ motorServer/motor"));

13 | © 2015, HCL Technologies. Reproduction Prohibited. This document is protected under Copyright by the Author, all rights reserved.

latch.await(); } catch (DeploymentException | URISyntaxException | InterruptedException e) { throw new RuntimeException(e); } } }

We used CountDownLatch to make sure that the main thread does not exit after executing the code. The main thread waits till the time the latch decrements the counter in the onClose() method, and then, the program terminates. In the main() method, we create an instance of ClientManager, which is then used to connect to @ServerEndpoint, available at ws://localhost:8025/WebSockets/game.

The console at client side is given below: June 15, 2015 1:40:26 PM com.shekhar.wordgame.client.WordgameClientEndpoint onOpen INFO: Connected ... 95f58833-c168-4a5f-a580-085810b4dc5a June 15, 2015 1:40:26 PM com.shekhar.wordgame.client.WordgameClientEndpoint onMessage INFO: Received .... motorStarted

Conclusion WebSocket is the only existing solution to fulfill duplex communication over the web and facilitate a live client server interaction. In this white paper, most of a developer’s and architect’s perspectives have been illustrated, along with a use case, which will be useful for developing any machine-driven, event- based application for either a browser-based application or any kind of machine status update application. It was a big challenge to develop a Java-based standalone WebSocket client in 2014. Today, with the useful Java Tyrus API, it is possible. This API supports reconnect onDisconnect and onConnectFailure events, which would be an added advantage for any of our applications. This API is still evolving, so we can expect many more surprises as newer and better features evolve.

References  http://en.wikipedia.org/wiki/WebSocket  http://chimera.labs.oreilly.com/books/1230000000545  https://tyrus.java.net/

Note of Thanks Special thanks to Sridhar Chebrolu ([email protected]) and Balamuralikrishnan Vengateson ([email protected]) for their support.

14 | © 2015, HCL Technologies. Reproduction Prohibited. This document is protected under Copyright by the Author, all rights reserved.

Author Info Sathish kumar

Sathish Kumar Komarapalayam Kathirvel ([email protected]) is a Software Engineer in HCL’s Engineering and R&D Services Group. He has more than 4 years of industry experience in software development, server-client programming, and standalone applications. He has experience in Java/J2EE, frameworks (Spring and Hibernate), technologies (web services and WebSockets), and platforms (Ubuntu and Windows).

15 | © 2015, HCL Technologies. Reproduction Prohibited. This document is protected under Copyright by the Author, all rights reserved.

Hello, I'm from HCL's Engineering and R&D Services. We enable technology led organizations to go to market with innovative products and solutions. We partner with our customers in building world class products and creating associated solution delivery ecosystems to help bring market leadership. We develop engineering products, solutions and platforms across Aerospace and Defense, Automotive, Consumer Electronics, Software, Online, Industrial Manufacturing, Medical Devices, Networking & Telecom, Office Automation, Semiconductor and Servers & Storage for our customers.

For more details contact: [email protected] Follow us on Twitter: http://twitter.com/hclers & LinkedIn: http://lnkd.in/bt8hDXM View our blog-site: http://www.hcltech.com/blogs/engineering-and-rd-services Visit our website: http://www.hcltech.com/engineering-rd-services