Skip to Content

I recently needed to prepare two talks. One for my presentation at #sitNL 2019, and one for one of my lectures.  well as one of my lectures. I both I wanted to show a simple demo involving different services from the SAP Cloud Platform. The demo should containing the following components:

  • A SAP NetWeaver backed System triggering a process in the SAP CP
  • A workflow implemented using the SAP CP Workflow service
  • A decision table implemented using the SAP CP Business Rules service
  • Optionally, an integration of SAP CP Mobile service, in particular Mobile Cards. This part will be covered in a future blog.

With the scope of the demo in place I needed a nice scenario for the demo. The most common scenario would have been using some kind of approval process. However, that seemed kind of boring. So I was looking for something more fun. Luckily, I watched an episode of The Walking Dead that evening and found a great scenario for the SAP CP!

The zombie scenario

The business scenario is basically a very simple description of what The Walking Dead is about. There is one guy named Rick. He is the leader of a group of people trying to survive in a wold full of zombies. Whenever he sees a zombie he does a quick assessment if the zombie needs to be killed or not. If the zombie needs to be killed Rick notifies his friend Daryl. Daryl is an experienced zombie hunter. He  has two weapons, a crossbow and a large knife. Depending on the information he receives from Rick Daryl decides which weapon is the most suitable one to kill the zombie. The whole scenario is shown in the figure below.

It is easy to see, that this scenario translates naturally to an SAP CP application architecture. This architecture. The world containing all these dangerous zombies is the ABAP back-end system. The ABAP back-end triggers a workflow in the SAP CP whenever a new zombie appears. This results in an work item in Ricks workflow inbox. Rick does the assessment and decides whether or not the zombie needs to be killed. If the zombie needs to be killed the workflow triggers the Daryl’s business rules, implements in the SAP CP business rules service, to decide how to best kill the zombie. Based on the result of the business service the appropriate killing action is executed and a notification is sent to Rick to inform him about the completion of the zombie killing. This basic architecture is shown in the figure below.

Building the zombie hunting application

In the next section I will describe the different elements comprising the zombie hunting application in detail. First, I’ll show how to implement the workflow. Next, I’ll show how to implement the business rules and test them via Postman. After that, I’ll show how to integrate the business rules and the workflow as well as how to test the workflow via Postman. Finally, I’ll show how to trigger the workflow form the back-end system.

The zombie workflow

The first step is build the zombie application workflow. This is done using the SAP Web IDE Full-Stack. In the SAP Web IDE create a new project by clicking on “New Project from Template” on the home screen. In the pop-up select the category “Process Management” and select “Workflow Project”.

The following figure show an overview of the zombie application workflow. When the process starts the first step is a user task. This user task notifies Rick in his inbox that a new zombie needs to be assessed. Rick will be able to decide by clicking a button to kill or to ignore the zombie. If the zombie is ignored a mail task is executed to notify Rick that the process ended and the zombie is ignored.

If Rick decides that the zombie needs to be killed. First a script task is executed in order to prepare the vocation of the rule service. Next a service task is executed invoking the business rules service. Depending on the weapon chosen by the business rules again a mail task is executed informing rick, that the zombie hast been killed by knife or crossbow respectively.

First user task: Assess Zombies

First, the user task to asses the zombies needs to be modeled. The following screenshot show the different properties of the task. In the example, the tasked is named Rick: Assess Zombie.

The task is of medium priority. The subject of the task is “Assess Zombie ${context.zombie_data.zombie_id}”. The content of the curly braces will during runtime be substitute with the content of the workflow context element zombie_data.zombie_id. In the SAP CP Workflow the context is a JSON object and the data of this context is read and set using ${context….} syntax.

Also the description of the task accesses the workflow context to provide a more detailed description of the task.

Finally, the user interface for the task is provided by a simple form. In this example the form is names zombie_info. Details of this form a shown below.

The form consist of a section with the title “Zombie Info”. Different data from the workflow context is shown inside this section. For example the “Zombie Type” is shown. The data for the zombie type originates from the workflow context (${context.zombie_data.zombie_type}). Furthermore, all form fields are set to read only.

On the decision tab of the form the tow possible decisions “Kill” and “Ignore” are available. The ID of the actions is used in the workflow to decide which path to take in the process.

