Skip to Content
Technical Articles
Author's profile photo Dries Van Vaerenbergh

WebSocket’s in SAP UI5 Multi Target Applications consuming Enterprise Messaging ?

Hi UI5ers!

In this blog post we will have a look on how we can combine a Node.js Application, an Approuter and an SAPUI5 application in a Multi Target Application using WebSocket’s.

This is a Blog series with the following topics in separated Blog posts:

Cloud Foundry Enterprise Messaging Webhooks ?
Send AMQP messages from CPI to Enterprise Messaging and Consume them in a Node.js AMQP Application ?
WebSocket’s in SAP UI5 Multi Target Applications consuming Enterprise Messaging ? (this blog)

 

Introduction

In this blog post we are going to reuse the code of our previously created “em-consumer” application.

This earlier created application is based and reused from the SAP HANA Academy.

More information about their very clear demo tutorials can be found here:

Repository:

git clone https://github.com/saphanaacademy/em-consumer.git

 

The GitHub repository of this application from the SAP HANA Academy can be found here: https://github.com/saphanaacademy/em-consumer

If you want to catch up with the previous blog, where we reused this code and made some adjustment, you can find it in Send AMQP messages from CPI to Enterprise Messaging and Consume them in a Node.js AMQP Application ?.

Since this blog will cover the development and implementation of WebSocket’s, more information can be found in the following blog post: https://blogs.sap.com/2018/01/23/how-to-use-websockets-in-the-cloud-foundry-environment-in-the-sap-cloud-platform/

The full code of this Multi Target Application we will be building in this blog, can be found in the following repository: https://github.com/vvdries/MtaEmUI5websocket

 

Building the project

I will be using the SAP Business Application Studio for the development of this application. I would recommend using this editor or Visual Code if you want to develop locally.

Perform the following steps to setup and build your project. Indeed time to ope the terminal!

1. Create a directory called “MtaEmUI5websocket“.

mkdir MtaEmUI5websocket

2. Navigate into this created directory.

cd MtaEmUI5websocket

3. Initialize a “Cloud Foundry HTML5 Application Repository” project.

Yo easy-ui5

Pass the following configuration values to it:

  • How do you want to name this project? ui5Websockets
  • Which namespace do you want to use? blogs
  • On which platform would you like to host the application? Cloud Foundry HTML5 Application Repository
  • Which view type do you want to use? XML
  • How do you want to name your main view? Error
  • Where should your UI5 libs be served from? Content delivery network (SAPUI5)
  • Would you like to create a new directory for the project? No

4. Create a directory for your Node.js application inside your mta project and call it “NodeWsEm“.

mkdir NodeWsEm

5. Navigate into this create directory.

cd NodeWsEm

6. Inside this directory initialize npm.

npm init

Press enter for all the default configuration parameters.

7. create an “index.js” file inside this “NodeWsEm” directory.

touch index.js

8. Copy paste the following code into it:

const WebSocketServer = require('ws').Server;
	//We will create the websocket server on the port given by Cloud Foundry --> Port 8080
	const ws = new WebSocketServer({
		port: process.env.PORT || 8080
	});
	
	var cfenv = require('cfenv');
	var appEnv = cfenv.getAppEnv();
	var emCreds = appEnv.getServiceCreds("EnterpriseMessaging");
	var emCredsM = emCreds.messaging.filter(em => em.protocol[0] === 'amqp10ws');
	const options = {
		uri: emCredsM[0].uri,
		oa2: {
			endpoint: emCredsM[0].oa2.tokenendpoint,
			client: emCredsM[0].oa2.clientid,
			secret: emCredsM[0].oa2.clientsecret
		},
		data: {
			source: "queue:ErrorQueue",
			payload: new Buffer.allocUnsafe(20),
			maxCount: 100,
			logCount: 10
		}
	};

	const { Client } = require('@sap/xb-msg-amqp-v100');
	const client = new Client(options);
	const stream = client.receiver('ErrorQueue').attach(options.data.source);

	ws.on('connection', function (socket) {
		socket.send(JSON.stringify({
			"message": "Hi, this is the Echo-Server"
		}));
	
		stream.on('data', (message) => {
			var payload = JSON.parse(message.payload.toString('utf8'));
			console.log(`Received the following message: ${JSON.stringify(payload)}`);
			socket.send(JSON.stringify(payload));
			message.done();
		});
	
		client
			.on('connected', (destination, peerInfo) => {
				console.log('Connected!');
			})
			.on('assert', (error) => {
				console.log(error.message);
			})
			.on('error', (error) => {
				console.log(error);
			})
			.on('disconnected', (hadError, byBroker, statistics) => {
				console.log('Disconnected!');
			});
	

		client.connect();
	});
  

