Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
Former Member

This blog post, as part 6 of BPM OData blog series, refers to the OData Service in SAP BPM available with SAP NetWeaver 7.3 EHP 1 SP 09 and higher. The features described in this blog post are available with SAP NetWeaver 7.3 EHP 1 SP 14 and higher. Before reading this blog post, it is recommended to read the previous parts of BPM OData blog series.

Overview

This blog post as well as all the previous blog posts about the BPM OData service is based on the business scenario in a credit institution. Previously, the scenario was considered from the point of view of the different participants. We were considering it from the point of view of the employees of the credit institution when we were talking about implementation of a task UI as well as from the point of view of the customer who submitted his data in the blog post about a process start UI. In this blog post, the scenario will be considered from the point of view of the department manager of the credit institution. One of the responsibilities of such a manager is to monitor and manage all the activities in his department. In our case, the BPM process containing the tasks to verify the customer data and to provide a credit limit can be considered as an example of the activity. Therefore, monitoring and management of the activities becomes monitoring and management of the processes. This blog post describes how to build an SAPUI5 application for such an administrative UI.

BPM Processes OData Service

Starting from SAP NetWeaver 7.3 EHP 1 SP 14 the BPM OData service provides functionality to access a collection of processes and to perform operations on a process. For that purpose, BPM Processes OData service should be used. This service as well as all the BPM OData services is available under ‘bpmodata’ root URL and has the ‘processes.svc’ name. The set of operations provided by the service includes the following:

  • Access to a collection of BPM processes
  • Suspend a process
  • Resume a process
  • Cancel a process

The service URLs can be represented using the following pattern:

http://<host>:<port>/bpmodata/processes.svc/<OData_resource_path_and_query_options>

Accessing a Collection of Processes

One of the responsibilities of the department manager in the business scenario is to monitor processes in his department. In scope of this activity, the manager should be able to see the processes including the information about the process time line, status, and the person who started the process. To represent information about a process, the BPM Processes OData service provides ProcessInstance entity type which contains all the required information. The metadata for the entity type is shown below:


<EntityType Name="ProcessInstance">
    <Key>
        <PropertyRef Name="InstanceId"/>
    </Key>
    <Property Name="InstanceId" Type="Edm.String" Nullable="false"/>
    <Property Name="Name" Type="Edm.String" Nullable="false"/>
    <Property Name="Subject" Type="Edm.String" Nullable="true"/>
    <Property Name="StartDate" Type="Edm.DateTimeOffset" Nullable="false"/>
    <Property Name="EndDate" Type="Edm.DateTimeOffset" Nullable="true"/>
    <Property Name="ModelId" Type="Edm.String" Nullable="false"/>
    <Property Name="DefinitionId" Type="Edm.String" Nullable="false"/>
    <Property Name="Status" Type="Edm.String" Nullable="false"/>
    <Property Name="ParentProcessInstanceId" Type="Edm.String" Nullable="true"/>
    <Property Name="RootProcessInstanceId" Type="Edm.String" Nullable="true"/>
    <Property Name="ProcessInitiatorName" Type="Edm.String" Nullable="true"/>
</EntityType>









In order to get a list of processes from the OData service, ProcessCollection entity set is used, which represents a collection of ProcessInstance entities.

More information about the service entity model can be found in the official documentation.

Obviously, a credit institution can have lots of processes. Some of them can be completed because a credit limit has been provided for the customer. Others can be canceled because the customer decided not to take a credit. Showing such processes to the manager makes no sense at all and makes the monitoring more difficult. Moreover, provisioning of all the processes via the OData service takes a lot of processing time on the server. Such a meaningless server load keeps the manager waiting. Which is definitely not what is expected. Based on the previous blog posts, some of you probably guessed that everything goes to the usage of $filter OData query option to limit the number of the returned entities and reduce the workload on the server. With the help of $filter query option the manager can specify which processes he would like to see and not to wait until all the processes are provided by the OData service.

In the BPM Processes OData service, every request to ProcessCollection entity set must have $filter query option in the request URL.

The table below shows the URL used to access a collection of processes along with the service response:

HTTP MethodGET
URL…/bpmodata/processes.svc/ProcessCollection?$filter=Status eq 'IN_PROGRESS' or Status eq 'SUSPENDED'&$format=json

Response Body

(simplified)


{
    "d": {
        "results": [
            {
                "InstanceId": "ffef91d67b8a11e4c1f300000034b6ba",
                "Name": "CreateCustomerProcess",
                "Subject": "Customer creation process",
                "StartDate": "/Date(1417679765790)/",
                "EndDate": null,
                "ModelId": "e007956a10a6daea576611e3c5c62c413890274c",
                "DefinitionId": "6c09936a310d118017f49889dfe194ec",
                "Status": "IN_PROGRESS",
                "ParentProcessInstanceId": null,
                "RootProcessInstanceId": null,
                "ProcessInitiatorName": "John_Smith"
            }
        ]
    }
}









