Skip to Content
Technical Articles
Author's profile photo Ayush Kumar

[Blog Post] SAP Event Mesh – CAP based implementation of SAP Event Mesh in a Single-Tenant Scenario

Authors: Ayush Kumar & Vipul Khullar 

Previous blog post in this series:

  1. [Blog Series] SAP Event Mesh – Deep Dive | SAP Blogs
  2. [Blog Post] SAP Event Mesh – Event Driven Architecture Explained | SAP Blogs
  3. [Blog Post] SAP Event Mesh – Single Tenancy & Multi-Tenancy Explained | SAP Blogs

Introduction:

In the previous few blog posts, we covered the basic concept and understanding of event-driven architecture, SAP Event Mesh Service, and its rest-based implementation.

In this blog post, we will explore how we can use the CAP framework to abstract ourselves from the underlying implementation thereby simplifying the work for us, unlike what we saw in the rest-based examples in the previous blog post.
There are multiple flavors of Messaging services, but the focus of this blog will be on SAP Event Mesh.

  1. Local Messaging
  2. File-Based Messaging
  3. Real Broker Based [SAP Event Mesh]

It is also possible to use local messaging and file-based messaging in CAP for asynchronous event-based communication. However, as part of this ongoing series, we will only focus on SAP Event Mesh Implementation.

Note:

  1. We will showcase all the implementations in a local setup, using the event mesh instance created in the previous blog post and not by deploying to BTP. However, all the steps remain the same even if you deploy to BTP.
  2. We plan only to cover the JAVA-based implementation, for Node-based implementation you can refer to  SAP Event Mesh: Multitenant Sample Scenario 1 | SAP Blogs

 

Pre-requisites:

To execute the following scenario, you need.

  1. BTP account (trail account would also work).
  2. Event Mesh entitlement for your subaccount.
  3. Service key for the Event Mesh instance.
  4. Local Setup for CAP JAVA (if you already have a CAP application initialized upgrade the CDS service version to 1.22.1 or higher, else you might face runtime errors complaining about bean error).

 

Scenario:

Architecture%20Diagram%20for%20Event%20Mesh%20based%20Communication%20between%20two%20CAP%20based%20microservices

Architecture Diagram for Event Mesh-based Communication Between Two CAP based Microservices

In this scenario, we have created two CAP-based microservices on BTP and we have tried to set up an event-based communication between the services with the help of Event Mesh. We have tried to leverage the CAP framework in JAVA for the emission and consumption of the event.

Project Setup

mvn archetype:generate -DarchetypeArtifactId="cds-services-archetype" -DarchetypeGroupId="com.sap.cds" -DarchetypeVersion="RELEASE"

This opens an interactive mode to setup your application in terminal/Command Line.

OR

you can download our sample application here.

Note: Your application name need not be the same as ours.

  • Navigate to db and create a schema.cds file
namespace sap.capire.enterpriseMessagingProducer; 
 
 using {  cuid, managed } from '@sap/cds/common'; 
 
entity student : cuid , managed { 
 
    firstName : localized String(100); 
    lastName : localized String(100); 
    currentClass : String(10); 
     
} 
 
  • Create a <service>.cds file
using { sap.capire.enterpriseMessagingProducer as db}  from '../db/schema'; 
 
service EnterpriseMessagingProducerService { 
 
    entity Students as projection on db.student; 
 
} 
  • In parent Pom.xml add the dependencies
<dependency>
    <groupId>com.sap.cds</groupId>
    <artifactId>cds-feature-enterprise-messaging</artifactId>
    <scope>runtime</scope>
</dependency>
  • Navigate to srv->src->main->resources->application.yaml
cds: 
  messaging.services: 
    - name: "messaging" 
      kind: "enterprise-messaging" 

  • Add default-env.json file to simulate binding to the Event Mesh instance in BTP
{ 
    "VCAP_SERVICES" : { 
    "enterprise-messaging": [{ 
      "label": "enterprise-messaging", 
      "credentials":{ 
        /*  add your service key here*/ 
           
      }  
    }] 
  } 
} 
  • Producer Handler.java
package com.sap.enterprisemessagingproducer.handlers;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import com.nimbusds.jose.shaded.json.JSONArray;
import com.nimbusds.jose.shaded.json.JSONObject;
import com.sap.cds.services.cds.CdsService;
import com.sap.cds.services.handler.EventHandler;
import com.sap.cds.services.handler.annotations.On;
import com.sap.cds.services.handler.annotations.ServiceName;
import com.sap.cds.services.messaging.MessagingService;

import cds.gen.enterprisemessagingproducerservice.Students;
import cds.gen.sap.capire.enterprisemessagingproducer.Student;

@Component
@ServiceName("EnterpriseMessagingProducerService")
public class ProducerHandler implements EventHandler {

    private static final Logger logger = LoggerFactory.getLogger(ProducerHandler.class);

    @Autowired
    @Qualifier("messaging")
    MessagingService messagingService;