The exclusive or gateway

The next step is to model the first exclusive decision gateway. The gateway has two possible sequence flows: the zombie needs to be killed or not. First, the sequence flow that the zombie does not need to be killed is modeled. This sequence flow is connected to a email task. Furthermore, it is labeled with “no” and marked as the default sequence flow. Using a default sequence flow assures, that the process doesn’t get stuck. When none of the conditions of the other sequence flows is valid the workflow engine will always execute the default sequence flow. The screenshot below shows the properties of the sequence flow.

The sequence flow for the case when the zombie needs to be killed is connected to a script task. The properties of this sequence flow are shown below. It is labeled with “yes” and the condition for this sequence flow to be executed is set to ${usertasks.usertask1.last.decision==”kill”}. The usertask element of the workflow context contains the results of the user tasks. In this example the usertask has the ID usertask1. The decision taken by the user is found in the element last.decision. It is set to the ID of the action taken by the user (see the form for the user taska above).

The email tasks

The properties of the email task for the case when the zombie is not killed is shown below. A email is sent to an email address which is hard coded in the task in this example. The subject is set to “Zombie ignored” and the mail body contains some information of what happened. The other two mail tasks in the workflow are pretty similar. Only the mail text differs in order to distinguish using which weapon a zombie has been killed.

Sending email from the mail task requires that the destination “bpmworkflowruntime_mail”. Details on how to configure this destination are available here.

The script task

The script task contains a simple JavaScript script that prepares the workflow data for the invocation of the rule service. The source code of the script used in the example is shown below. An InvokeRuleService element is added to the workflow context. This request contains a simple element “request”. This element only has a “__type__” which is defined later in the rule service and a value “zombie_type” which is taken from the context.

var request = {
		"__type__": "rule_input",
		"zombie_type": $.context.zombie_data.zombie_type };

var invoke_rule_service = {
		"request" : request
};

$.context.InvokeRuleService = invoke_rule_service;

Invoking the zombie killing rules

The next step is to invoke the rule service to decide how a zombie needs to be killed. This is done using a service task. The configuration of the service task in the example is shown below. The service invokes the business rules via the destination bpmrulesruntime. This destination is configures automatically when the business rules service is activated. The service that is invoked is chosen form the SAP API Hub. Here the Rule Execution API for Neo is selected.

The path to the rules service is “/rules-service/rest/v1/rule-services/java/zombie_rules/zombie_rule_service”. This path consists of the generic part “/rules-service/rest/v1/rule-services/java/” followed by the name of the rules project (zombie_rules) and the rule service that is invoked (zombie_rule_service).

Handling of the XSRF-token is done automatically by the script task. Only the URL of the service to request the token needs to be configured (/rules-service/v1/rules/xsrf-token in this case).

Finally, the Request and Response Variable define where in the workflow context the rules service request and response are stored (cf. the script task above).

After everything has been modeled the form, the script and the workflow can be deployed to the SAP CP.

The final killing decision

Depending on the results of the rule set an exclusive gateway is used to decide which sequence flow is executed, i.e. using which weapon a zombie is killed. Again, one of the sequence flows is modeled as a default flow. The condition of the second sequence flow is shown below. If the rule service response contains as a weapon type the crossbow, this sequence flow is executed. The correspondign condition is ${context.InvokeRuleService.response.weapon_type == “crossbow”}.

 

The zombie rules

The zombie business rules are a simple decision table. The rules are created using the Business Rules Editor. The Business Rules Editor is available form the Business Rules service of the SAP CP. Documentation on how to activate and configure the Business Rules service is available here.

First, a business rules project is created in the Business Rules Editor. The zombie_rules projects in the example contains two data object. One named rule_input and one named rule_output.

The structure of the two data objects is shown in the following screenshots. The data object rule_input consists of two data elements, a zombie_danger_level and a zombie_type. The data object rule output just contains the weapon_type (which will be used to kill the zombies). Note that this are exactly the structures we used when modelling the workflow. For example, in the script task an we set the __type__ attribute to “rule_input”.

In the rule service the data objects are assigned to the input and result of a rule respectively. Using the rule service it is defined that the data object rule_output is used as a rule result in this particular service.