In the sample URL, $filter query option is used to retrieve all the running and suspended processes. Besides the $filter query option, $top and $skip query options are also supported for the ProcessCollection. More information about supported URLs for the ProcessCollection entity set and about the usage of $filter query option for it can be found in the official documentation.

Of course, the department manager is only interested in the processes which are running in his department. Therefore, the service response provides processes for which the current user is the process administrator. As a result, the manager can see only the processes which he is allowed to see and the ones he can manage, i.e. suspend, resume or cancel.

Performing Operations on a Process

Besides providing access to a collection of processes, the BPM Processes OData service also allows to suspend, resume or cancel a process. In our business scenario, the process can be suspended if an additional information should be provided by the customer and resumed once the required information is provided. The process can be canceled if a customer changed his mind and decided not to take a credit.

All the mentioned process actions are implemented as Suspend, Resume and Cancel function imports in the BPM Processes OData service. Each of the function imports works in a similar way requiring identifier of the process instance as the only input parameter and providing suspended, resumed or canceled process instances in the service response respectively.

The table below shows the URL used to suspend a process along with the service response:

HTTP MethodPOST
URL…/bpmodata/processes.svc/Suspend?InstanceId='ffef91d67b8a11e4c1f300000034b6ba'
Request HeadersAuthorizationBasic dXNlcm5hbWU6cGFzc3dvcmQ=
X-CSRF-Token781057a9-b96a-468c-b393-981f98292335
Acceptapplication/json
Response Body

{
    "d": {
            "InstanceId": "ffef91d67b8a11e4c1f300000034b6ba",
            "Name": "CreateCustomerProcess",
            "Subject": "Customer creation process",
            "StartDate": "/Date(1417679765790)/",
            "EndDate": null,
            "ModelId": "e007956a10a6daea576611e3c5c62c413890274c",
            "DefinitionId": "6c09936a310d118017f49889dfe194ec",
            "Status": "SUSPENDED",
            "ParentProcessInstanceId": null,
            "RootProcessInstanceId": null,
            "ProcessInitiatorName": "John_Smith"
    }
}









In order to suspend, resume or cancel a process, the service user should be the process administrator.

Implementing the UI

Knowing the details about the consumption of the BPM Processes OData service the next step is to implement an administrative UI via the service. As it was mentioned before, such a UI should allow the department manager to monitor and manage the processes in his department. In this blog post, the following UI will be used as a sample:

In general, the administrative UI for the department manager looks pretty similar to the task inbox UI which was described in one of the previous blog posts. Besides the visual similarity, the implementation of the UIs is also quite similar. Therefore, it is highly recommended to read the blog post about the implementation of the custom task inbox UI before continuing reading, here. In the following sections only the differences between the both implementations will be described.

Implementing a UI for Accessing a Collection of Processes

Implementation of almost every SAPUI5 application for OData services starts with the creation of the service-specific ODataModel instance, and the administrative UI for the BPM Processes OData service is not an exception. The code snippet below shows the definition of the ODataModel in onInit() function of the SAPUI5 controller for the administrative UI:


onInit : function() {
    var processesServicePath = "/bpmodata/processes.svc/";
    var processesODataModel = new sap.ui.model.odata.ODataModel(processesServicePath, true);
    processesODataModel.setDefaultCountMode(sap.ui.model.odata.CountMode.None);
    processesODataModel.setDefaultBindingMode(sap.ui.model.BindingMode.OneWay);
    this.getView().setModel(processesODataModel);
}












After the model is defined and set to the view, it is time to configure UI bindings. In our case, we use a table to show the processes on the UI. Therefore, the bindings should be specified for the table columns:


var processesTable = new sap.ui.table.Table({title : "Credit department processes" });
// define column bindings
processesTable.addColumn(new sap.ui.table.Column({
    label : new sap.ui.commons.Label({text : "Name"}),
    template : new sap.ui.commons.TextView({text : "{Name}"})
}));
processesTable.addColumn(new sap.ui.table.Column({
    label : new sap.ui.commons.Label({text : "Subject"}),
    template : new sap.ui.commons.TextView({text : "{Subject}"})
}));
processesTable.addColumn(new sap.ui.table.Column({
    label : new sap.ui.commons.Label({text : "Status"}),
    template : new sap.ui.commons.TextView({text : "{Status}"})
}));
processesTable.addColumn(new sap.ui.table.Column({
    label : new sap.ui.commons.Label({text : "Started at"}),
    template : new sap.ui.commons.TextView({text : {
        path : "StartDate",
        formatter : function(date) {
            if (date) {
                var dateFormatter = sap.ui.core.format.DateFormat.getDateTimeInstance({style : "medium"});
                return dateFormatter.format(date);
            }
            return "";
        }
    }})
}));
processesTable.addColumn(new sap.ui.table.Column({
    label : new sap.ui.commons.Label({text : "Started by"}),
    template : new sap.ui.commons.TextView({text : "{ProcessInitiatorName}"})
}));