    @On(event = CdsService.EVENT_CREATE, entity = "EnterpriseMessagingProducerService.Students")
    public void produceStudentEnrollementEvent(List<Students> studentlists) throws Exception {

        JSONObject payload = new JSONObject();

        JSONArray jsonArray = new JSONArray();

        for (Students students : studentlists) {
            JSONObject jsonObject = new JSONObject();

            jsonObject.put(Student.FIRST_NAME, students.getFirstName());
            jsonObject.put(Student.LAST_NAME, students.getLastName());
            jsonObject.put(Student.CURRENT_CLASS, students.getCurrentClass());

            jsonArray.add(jsonObject);

        }

        payload.put("data", jsonArray);

        logger.info("Data Emitted to the topic  {}", payload.toJSONString());
        messagingService.emit("com/eventmesh/blog/StudentEnrolled", payload);

    }
}

Here, we have used a handler to emit events but it is also possible to emit events directly from CDS service layer. You can refer here for more details.

  • Now run the application

Queue%20and%20Topic%20created%20by%20CAP%20implicitly

Application Log for CAP Microservice

Observations:

  1. If you do not explicitly create a queue and assign a topic to it, then the enterprise-messaging service automatically creates a queue for you and subscribes to the topic implicitly.
  2. If you create a queue yourself and refer to it in your application.yaml file no such random queue is created.
  3. It will also point out that we are not able to register the queue subscription automatically, the reason being that we did not follow the rules specified by the event mesh service to append the topic/queue names with respective namespaces (if you don’t follow the specified naming structure as described in the previous blog post).

Queue%20created%20in%20SAP%20Event%20Mesh%20by%20CAP

Queue Created in SAP Event Mesh by CAP

 

Queue%20Subscription%20created%20by%20CAP

Queue Subscription Created by CAP

Input:

Post%20Request%20to%20create%20a%20student%20record

Post Request to Create a Student Record

 

Output :

Receiving%20Message%20from%20CAP%20Microservice

Receiving Message from CAP Based Microservice

Reading%20the%20Event%20In%20SAP%20Event%20Mesh%20UI

Reading the Event In SAP Event Mesh UI

Now let’s create two consumers one within the same microservice and the other one in a different microservice.

  1. For the same microservice you just need to create a new handler/java class.
  2. For different microservice we need to follow the same steps as we have followed to create the producer or you can download it from here
    1. You need to have the same default-env.json as that of the producer to bind it to the same instance.
    2. Now run it on any other port as we will run the first microservice on 8080.
  • Consumer Handler.java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.sap.cds.services.handler.EventHandler;
import com.sap.cds.services.handler.annotations.On;
import com.sap.cds.services.messaging.TopicMessageEventContext;

@Component
public class ConsumerHandler implements EventHandler{
    

    private static final Logger logger = LoggerFactory.getLogger(ConsumerHandler.class);

    @On(service = "messaging", event = "com/eventmesh/blog/StudentEnrolled")
    public void listen(TopicMessageEventContext context) {
        
        logger.info("---------------------------Reading Payload Emitted by the Event----------------------------------------------------");
         logger.info("checking if the message if read from SAP Event Mesh 
{}",context.getIsInbound());
        logger.info("reading event id{}",context.getMessageId());
        logger.info("reading event data{}", context.getData());
    }

}

 

  • context.getIsInbound returns true if the message is received from a remote service and not locally.

Creating%20a%20new%20Student%20Entity%20in%20Producer%20Microservice

Creating a New Student Entity in Producer Microservice

 

Consuming%20Events%20in%20Two%20different%20microservices

Consuming Event in a Different Microservice

 

Snapshot%20of%20the%20queue%20and%20consumption%20microservice

Snapshot of the Queue and the Consuming Microservice

 

If you look at the SAP Event Mesh queue you will see that we have read the message from the queue.
Sometimes it might happen that for a fraction of a second you might see the message count as non-zero but that’s because the messages in the queues are waiting for the acknowledgment from your application before it gets removed.

Conclusion:
 In this blog post, we have showcased how we can leverage the CAP framework to easily implement SAP Event Mesh Service in our application. It is also important to note that we can use multiple types of messaging services in a single application to perform various operations if required. Also since this series is specifically related to SAP Event Mesh, we did not discuss the working and implementation of other types of messaging services available in CAP. But we will highly encourage you to look at our repository where we have implemented all of them in separate branches.
We also did not look upon the webhook mechanism which can be very useful if we are using any other application apart from CAP to communicate with SAP Event Mesh. Let us know in the comment section if you wish to know more about them then we will take these topics in future blog posts.

In the next few blog posts of this series, we will focus on how we can leverage SAP Integration Suite to establish communication between different microservices.

Next blog in this series: [Blog Post] SAP Event Mesh – Enable SAP Cloud Integration Suite to Consume Messages from SAP Event Mesh Service | SAP Blogs

 

 

Assigned Tags

      Be the first to leave a comment
      You must be Logged on to comment or reply to a post.