RAP Based Events in SAP S/4HANA Cloud ABAP Environment ( aka Embedded Steampunk )

Event Driven Architecture has gained a lot of popularity in recent times as businesses are looking to leverage it to become flexible , agile and scalable. Events are used more and more for real time integration with 3rd party systems without the need to extend the core. There are great many blogs already written about Event Driven Architecture and Event Mesh and how to configure event mesh to send events from S/4HANA On-Premise or cloud system to BTP Event mesh. This blog is focused more on ABAP RESTful Application Programming Model ( RAP ) based events introduced as part of the recent release.

With the release of BTP ABAP environment 2208 and developer extensibility( Embedded Steampunk) in S/4HANA Cloud , ABAP RESTful Application Programming Model framework now supports event driven architecture natively. Events represent a significant change of state of the RAP business objects or of one of its child entity that is relevant for follow-up processes . RAP BO’s can act as both Event Consumer and Event Producer.

Just like the standard SAP S/4HANA On-Premise or Cloud events RAP based events too work together with event mesh as a message broker to produce or receive events , we will continue the discussion with the assumption that Event mesh is already configured in your system and Channels are already set up for outbound topic binding.

RAP Business Objects as Event Consumers

Events can be consumed from the Event Mesh Queue using the newly introduced event consumption model . Event Consumption Model can be created using the AsyncAPI JSON file for a particular event , the consumption model based on the payload mentioned in the AsyncAPI JSON creates an abstract entity , consumer class and a consumer extension class , the consumer extension class can then be used to plugin our custom logic on how the event should be handled. For Example a sales order can be created using a RAP BO based on the event payload.

Please check the below tutorial which explains in great detail on how to configure Event Mesh in a SAP S/4HANA cloud system and how to Consume Events using the Event Consumption Model.

Event Consumption in ABAP Development Tools using RAP BO

RAP Business Objects as Event Producers

RAP entity events are defined through Behavior Definition on root node level for both managed and unmanaged scenario. Entity events can have a parameter ( Abstract CDS Entity ) which acts as the event payload and is optional. If no parameter is defined the keys for the root BO is used as the event payload. The RAP Event created will be then mapped to a event type using “Event Binding” which will allow the event to be configured as an Outbound Topic in our event mesh Channel. This topic is then subscribed by an event mesh queue for further processing, messages can be consumed by 3rd party systems from the queue directly.

The event can also be triggered from outside the RAP Business object by wrapping the “Raise Event” in a local class in the behavior pool class and calling the same by creating static method in the global class pool of the behavior implementation class. This static method can be then used to raise the events from outside the RAP BO by passing the payload as an importing parameter.

For this use case a simple RAP BO is created which will send an event for every new instance created using the RAP BO , a parameter is defined for the event using an abstract entity that acts as payload structure to send additional Contact Details along with the partner number created. Keyword “RAISE ENTITY EVENT” is then used to raise the event when a new instance is created , this is implemented within its own behavior pool using an additional save. 

Interface View 

@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Interface View for Contact Info'
define root view entity ZI_CONINFO as select from ztabconinfo
{ key bpno as Bpno, firstname as Firstname, lastname as Lastname, @Semantics.eMail.address: true email as Email, @Semantics.user.createdBy: true local_created_by as LocalCreatedBy, @Semantics.systemDateTime.createdAt: true local_created_at as LocalCreatedAt, @Semantics.user.lastChangedBy: true local_last_changed_by as LocalLastChangedBy, //local ETag field --> OData ETag @Semantics.systemDateTime.localInstanceLastChangedAt: true local_last_changed_at as LocalLastChangedAt, //total ETag field @Semantics.systemDateTime.lastChangedAt: true last_changed_at as LastChangedAt
}

Consumption View 

@EndUserText.label: 'Consumption View for Contact Info'
@AccessControl.authorizationCheck: #NOT_REQUIRED
@Metadata.allowExtensions: true
@Metadata.ignorePropagatedAnnotations: true
define root view entity ZC_CONINFO provider contract transactional_query as projection on ZI_CONINFO
{ key Bpno, Firstname, Lastname, Email, LocalLastChangedAt
}

Metadata Extension 