In the example the rules project contains a single business rule named zombie_rule. This rule is a decision table. Based ion the zombie_type of the rule input a certain weapon is chosen and the rule output is set accordingly. If the zombie_type, e.g., is equal to ‘Lurker’, the ‘knife’ is chosen as the appropriate weapon_type.

Note that in the rule table the deliminator for strings is a single quote (‘) not a double quote as one might expect.

Finally, the ruleset links a rule to the rule service. In this example the zombie_rule to the zombie_rule_service.

Once everything has been modeled all the artifacts created in the Business Rules Editor need to be activated. After that the rule service can be deployed to the SAP CP.

Testing the zombie rules

Once the rules have been deployed it is possible to test them via the Business Rules REST API. The APIs of all the service available in the SAP CP can be found on the SAP API Business Hub. The API of the Business Rules service is available here.

One of the nice features of the SAP API Business Hub is, that it can be used to test APIs directly. The APIs can either be tested using a sandbox or using real service. I configures an environment for the business rules service in the SAP CP Trial. Using this configuration it is possible to the the rules service. To do this it is first necessary to request a XSRF-Token from the service.

Using the obtained XSRF-Token it is now possible to invoke the rule service via the Invoke Rule Service API. As an input the project and the ruleservice name are required (in the example zombie_rules and zombie_rule_service). Furthermore, the XSRF token as well as a request body needs to be provided. The request body for this example ist

[
  {
    "__type__": "rule_input",
    "zombie_type": "Lurker"
  }
]

Using this information the service can be invoked.

if the provided information is correct, the service is invoked an the rule result is returned in the response body. In this example the following result is returned:

[
  {
    "__type__": "rule_output",
    "weapon_type": "knife"
  }
]

As we can see the business rules were executed correctly as lurker zombies should be killed using a knife.

Testing the zombie workflow

The connection between the workflow and the business rules has already be established when the script task of the workflow as configured. Therefore, it is now possible to test the whole scenario using the workflow API. It is possible to do this using the SAP API Business Hub. However, for regular tests of APIs Postman is much more convenient. Using postman it is possible to store request and executing them multiple times. In order to test the zombie workflow it is first necessary to obtain an XRSDF-Token again.

Instantiating a service is done by sending a POST request /v1/workflow-instances API endpoint. In this POST request the workflow definition as well as the context data needs to be send as a body. In this example the following data was sent.