Having bindings for the table columns does not mean that the table will be populated with the data. Moreover, in the controller, we only set the model to the view but we have not bound the table to a property in the model representing the processes.

As it was mentioned before, to get a list of processes from the BPM Processes OData service a request should be sent to the ProcessCollection entity set. It was also mentioned that all the requests to the entity set must contain $filter query option in the request URL. Exactly the same situation was described in the blog post about implementing a custom task inbox UI, where it was necessary to get tasks from the TaskCollection entity set of the BPM Tasks OData service. In that blog post, we used SAPUI5 Filter objects to define value for $filter query option. After that, the created filters were used for the aggregation binding for the UI table with the tasks. In this blog post, we have to do exactly the same, adjusting the filters and the binding path according to the BPM Processes OData service.

First of all, let us define the filters. Of course, the department manager is interested in the processes which his subordinates are working on. Therefore, it is necessary to define the filters to show only running or suspended processes:


var inProgressStatus = new sap.ui.model.Filter("Status", sap.ui.model.FilterOperator.EQ, "IN_PROGRESS");
var suspendedStatus = new sap.ui.model.Filter("Status", sap.ui.model.FilterOperator.EQ, "SUSPENDED");









Having the filters, the next step is to define the aggregation binding for the UI table to ensure that the created filters will be used as a value of $filter query option when the binding is resolved by the ODataModel, i.e. when a request is sent to the OData service.


processesTable.bindRows("/ProcessCollection", null, null, [inProgressStatus, suspendedStatus]);









Such an aggregation binding will be resolved by the underlying ODataModel by sending the following request to the BPM Processes OData service:

…/bpmodata/processes.svc/ProcessCollection?$filter=Status eq 'IN_PROGRESS' or Status eq 'SUSPENDED'

That's it! Now, we have the table with the processes on the UI.

The entire implementation of the SAPUI5 view for the sample application can be found in the attached processAdmin.txt.zip file. In the sample application, static filtering is implemented, meaning that the $filter expressions are ‘hardcoded’ in the SAPUI5 view implementation. Dynamic filtering can also be implemented by adding a number of additional UI controls to specify the filter criteria, selecting a property by which the processes should be filtered (e.g. Status) and the filtering value (e.g. IN_PROGRESS).

Implementing a UI for Process Actions

In the previous section, we populated the table on the UI with the processes provided by the OData service. Now, the department manager can monitor the processes in his department. But he is a manager, meaning that he also wants to manage the processes that he can see. For that purpose, we have Suspend, Resume and Cancel buttons in the table toolbar. Suspend, Resume and Cancel process actions are represented as the corresponding function imports in the BPM Processes OData service, therefore, clicking on each of these buttons should result in sending the corresponding requests to the service. The similar situation has already been described in the blog post about implementing a custom task inbox UI. In that case, it was necessary to call the function import in order to release a task. In our case, the situation is pretty similar except of the names of the function imports and the names of their input parameters.

As usual, a JavaScript function which calls a function import should be implemented in the controller. Because the function imports for process actions are similar to each other, we can handle ‘press’ events for the UI buttons using one generic JavaScript function:


executeProcessAction : function(actionName, processInstanceId) {
    if (!processInstanceId || !actionName) {
        return;
    }
    // define messages to be shown in case of success and error
    var successMessage = this.getSuccessMessage(actionName);
    var errorMessage = actionName + " action failed.";
    //define function import parameters
    var functionParameters = {};
    functionParameters.method = "POST";
    functionParameters.urlParameters = { "InstanceId" : processInstanceId };
    functionParameters.success = function() {
        alert(successMessage);
    };
    functionParameters.error = function() {
        alert(errorMessage);
    };
    var processesODataModel = this.getView().getModel();
    // call the required function import
    processesODataModel.callFunction(actionName, functionParameters);
}











The function takes two parameters: name of the action which should be performed and the identifier of the process instance on which the action should be performed. Technical details of calling OData function imports from SAPUI5 have been described in the blog post about implementation of a custom task inbox UI.

Full implementation of the SAPUI5 controller can be found in the attached processAdmin.txt.zip file.

Conclusion

This blog post has shown the implementation of the administrative UI for BPM processes using the BPM OData service. In this part, technical details of the BPM Processes OData service have been described. It was also shown how to consume the service from SAPUI5 and how to build a sample UI application based on it.

The attached processAdmin.txt.zip file contains the implementation of the administrative UI described in this blog post. The archive contains the implementation of both, SAPUI5 view and controller for the sample application. The attached implementation can be used to ‘play’ with the UI and is not intended to be used for production purposes.