Skip to content
This repository has been archived by the owner on Nov 17, 2021. It is now read-only.

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 

The EMITTER component

Contents

Overview

This section relates to the SAP S/4HANA Cloud event that is used to kick off the whole process, and is represented by the "EMITTER" block in the whiteboard diagram.

The EMITTER component in context

It can be found in the s4hana/event/ directory of this repository.

This component starts off the whole flow by emitting an event message to the "salesorder/created" topic on the instance of the Enterprise Messaging service.

It is a single Bash shell script emit, supported by two helper libraries:

  • localutils.sh providing basic functions for logging, access token retrieval, and so on
  • settings.sh providing the actual names of instances, plans and service keys

settings.sh is actually a symbolic link to a shared file in the root of this repository.

The EMITTER component uses the Messaging API to publish a message to a topic on the bus provided by this project's Enterprise Messaging service instance. The specific API endpoint used is POST /messagingrest/v1/topics/{topic-name}/messages.

The API call is authenticated with OAuth 2.0, whereby an access token is retrieved using facilities in the localutils.sh library and details in the settings.sh library.

Requirements

The emit Bash script uses some external tools, none of which are obscure, but some of which you may need to explicitly install:

If you are using the SAP Business Application Studio (App Studio) for your development environment, and have followed the Using the SAP Business Application Studio instructions, these tools will already be installed and ready for you to use (from the Add tools to your Dev Space step).

You'll also need a message bus, in the form of an instance of the SAP Enterprise Messaging service. Follow the Message bus setup instructions if you haven't done already.

These instructions assume you've forked this repository (see the Download and Installation instructions) and cloned it locally.

Usage

The component itself is the emit script in this directory. It's designed to be used from the command line, and expects a single parameter that is mandatory - the sales order number. In order for the end-to-end process to make sense and work properly, this must be a sales order that exists in the S/4HANA mock system. Use your SANDBOX component to get a proxy running in front of the API Hub's mock service for API_SALES_ORDER_SRV, and pick a valid sales order from the A_SalesOrder entityset.

For example, if you are currently running a local version of the proxy, look at the first 10 sales orders in the entityset at

http://localhost:5000/sap/opu/odata/sap/API_SALES_ORDER_SRV/A_SalesOrder?$top=10

and pick one of the sales order IDs from that list (get the value from the SalesOrder property).

To use this EMITTER component:

  1. Make sure you're in this s4hana/event/ directory
  2. Make sure you're logged into CF and connected to your organization and space where you have your message bus
  3. Choose a sales order number as described above (e.g. 1)
  4. Call the script, passing that sales order number (e.g. ./emit 1)

Before making the call to the emit script, you may also want to remove any existing sk*.json file, which may contain stale service key information - it will be regenerated when you call emit.

These steps should look like this - there will be a couple of log messages produced if successful:

user: teched2020-developer-keynote $ cd s4hana/event/
user: event $ ./emit 1
user: event $ cf login
API endpoint: https://api.cf.eu10.hana.ondemand.com

Email: sapdeveloper@example.com

Password:
Authenticating...
OK

Select an org:
1. 14ee89fftrial
2. ...

Org (enter to skip): 1
Targeted org 14ee89fftrial

Targeted space dev

API endpoint:   https://api.cf.eu10.hana.ondemand.com (API version: 3.91.0)
User:           sapdeveloper@example.com
Org:            14ee89fftrial
Space:          dev
user: event $ rm sk-emdev-sk1.json
user: event $ ./emit 1
2020-12-31 11:25:22 Publishing sales order created event for 1
2020-12-31 11:25:22 Publish message to topic salesorder%2Fcreated

The %2F in the topic name is a URL encoded / which is required because the Messaging API endpoint uses the topic name in the URL path. We could have the emit script encode it, but that would mean an extra dependency on e.g. Python or an npm package for example, which is not worth it for this.

Checking event messages

The output at the end of the previous section, stating that a sales order created event was indeed published, is all well and good, but the rhyming proverb Доверяй, но проверяй (Trust, but verify) encourages to dig in a little to check what was published.

This is an optional last step, in case you're interested.

Overview

Accompanying the Diving into messaging on SAP Cloud Platform series on the Hands-on SAP Dev show (see An overview of SAP Developers video content for more info) there's a repository cloud-messaging-handsonsapdev.

In this repository there are scripts that allow you to use the SAP Enterprise Messaging APIs in a simple way from the comfort of the terminal. There are two APIs, each with various endpoints. Briefly, they are:

  • Management: relating to queues and queue subscriptions
  • Messaging: relating to production and consumption of messages (including via webhook subscriptions)

To verify what is actually happening with this EMITTER component, you can use the Management API to set up a test queue & subscribe it to the "salesorder/created" topic. Then, once you've used the emit script as described earlier, you can use the Messaging API to consume the messages from that test queue and have a quick look at the contents. This way you can get a bit closer to what's going on, while also verifying for yourself that emit did what it said it did.

Setting up