@Metadata.layer: #CORE
@UI: { headerInfo: {
typeName: 'User',
typeNamePlural: 'Users',
title: { type: #STANDARD, value: 'Bpno' } }, presentationVariant: [{ sortOrder: [{ by: 'Bpno', direction: #DESC }], visualizations: [{type: #AS_LINEITEM}] }] }
annotate view ZC_CONINFO with
{ @UI.facet: [ { label: 'General Information', id: 'GeneralInfo', type: #COLLECTION, position: 10 }, { id: 'Userdetails', purpose: #STANDARD, type: #IDENTIFICATION_REFERENCE, label: 'User Details', parentId: 'GeneralInfo', position: 10 } ] @UI: { lineItem: [ { position: 10, importance: #HIGH , label: 'User Number'} ] , identification: [ { position: 10 , label: 'User Number' } ] } Bpno; @UI: { lineItem: [ { position: 20, importance: #HIGH , label: 'First Name'} ] , identification: [ { position: 20 , label: 'First Name' } ] } Firstname; @UI: { lineItem: [ { position: 30, importance: #HIGH , label: 'Last Name'} ] , identification: [ { position: 30 , label: 'Last Name' } ] } Lastname; @UI: { lineItem: [ { position: 40, importance: #HIGH , label: 'Email Address'} ] , identification: [ { position: 40 , label: 'Email Address' } ] } Email; }

Behavior Definition for Interface view

In the below behavior definition the event is defined along with a CDS abstract entity as a parameter. The Keys for the RAP BO along with the parameter makes the payload for the event.

managed implementation in class zbp_i_coninfo unique;
strict ( 2 );
with draft; define behavior for ZI_CONINFO alias Userdetails
persistent table ztabconinfo
draft table ztabconinfod
lock master
total etag LocalLastChangedAt
authorization master ( instance )
with additional save
{ create; update; delete; field ( readonly ) LastChangedAt, LocalLastChangedBy, LocalLastChangedAt, LocalCreatedBy, LocalCreatedAt; event SendContact parameter ZABS_EVENTSTRUC; draft action Edit; draft action Activate; draft action Discard; draft action Resume; draft determine action Prepare; }

CDS Abstract Entity

This will act as the Event Payload along with the RAP BO Key.

@EndUserText.label: 'Event Structure'
define abstract entity ZABS_EVENTSTRUC
{ firstname : abap.char(20); lastname : abap.char(20); email : abap.char(20); created_by : abp_creation_user; created_at : abp_creation_tstmpl; }

Raising the event in Save Modified 

The event is then raised in Save Modified method of the Implementing class for the behavior definition. For our use case we don’t want to raise an event for update or delete and hence the additional check is performed to ensure that the event is raised only for Create Scenarios.

method save_modified. if create-userdetails is not initial. raise entity event zi_coninfo~SendContact from value #( for userdet in create-userdetails ( Bpno = userdet-Bpno firstname = userdet-Firstname lastname = userdet-Lastname email = userdet-Email ) ). endif. endmethod.

The Behavior definition for the consumption view , the Service definition and the ODataV4 UI Service binding is then created to expose the Business object. Once the Service is published we can then  create an event binding to map the RAP Event and RAP BO and create a custom topic which will be the configured in the EM outbound channel for outbound communication.

The Namespace, Business object and Business Object Operation together becomes the topic for this event as can be seen in the field “Type” below.

The Root Entity and the Event defined in the BDEF is then added as shown below to the Event Binding to map it to the name space.

Event%20Binding

Event Binding

The Event is then available in the dropdown for outbound topics and can be configured in the SAP S/4HANA Cloud Event mesh Channel as an Outbound Topic.

Configured%20as%20an%20Outbound%20Topic

Available under Outbound Topic

RAP%20Event%20configured%20as%20outbound%20Topic

RAP Event configured as outbound Topic

This is now ready for consumption and can be subscribed to an event mesh queue as shown below. The message can then be consumed from event mesh queue using the standard consumption model such as AMQP, REST , Webhook or now from another RAP business object.

Topic%20Subscribed%20in%20the%20EM%20Queue

Topic Subscribed in the EM Queue

To test the application we can then create a new Instance with the corresponding contact details, on saving the contact info an event will be raised which will then send the contact details to the EM queue.

New%20Instance%20Created

New Instance Created

Message%20Received%20in%20Queue

Message Received in Queue

Event payload

In conclusion, native support of RAP based events dramatically strengthens SAP’s capability to support event driven architecture and gives us as developers the capability make our applications agile and flexible. This will also enable us to extend standard business processes with additional functionality or post processing steps without the need of enhancement keeping the core clean. Using RAP as an event producer we can now have our own custom event which can be used for all the scenarios where Standard events are not available or Simple Notification event doesn’t suffice the requirement , in saying so we should not forget that events are means to be lightweight and hence the payload should be kept to essential fields only.

Below are some of the materials I referred to while writing this blog and can provide more insights additionally I would highly recommend going through the tutorial for event consumption scenarios .  Let me know what you think of this new feature in comments below and please provide feedback.

RAP Business Events

Creating Business Events

Creating Event Consumption Model