{
  "definitionId": "zombie_wf",
  "context": {
  	"zombie_data" : {
		"zombie_id" : "sitNL",
		"zombie_type" : "Lurker",
		"zombie_danger_level" : 250
	}
  }

This will instantiate the workflow with the ID zombie_wf and provide the context data to the workflow instance. If the instantiation of the workflow was successful, the ID of the instance will be returned. This can be seen in the following screenshot. This is a screenshot of using Postman to invoke the service.

In the monitoring application of the SAP CP Workflow service now one instance of the zombie_wf is running. The execution log of the monitoring application shows, that the workflow was started and that currently the “Assess Zombie sitNL” user task is waiting to be executed.

In the workflow inbox of Rick (or in this case myself) there is now one task. The UI of this task is the form we created in the SAP Web IDE when modeling the workflow. Also the task has tow possible action: Kill or Ignore the zombie. Depending on which button is clicked the corresponding sequence flow and tasks of the workflow are executed.

Clicking on Kill would result in the execution sequence shown in the screenshot below. First the “Prepare Daryl” script task is executed. Then the business rules are invoked (“Execute Daryl in the example). Finally, a mail task is executed sending an email that the zombie was killed by Daryl using a knife.

Integrating the zombie world

The final step is integration the process into the zombie world, i.e. an ABAP back-end system. To invoke the workflow only a call to the appropriate API is necessary. The following ABAP code snippet can be used to invoke the workflow service. Basically what happens in this code snippet is straight forward.

First a http_client is instantiated for the API to request an XSRF-Token. The required APIKey can be obtained from the SAP API Business Hub. The example uses basic authentication to access the service. For this username:password needs to be provided in base64 encoding in authorization header. Once the XSRF-Token has been obtained a new request is created to instantiate the workflow. In order for the XSRF-Token to be valid the cookies of the first request need to be copied over to the second one (LOOP AT cookies… below). The body data is provided as simple string containing the JSON data. With this the service can be instantiated.

 

REPORT zcd_zombie_runner.

DATA: http_client TYPE REF TO if_http_client.
DATA: token TYPE string.

cl_http_client=>create_by_url(
  EXPORTING
    url = 'https://bpmworkflowruntimewfs-p650074trial.hanatrial.ondemand.com/workflow-service/rest/v1/xsrf-token'
  IMPORTING
    client = http_client ).

http_client->request->set_method('GET').

http_client->request->set_header_field( name = 'X-CSRF-Token' value = 'Fetch' ).
http_client->request->set_header_field( name = 'Content-Type' value = 'application/json' ).
http_client->request->set_header_field( name = 'Accept' value = 'application/json' ).
http_client->request->set_header_field( name = 'APIKey' value = '<your api key>' ).

"Basic Auth : provide username:password in Base64 encoded in Authorization header
http_client->request->set_header_field( name = 'Authorization' value = 'Basic <base64 encoding od username:password>' ).

http_client->send(
  EXCEPTIONS
    http_communication_failure = 1
    http_invalid_state         = 2
    http_processing_failed     = 3
    http_invalid_timeout       = 4
    OTHERS                     = 5 ).

IF sy-subrc = 0.
  http_client->receive(
    EXCEPTIONS
      http_communication_failure = 1
      http_invalid_state         = 2
      http_processing_failed     = 3
      OTHERS                     = 5 ).
ENDIF.

token = http_client->response->get_header_field( 'X-CSRF-Token' ).

DATA cookies TYPE  tihttpcki.
http_client->response->get_cookies( CHANGING cookies = cookies ).


cl_http_utility=>set_request_uri(
  EXPORTING
    request = http_client->request
    uri     = 'https://bpmworkflowruntimewfs-p650074trial.hanatrial.ondemand.com/workflow-service/rest/v1/workflow-instances'
).

LOOP AT cookies ASSIGNING FIELD-SYMBOL(<cookie>).
  http_client->request->set_cookie( name = <cookie>-name
                                    value = <cookie>-value ).
ENDLOOP.

"setting request method
http_client->request->set_method('POST').

"adding headers
http_client->request->set_header_field( name = 'X-CSRF-Token' value = token ).

http_client->request->set_cdata(
    data = '{ "definitionId": "zombie_wf", "context": { "zombie_data" : { "zombie_id" : "The mighty ABAP Zombie", "zombie_type" : "Monster", "zombie_danger_level" : 44300 } } }' ).

http_client->request->set_header_field( name = 'Authorization' value = 'Basic <base64 encoding od username:password>' ).

http_client->send(
  EXCEPTIONS
    http_communication_failure = 1
    http_invalid_state         = 2
    http_processing_failed     = 3
    http_invalid_timeout       = 4
    OTHERS                     = 5 ).

IF sy-subrc = 0.
  http_client->receive(
    EXCEPTIONS
      http_communication_failure = 1
      http_invalid_state         = 2
      http_processing_failed     = 3
      OTHERS                     = 5 ).
ENDIF.

IF sy-subrc <> 0.
  "error handling
ENDIF.

DATA code TYPE i.
DATA reason TYPE string.

http_client->response->get_status( IMPORTING code = code reason = reason  ).

WRITE: code.
WRITE: reason.

The JSON data sent in the ABAP code is the following:

{
	"zombie_data" : {
		"zombie_id" : "The mighty ABAP Zombie",
		"zombie_type" : "Monster",
		"zombie_danger_level" : 44300
	}
}

Using this data the following workflow inbox item is created:

Now it is upon Rick to decide what will happen to the mighty ABAP zombie. Happy zombie killing…

 

To report this post you need to login first.

3 Comments

You must be Logged on to comment or reply to a post.

  1. Nabheet Madan

    Wow Christian great stuff. I have watched the complete series but this never occured to me😀. After reading your blog i think now some cool series will also watched from another angle.

    One complaint though instead hunting Zombies you should have Negan the so called Saviors🤣

    Thanks

    Nabheet

     

    (1) 
    1. Christian Drumm
      Post author

      Hi Nabheet,

      the problem is, that the latest season is not on Amazon Prime yet. So I don‘t know what happens to Negan. So I took the safe bet and chose zombies… 😜

      Christian

      (0) 

Leave a Reply