In this code you will see the SAP HANA Academy code is reused to connect to Enterprise messaging. Via that connection we are notified once messages were created and send to the queue. This was also implemented and tested in the previous blog.

But this code was a little extended, to support and add the WebSocket protocol.

WebSocket’s are implemented here and our UI5 application will connect to this WebSocket later on.

This means that Enterprise Messaging is notifying the Node.js application and the WebSocket inside this Node app will notify the UI5 Application on his turn.

First of all, we need to install the required dependencies/packages. Run the following NPM commands to install these packages:

npm i express		
npm i cfenv		
npm i @sap/xb-msg-amqp-v100
npm i ws

Once you installed the packages, they will be visible in your “package.json” file inside your Node app. Do not forget to add the start script in here.

This code does not differ that much since the previous blog. The only adjustments made here are regarding the WebSocket.

To import and create a WebSocket, the following code has been added to the top of our “index.js file“.

Once the WebSocket Server has been created, the connection to the Enterprise Messaging Queue should still be maintained. This is done by the following code (just like in the previous blog and like it was explained by the SAP HANA Academy):

With this a WebSocket Server has been created and a connection the Enterprise Messaging Service has been established.

Now the only thing left to do is to setup the connections for the WebSocket.

This is done via the “ws.on(‘connection..’”, it allows us to listen for devices that can connect to the WebSocket.

Once they connect, they will receive the message “Hi, this is the Echo-Sevrer”.

As you can see, the “stream.on(‘data’” part has been removed inside our WebSocket. By this we are able to retrieve the data (coming from the Enterprise Messaging Service) inside our WebSocket. Once received this data is send to the socket via the “socket.send” function. This way all the connected devices will receive the incoming Enterprise Messaging message.

The next thing we want to do is to setup our “mta.yaml” file correctly. Not that it is not correct at the very moment, but we need to add our Node Module to it. This along with the Enterprise Messaging service as a resource. I will briefly show you the important parts you have to add.

The Node module should be added under the “modules” section inside your “mta.yaml” file.

Extend your “ui5Websockets” module with the “NodeWsEm_api”.

Last but not least the Enterprise Messaging Service should be added as a resource under the respective “resources” section.

In the end your “mta.yaml” file should look like this:

ID: ui5Websockets
_schema-version: 3.2.0
description: Enter&nbspdescription&nbsphere
version: 0.0.1
parameters:
  enable-parallel-deployments: true

modules:
  - name: ui5Websockets
    type: nodejs
    path: approuter
    parameters:
      disk-quota: 512M
      memory: 512M
    requires:
      - name: ui5Websockets_destination
      - name: ui5Websockets_uaa
      - name: ui5Websockets_html5_repo_runtime
      - name: NodeWsEm_api
        group: destinations
        properties:
          forwardAuthToken: true
          name: NodeWsEm_api
          strictSSL: false
          url: "~{url}"
  - name: ui5Websockets_deployer
    type: com.sap.html5.application-content
    path: deployer
    requires:
      - name: ui5Websockets_html5_repo_host
    build-parameters:
      builder: custom
      commands:
        - npm&nbsprun&nbspbuild:ui --prefix ..
  - name: NodeWsEm
    type: nodejs
    path: NodeWsEm
    provides:
      - name: NodeWsEm_api
        properties:
          url: ${default-url}
    requires:
      - name: EnterpriseMessaging

resources:
  - name: ui5Websockets_destination
    type: org.cloudfoundry.managed-service
    parameters:
      service-plan: lite
      service: destination
  - name: ui5Websockets_uaa
    type: org.cloudfoundry.managed-service
    parameters:
      path: ./xs-security.json
      service-plan: application
      service: xsuaa
  - name: ui5Websockets_html5_repo_runtime
    type: org.cloudfoundry.managed-service
    parameters:
      service-plan: app-runtime
      service: html5-apps-repo
  - name: ui5Websockets_html5_repo_host
    type: org.cloudfoundry.managed-service
    parameters:
      service-plan: app-host
      service: html5-apps-repo
      config:
        sizeLimit: 5
  - name: EnterpriseMessaging
    type: org.cloudfoundry.existing-service
    parameters:
      service: enterprise-messaging
      service-plan: dev

The next change will occur in the “xs-app.json“ file inside your “approuter” directory.

Add the following routes to it and enable the WebSocket’s.

{
  "welcomeFile": "blogsui5Websockets/",
  "authenticationMethod": "route",
  "websockets": {
    "enabled": true
  },
  "logout": {
    "logoutEndpoint": "/do/logout"
  },
  "routes": [
    {
      "source": "^/NodeWS(.*)$",
      "target": "$1",
      "authenticationType": "none",
      "destination": "NodeWsEm_api",
      "csrfProtection": false
    },
    {
      "source": "^(.*)$",
      "target": "$1",
      "service": "html5-apps-repo-rt",
      "authenticationType": "xsuaa"
    }
  ]
}

The last change can be found in the “Error.controller.js” file inside your “webapp/controller” directory.

This code should look like this:

sap.ui.define([
  "blogs/ui5Websockets/controller/BaseController",
  "sap/ui/core/ws/WebSocket",
  "sap/m/MessageToast"
], function (Controller, WebSocket, MessageToast) {
  "use strict";

  return Controller.extend("blogs.ui5Websockets.controller.Error", {
    onInit: function () {
      var connection = new WebSocket("/NodeWS");
      // connection opened
      connection.attachOpen(function (oControlEvent) {
        console.log(oControlEvent.getParameter("data"));
      });

      // server messages
      connection.attachMessage(function (oControlEvent) {
        var msg = JSON.parse(oControlEvent.getParameter("data"));
        console.log(JSON.stringify(msg));
        MessageToast.show(msg.message || msg.errorMessage);
      });

      // error handling
      connection.attachError(function (oControlEvent) {
        console.log(oControlEvent.getParameter("data"));
      });

      // onConnectionClose
      connection.attachClose(function (oControlEvent) {
        console.log(oControlEvent.getParameter("data"));
      });
    }
  });
});

The “WebSocket” is imported as well as the “MessageToast” control.

The connection to the Node WebSocket is set via the path declared in de “xs-app.json” file inside your “approuter” directory. Next the different WebSocket scenarios are covered via the “attachOpen”, Message, Error and Close scenarios.

In the “attacheMessage” function the incoming message is parsed and displayed on the screen via a MessageToast. Either the “Hi” message of the server (WebSocket) or the error message from Postman or CPI is displayed.

With this you finished the full development and setup for your MTA Enterprise Messaging UI5 WebSocket application. Now it is time to deploy it.

Go to your terminal and navigate to the root directory of your MTA project.

Make sure you are logged in to Cloud Foundry and you are targeting the right organization and space.

Once double checked execute the deployment command:

npm run deploy

This will start the deployment and can be followed in the terminal window,

Once the deployment is finished you can go to your Cloud Platform account under your organization and space and you will see the applications were started under the “Applications” section.

Select the “ui5Websockets” application and open the URL.

You will see that the WebSocket server will greet you, just like we taught him to.

When you resend a message to the “ErrorQueue” via Postman or via CPI (AMQP) you will see that the Node application detected this message and that it is automatically shown inside the app because of the WebSocket connection.

Ep11. – Max’s Adventure in SAP Cloud Platform: Enterprise Messaging w/ Dries Van Vaerenbergh

For more information or a recap you can replay the Livestream “Ep11. – Max’s Adventure in SAP Cloud Platform: Enterprise Messaging w/ Dries Van Vaerenbergh” where Max and I have a deeper look on the Enterprise Messaging Service itself. This combined with a small chat WebSocket app. Enjoy!

 

Wrap up ?

With this you created a Multi Target application containing a Node.js app, which is responsible to connect to the Enterprise Messaging Service and will notify the UI5 application in real time with the appropriate messages.

The connection to the WebSocket could be place in the “Component.js” file or even in an “App.controller.js” file. In this blog I only showed you on how to connect the whole architecture.

Do notice, there is no authentication method implemented on your Node WebSocket application. This could be achieved by using the xsuaa service and the passport package. At the moment the “authenticationType” for the “NodeWS” path inside your “xs-app.json” file is also set to “none”. It should only take some small configurations and development to setup this security. Just do not forget it. ?

I hope you found this blog interesting and that it may serve you in the future during your Enterprise Messaging, Node.js, Websocket and UI5 development.

Kind regards,

Dries

 

Assigned Tags

      11 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Helmut Tammen
      Helmut Tammen

      Really great work Dries. Good structured documents with easy to understand examples. Learned a lot

      Thank you Helmut

      Author's profile photo Dries Van Vaerenbergh
      Dries Van Vaerenbergh
      Blog Post Author

      Thanks a lot Helmut!

      Really appreciate the feedback!

      Happy to hear the examples are clear!

      Again a big thanks!

      Kind regards,

      Dries

      Author's profile photo Carlos Roggan
      Carlos Roggan

      Hello Dries Van Vaerenbergh , thanks very much for this great post...! Very good that you're passionate about sharing and please go on with that 😉
      Cheers,
      Carlos

      Author's profile photo Dries Van Vaerenbergh
      Dries Van Vaerenbergh
      Blog Post Author

      Hi Carlos Roggan thanks for the feedback!

      Learned a lot from many Community members their blog posts, including yours! Thanks for that!

      Best regards,

      Dries

      Author's profile photo M W
      M W

      Hi, great Blog!

      I am trying to rebuild what you did but I get stuck at the deployment "npm run deploy".

      This is the Error I get:

      Author's profile photo Dries Van Vaerenbergh
      Dries Van Vaerenbergh
      Blog Post Author

      Hi thank you for your feedback and nice that you are trying it out!

      It looks like you are trying to develop the application locally on you computer, is that correct?

      In case you are developing locally you have to make sure that you have the "Cloud MTA Build Tool (MBT)" installed in order to build to MTA project.

      You can check if you have tis installed already by executing the following command:

      mbt build

      In case it is not installed you can download and follow the installation steps here:

      https://sap.github.io/cloud-mta-build-tool/download/

      I created this MTA project inside the SAP Business Application Studio which comes with different types of workspaces with all the required commands and modules preinstalled. I used the "SAP Cloud Business Application" Workspace.

      I hope the above explanation addresses your problem and if not please let me know!

      Thanks again for your reaction and feedback.

      Good luck!

      Kind regards,

      Dries

      Author's profile photo YAO-CHING WEN
      YAO-CHING WEN

      Thanks for your great sharing Dries!

      I am trying to rebuild what you did but I get stuck at the deployment “npm run deploy”.

      So I use mbt build instead and I get a error message, can you give me some suggestion? Many thanks.

      Author's profile photo Dries Van Vaerenbergh
      Dries Van Vaerenbergh
      Blog Post Author

      Hi Yao-Ching,

      Thanks for your feedback! Nice you are trying it out yourself!

      Regarding your error message:

      1. Did you create the enterprise messaging service instance in your cloud foundry environment?
      2. If you did, does it has the same name as the name you provided in the mta.yaml file?

      Could you check those and adjust if needed?

      I hope this helps already! 🙂

      Best regards,

      Dries

      Author's profile photo Andrew Mai
      Andrew Mai

      Hi,

      Can I know the detail config in the destination NodeWsEm_api, should I use the wss://my-srv-socket.url one or just put the https://my-srv-socket.url? I'm having trouble to connect to the websocket through the AppRouter. I can connect directly through the websocket URL (https://my-srv-socket.url), but if I want to connect through the AppRouter path: const socket = io("/srv-socket"), it will not able to connect.

      Author's profile photo Keerthana Jayathran
      Keerthana Jayathran

      Hi Dries Van Vaerenbergh

      I am getting upgrade required error while running the node application and the ui is also not rendering properly.Could you please help me with this.

      Thank you

      Regards,
      Keerthana

      Author's profile photo Naveen Jain
      Naveen Jain

      Dear Dries Van Vaerenbergh,

      I followed your blog. everything was fine for me but now i am getting AMQP not allowed error.

       

      AmqpError: target (topic/queue) forbidden (220056) [amqp:not-allowed] [receiver: S11/S4HANA/SO/SalesOrder; sapGatewayErrorCode: V1/220056] error. few months ago it was working fine.

      Any idea?

      Regards

      Naveen Jain