First, open up a second terminal in which to perform these steps. You can use the shortcut Ctrl-` to open up a new terminal window, or you can use the "Split Terminal" feature to create another terminal window side-by-side. This screenshot shows a second split terminal, which was created by using the "two boxes" icon in the top right of the first terminal window (you can also use the "Terminal: Split Terminal" command from App Studio's Command Palette, also shown in the screenshot):

split terminals

Next, in the second terminal, move to the projects/ directory, which is where your current cloned repository is (this is also shown in the screenshot above), like this:

user: teched2020-developer-keynote $ cd $HOME/projects
user: projects $

If at this point you list the contents of the projects/ directory you'll see the root of this repository, i.e. a directory called teched2020-developer-keynote:

user: projects $ ls
teched2020-developer-keynote

Now clone the cloud-messaging-handsonsapdev repository:

user: projects $ git clone https://github.com/SAP-samples/cloud-messaging-handsonsapdev.git
Cloning into 'cloud-messaging-handsonsapdev'...
remote: Enumerating objects: 322, done.
remote: Total 322 (delta 0), reused 0 (delta 0), pack-reused 322
Receiving objects: 100% (322/322), 113.32 KiB | 547.00 KiB/s, done.

At this point there are two directories in projects/, one for each of the repositories you now have cloned here:

user: projects $ ls
cloud-messaging-handsonsapdev  teched2020-developer-keynote

Move into the new cloud-messaging-handsonsapdev/ directory:

user: projects $ cd cloud-messaging-handsonsapdev/
user: cloud-messaging-handsonsapdev $

At this point you're ready to invoke the management and messaging scripts that allow you to use the Management and Messaging APIs respectively.

Try them both out now, with no arguments, to get a feel for what they offer.

Before invoking either the management or messaging script, ensure you're authenticated and connected to your CF org and space with cf login.

The management script offers queue and queue subscription related API endpoints:

user: cloud-messaging-handsonsapdev $ ./management
create_update_queue
delete_queue
get_queue
list_queues
list_queue_subscriptions
create_update_queue_subscription
delete_queue_subscription

The messaging script offers message production and consumption API endpoints:

user: cloud-messaging-handsonsapdev $ ./messaging
publish_message_to_topic
publish_message_to_queue
list_webhook_subscriptions
get_webhook_subscription
create_webhook_subscription
delete_webhook_subscription
trigger_handshake_request
pause_webhook_subscription
resume_webhook_subscription
consume_message_from_queue
acknowledge_message_consumption

Queue and queue subscription to a topic

Use the management script to create a test queue, and then connect it to the "salesorder/created" topic.

First, the queue. Let's call it "test":

user: cloud-messaging-handsonsapdev $ ./management create_update_queue test
{
  "name": "test",
  "messageCount": 0,
  "queueSizeInBytes": 0,
  "unacknowledgedMessageCount": 0,
  "maxQueueSizeInBytes": 0,
  "maxQueueMessageCount": 0,
  "respectTtl": null,
  "deadMsgQueue": null
}

Now, the queue subscription, connecting this "test" to the "salesorder/created" topic:

user: cloud-messaging-handsonsapdev $ ./management create_update_queue_subscription test salesorder/created
{
  "queueName": "test",
  "topicPattern": "salesorder/created"
}

Let's just check to see if there are any messages in this new "test" queue:

user: cloud-messaging-handsonsapdev $ ./management get_queue test
{
  "name": "test",
  "messageCount": 0,
  "queueSizeInBytes": 0,
  "unacknowledgedMessageCount": 0,
  "maxQueueSizeInBytes": 0,
  "maxQueueMessageCount": 0,
  "respectTtl": null,
  "deadMsgQueue": null
}

We can see from the value for the messageCount property that there are none (which makes sense, we've only just created it).

So far so good. Now we're ready to use the emit script again to create another "salesorder/created" message.

Publishing of another message

Back over in the first terminal (on the left in the screenshot above), use the emit script again to publish another message to the "salesorder/created" topic.

For those wondering, the message we published earlier disappeared, as there was no queue subscribed to the topic, and it is the queue mechanism, rather than the topic mechanism, where messages are held.

user: event $ ./emit 1
2020-12-31 13:59:15 Publishing sales order created event for 1
2020-12-31 13:59:15 Publish message to topic salesorder%2Fcreated

Back over in the second terminal (on the right), let's check again to see if there are now any messages in the "test" queue:

user: cloud-messaging-handsonsapdev $ ./management get_queue test
{
  "name": "test",
  "messageCount": 1,
  "queueSizeInBytes": 256,
  "unacknowledgedMessageCount": 0,
  "maxQueueSizeInBytes": 0,
  "maxQueueMessageCount": 0,
  "respectTtl": null,
  "deadMsgQueue": null
}

We now have one message in the queue!

Consuming the message from the queue

Let's consume that message, using the Messaging API. That way we can have a look at the details.

user: cloud-messaging-handsonsapdev $ ./messaging consume_message_from_queue test
2020-12-31 14:03:41 Consume message from queue
{"type":"sap.s4.beh.salesorder.v1.SalesOrder.Created.v1","specversion":"1.0","source":"/default/sap.s4.beh/DEVCLNT001","id":"db13c94e-c20f-4b2e-8171-6970104721a0","time":"2020-12-31T13:59:15Z","datacontenttype":"application/json","data":{"SalesOrder":"1"}}

Great - we can see that the message is indeed what we're expecting. If we format the message JSON, we can read it a little better:

user: cloud-messaging-handsonsapdev $ echo $'{"type":"sap.s4.beh.salesorder.v1.SalesOrder.Created.v1","specversion":"1.0","source":"/default/sap.s4.beh/DEVCLNT001","id":"db13c94e-c20f-4b2e-8171-6970104721a0","time":"2020-12-31T13:59:15Z","datacontenttype":"application/json","data":{"SalesOrder":"1"}}' | jq .
{
  "type": "sap.s4.beh.salesorder.v1.SalesOrder.Created.v1",
  "specversion": "1.0",
  "source": "/default/sap.s4.beh/DEVCLNT001",
  "id": "db13c94e-c20f-4b2e-8171-6970104721a0",
  "time": "2020-12-31T13:59:15Z",
  "datacontenttype": "application/json",
  "data": {
    "SalesOrder": "1"
  }
}

Nice work!