This blog post, as part 5 of BPM OData blog series, refers to the OData Service in SAP NetWeaver 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 11 and higher. Before reading this blog post, it is recommended to read the previous parts of the BPM OData blog series.

Overview

In all the previous blog posts about the BPM OData service, we were considering a business scenario that is related to processing of customer data. In all the cases, the customer data was already available and the purpose of the blog posts was to describe how to implement a UI to work on the provided data. Some of you were probably wondering how a customer provides his data and whether it is possible to implement a SAPUI5 UI for that purpose. And what about the OData? Are there any OData services in SAP BPM that can be used for that purpose? The answer to all these questions is “Yes”. And this blog post answers the aforementioned questions in more detail.

The purpose of this blog post is to describe how to implement a UI to provide customer data. In our business scenario, such a UI can be considered as the entry point for a customer who wants to provide his data to the credit institution. Obviously, without the provided data neither the customer service employee nor the financial officer will be able to start working on the customer data to verify it and provide a credit limit after that. It means that the submission of the data by the customer can be considered as the event, which starts the entire process. In such a case, the customer data itself can be considered as the start data for such a process.

Process Model

If we represent the business scenario as a process in SAP BPM, submission of the customer data can be considered as the process start event and the customer data itself can be considered as the process start data. In this blog post, as well as in all the previous blog posts, the following process model is used for the business scenario:

/wp-content/uploads/2014/09/process_model_546454.pngIn order to start a process in SAP BPM, a process start event should be triggered. As it was mentioned previously, in our business scenario, the process start event represents the submission of the data by the customer. To allow the customer to submit his data it is necessary to define data for the process start event. For that purpose, a custom event trigger has been defined having service operation with the following input data structure:


<complexType name="Customer">
    <sequence>
        <element name="firstName" type="string"></element>
        <element name="lastName" type="string"></element>
        <element name="address" type="tns:Address"></element>
        <element name="currency" type="string" default="EUR"></element>
        <element name="phone-numbers" type="string" maxOccurs="unbounded"
            minOccurs="0"></element>
        <element name="vcards" type="tns:Vcard" maxOccurs="unbounded"
            minOccurs="0"></element>
    </sequence>
</complexType>
<complexType name="Address">
    <sequence>
        <element name="street" type="string"></element>
        <element name="city" type="string"></element>
        <element name="zip" type="integer"></element>
        <element name="country" type="string"></element>
    </sequence>
</complexType>
<complexType name="Vcard">
    <sequence>
        <element name="attr1" type="string"></element>
        <element name="attr2" type="string"></element>
        <element name="attr3" type="string"></element>
    </sequence>
</complexType>

































More information about how to model process start events can be found in the official documentation.

If we compare the defined process start data with the input data of Verify Customer Data task, we can see that the structure of the data is the same. As a result, once the process is started, its start data is mapped to the input data of Verify Customer Data task to enable customer service employee to verify the provided data.

Having all the required changes in the process model, it is time to start the process.

BPM Process Start OData Service

Starting from SAP NetWeaver 7.3 EHP 1 SP 11 the BPM OData service provides functionality to start a BPM process. For that purpose, BPM Process Start OData service should be used. This service along with all the other BPM OData services is available under ‘bpmodata’ root URL and has the name ‘startprocess.svc’. The BPM Process Start OData service provides the following operations:

  • Access to Process Start Data
  • Start a Process

Besides the supported operations, the BPM Process Start OData service as well as all the OData services should provide the EDM service metadata to describe the service entity model. The metadata of the service contains two standard entity types and a number of entity types to represent a process start data. The standard entity types are named StartData and ProcessStartEvent. The purpose of the StartData entity type is to represent information about the process, which can be started using the OData service. ProcessStartEvent entity type is referenced by StartData entity type and is used as a wrapper around the entity type representing the process start data itself. The entity type for the process start data itself is an EDM representation of the XSD complex type, which is defined as the input for the service operation to trigger the process start event. In our case, the entity type for the process start data corresponds to the Customer XSD complex type and has the following structure:


<EntityType Name="Customer">
    <Key>
        <PropertyRef Name="EDM_Key" />
    </Key>
    <Property Name="EDM_Key" Type="Edm.String" Nullable="false" />
    <Property Name="firstName" Type="Edm.String" Nullable="true" />
    <Property Name="lastName" Type="Edm.String" Nullable="true" />
    <Property Name="currency" Type="Edm.String" Nullable="true"    DefaultValue="EUR" />
    <NavigationProperty Name="address"
        Relationship="BPMProcessStart.Customer_Address" FromRole="Customer"
        ToRole="Address" />
    <NavigationProperty Name="vcards"
        Relationship="BPMProcessStart.Customer_Vcard" FromRole="Customer"
        ToRole="Vcard" />
    <NavigationProperty Name="phone-numbers"
        Relationship="BPMProcessStart.Customer_phone-numbers" FromRole="Customer"
        ToRole="phone-numbers" />
</EntityType>
<EntityType Name="Address">
    <Property Name="street" Type="Edm.String" Nullable="true" />
    <Property Name="city" Type="Edm.String" Nullable="true" />
    <Property Name="zip" Type="Edm.Decimal" Nullable="true" />
    <Property Name="country" Type="Edm.String" Nullable="true" />
</EntityType>
<EntityType Name="phone-numbers">
    <Key>
        <PropertyRef Name="EDM_Key" />
    </Key>
    <Property Name="EDM_Key" Type="Edm.String" Nullable="false" />
    <Property Name="phone-numbers" Type="Edm.String" Nullable="true" />
</EntityType>
<EntityType Name="Vcard">
    <Key>
        <PropertyRef Name="EDM_Key" />
    </Key>
    <Property Name="EDM_Key" Type="Edm.String" Nullable="false" />
    <Property Name="attr1" Type="Edm.String" Nullable="true" />
    <Property Name="attr2" Type="Edm.String" Nullable="true" />
    <Property Name="attr3" Type="Edm.String" Nullable="true" />
</EntityType>
































More information about generation of EDM metadata from XSD can be found in the official documentation.

The process start data is defined at the process design time and is different for different processes. It means that in order to generate the metadata containing EDM representation of a particular process start data the process identifier should be provided to the BPM Process Start OData service. Every process in SAP BPM can be uniquely identified by the name of its vendor, name of the development component where the process is located and the process name. It means that all these identifiers should be provided to the BPM OData service to generate EDM metadata for the process start data. In general, every URL for the BPM Process Start OData service should contain all the process identifiers to identify the process which start data should be retrieved or the one, which should be started. As a result, all the URLs of the service can be represented using the following pattern:

http://<host>:<port>/bpmodata/startprocess.svc/<vendor>/<dcName>/<process_name>/<OData_resource_path_and_query_options>

In the pattern above, <vendor>, <dcName> and <process_name> represent process vendor name, name of the process development component and the process name respectively.

Accessing Process Start Data

Before starting a process its start data should be retrieved to get information about its structure. After that, the retrieved data should be modified and sent to the OData service in order to start a process.

The table below shows the URL used to access process start data along with the service response:

HTTP Method GET
URL …/bpmodata/startprocess.svc/test.sap.com/tc~bpem~customer~process/CreateCustomerProcess/StartData?$expand=ProcessStartEvent,ProcessStartEvent/Customer,ProcessStartEvent/Customer/address,ProcessStartEvent/Customer/phone-numbers,ProcessStartEvent/Customer/vcards&$format=json

Response Body

(simplified)


{
  "d": {
    "results": [
      {
        "vendor": "test.sap.com",
        "dcName": "tc~bpem~customer~process",
        "processTechnicalName": "CreateCustomerProcess",
        "processInstanceId": null,
        "ProcessStartEvent": {
          "Customer": {
            "firstName": null,
            "lastName": null,
            "currency": null,
            "address": null,
            "phone-numbers": {
              "results": []
            },
            "vcards": {
              "results": []
            }
          }
        }
      }
    ]
  }
}































The BPM Process Start OData service supports requests only to the StartData entity set. It means that in order to get the structure of the process start data itself, all the corresponding navigation properties should be expanded. For that purpose, the URL in the table contains the $expand OData query option with the corresponding values.

The list of the supported URLs for the StartData entity set can be found in the official documentation. More information about the OData query options can be found on the odata.org web site.

Starting a Process

In the previous section, it has been shown how to get the process start data using the BPM Process Start OData service. The process start data is represented as Customer entity in the service response. Since the process has not been started, its start data is empty, which results in having ‘null’ values for all of its properties. In order to start a process the start data that has been returned by the service should be modified by setting values for all of its properties. After that, the modified start data should be sent to the service. In our case, modification of the start data requires setting values for the properties of the Customer entity. For primitive properties like firstName it is quite simple because the property value is a string representing the customer name whereas for complex properties like address or vcards it can be difficult because the property value is not a primitive one and there is no information about the structure of the value in the service response.

In order to get information about the structure of address and vcards properties the service metadata can be used. Because both of the properties are complex ones they are represented as navigation properties in the Customer entity type.


<NavigationProperty Name="address"
        Relationship="BPMProcessStart.Customer_Address" FromRole="Customer"
        ToRole="Address" />
    <NavigationProperty Name="vcards"
        Relationship="BPMProcessStart.Customer_Vcard" FromRole="Customer"
        ToRole="Vcard" />































Looking at the definition of a navigation property it is possible to get information to which entity type it points. Every navigation property has a ToRole attribute which contains the name of the entity type to which the property points. In our case, the address property points to the Address entity type. Based on the entity type structure


<EntityType Name="Address">
    <Property Name="street" Type="Edm.String" Nullable="true" />
    <Property Name="city" Type="Edm.String" Nullable="true" />
    <Property Name="zip" Type="Edm.Decimal" Nullable="true" />
    <Property Name="country" Type="Edm.String" Nullable="true" />
</EntityType>































the following entity can be created:


{
    "street": "Main str.",
    "city": "Walldorf",
    "zip": "69190",
    "country": "Germany"
}































Such an entity should be specified as the value of the address property of Customer entity. The entity for the vcards property can be created in the same way based on the Vcard entity type. The only difference is that vcards is a multi-valued property and the created entity should be specified in scope of a results[] array.

In general, the OData service metadata should always be used when it comes to specify a value for a property of the OData entity. Based on the metadata you can find the type of the property and specify the value in the required format. The metadata also allows determining the structure of the property value when it is a navigation property. More information about how to specify values for properties in OData can be found on the odata.org web site.

Having the JSON object for the Customer entity it is time to send it to the BPM Process Start OData service in order to start the process. For that purpose, a POST request should be sent to the StartData entity set.

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

HTTP Method POST
URL …/bpmodata/startprocess.svc/StartData
Request Headers Authorization Basic dXNlcm5hbWU6cGFzc3dvcmQ=
X-CSRF-Token 781057a9-b96a-468c-b393-981f98292335
Content-Type application/json
Accept application/json
Request Body

{
    "ProcessStartEvent": {
        "Customer": {
            "firstName": "John",
            "lastName": "Doe",
            "currency": "EUR",
            "address": {
                "street": "Main str.",
                "city": "Walldorf",
                "zip": "69190",
                "country": "Germany"
            },
            "phone-numbers": {
                "results": [
                    {
                        "phone-numbers": "111-111-111"
                    },
                    {
                        "phone-numbers": "222-222-222"
                    },
                    {
                        "phone-numbers": "333-333-333"
                    }
                ]
            },
            "vcards": {
                "results": [
                    {
                        "attr1": "John Doe",
                        "attr2": "john.doe_at_provider.com",
                        "attr3": "john.doe"
                    },
                    {
                        "attr1": "J.D.",
                        "attr2": "jd_at_provider.com",
                        "attr3": "jd"
                    }
                ]
            }
        }
    }
}




























Response Body


{
    "d": {
        "vendor": "test.sap.com",
        "dcName": "tc~bpem~customer~process",
        "processTechnicalName": "CreateCustomerProcess",
        "processInstanceId": "7367b9b33e5d11e485ae00000034b6ba",
        "ProcessStartEvent": {
            "Customer": {
                "firstName": "John",
                "lastName": "Doe",
                "currency": "EUR",
                "address": {
                    "street": "Main str.",
                    "city": "Walldorf",
                    "zip": "69190",
                    "country": "Germany"
                },
                "phone-numbers": {
                    "results": [
                        {
                            "phone-numbers": "111-111-111"
                        },
                        {
                            "phone-numbers": "222-222-222"
                        },
                        {
                            "phone-numbers": "333-333-333"
                        }
                    ]
                },
                "vcards": {
                    "results": [
                        {
                            "attr1": "John Doe",
                            "attr2": "john.doe_at_provider.com",
                            "attr3": "john.doe"
                        },
                        {
                            "attr1": "J.D.",
                            "attr2": "jd_at_provider.com",
                            "attr3": "jd"
                        }
                    ]
                }
            }
        }
    }
}




























The service response for the sent request contains the data with which the process has been started. The service response also contains a value for the processInstanceId property of the StartData entity. The property value contains the identifier of the started process instance.

Implementing the UI

Having all the necessary information about how to consume the BPM Process Start OData service it is time to implement a UI to start a process. As it was mentioned in the beginning of the blog post, a UI to start a process can be considered as the entry point for a customer of a credit institution. Such a UI can be represented as a form containing a number of fields where customer can enter his data. Once the form is filled, the ‘Submit’ button should be clicked to submit the data, i.e. to start the process.

Customer_Data_UI.png

Implementing a UI for Accessing Process Start Data

One of the main steps when implementing a UI for an OData service is to define a model, which is represented as sap.ui.model.odata.ODataModel instance in SAPUI5. In the previous blog posts, the ODataModel was used to retrieve the existing data (e.g. task input data) from the OData service and to resolve UI bindings with this data. In that case, the entity, returned by the OData service, had values for top-level properties (e.g. firstName) as well as for the nested properties (e.g. address). As a result, binding expressions like {Customer/address/city} were possible. In case of the BPM Process Start OData service, the situation is different. As it was shown previously, a process start data that is returned by the service is empty because it corresponds to a non-started process. In this case, UI binding for top-level properties like firstName will be resolved correctly whereas binding expression {Customer/address/city} will not be resolved because address property is empty and the internal city property is not available.

As you remember, we had a similar situation in the Starting a Process section when it was necessary to create a POST request body to start a process. In that case, the service metadata was used to determine the structure of the address navigation property. After that, the corresponding entity was created manually and set for the property in the request body. In general, we need to do almost the same before defining a model for the view of the process start UI.

Obviously, looking into the metadata and hard-coding structure of the navigation properties in the model is not a task an SAPUI5 developer dreams of. To make developer’s life easier there is the utility.txt.zip file attached to this blog post. The file provides the createEntityForEntityType() function which creates an OData JSON entity for the required entity type. In short, the function automates the manual process of the entity creation that was shown in the Starting a Process section. The function takes two parameters: OData service metadata and name of the entity type for which an entity should be created. The OData service metadata can be retrieved by calling the getServiceMetadata() function of the ODataModel. The sample usage of the functionality is shown below:


var startProcessSvcURL =
"/bpmodata/startprocess.svc/test.sap.com/tc~bpem~customer~process/CreateCustomerProcess";
this.processStartODataModel = new sap.ui.model.odata.ODataModel(startProcessSvcURL, true);
this.processStartODataModel.setCountSupported(false);
this.edmMetadata = this.processStartODataModel.getServiceMetadata();
var customerEntity = createEntityForEntityType(this.edmMetadata, "Customer");























The entity that is created for the entity type also contains entities for all the navigation properties of the entity type. The figure below shows the entity that is created for the Customer entity type:


{
    "firstName": null,
    "lastName": null,
    "currency": null,
    "address": {
        "street": null,
        "city": null,
        "zip": null,
        "country": null
    },
    "phone-numbers": {
        "results": []
    },
    "vcards": {
        "results": []
    }
}























Now it is time to set this entity to the model to be able to have binding expressions for properties of the address property and for multi-values properties like phone-numbers and vcards as well.

Because every instance of the ODataModel is based on an OData service, changes in the model are queued internally as the corresponding requests to the OData service and should be submitted at the end. In our case, we only want to use hierarchical binding expressions for the nested properties without sending any requests to the OData service. Therefore, sap.ui.model.json.JSONModel fits better for our purposes:


var modelData = {};
modelData["Customer"] = customerEntity;
var jsonModel = new sap.ui.model.json.JSONModel(modelData);
var view = this.getView();
view.setModel(jsonModel);























The entire implementation of the onInit() function of the SAPUI5 controller containing all the aforementioned changes can be found in the attached startProcess.txt.zip file.

Working with Collections in Process Start Data

As it is shown on the screenshot of the sample UI, customer’s vCards are represented as tables. If we look at the customer entity, which has been created for the Customer entity type, we can see that the vcards property has an empty results[] array as its value. The results[] array is required by the OData protocol to represent a collection of items and it is empty because the collections of vCards is empty by default. Since a vCard is represented as an element of the results[] array, the UI table should be bound to the vcards property in the following way:


vcardsTable.bindRows("vcards/results");























Columns of each table row should be mapped to the corresponding properties of a vCard:


var attr1Column = new sap.ui.table.Column( {
    label : new sap.ui.commons.Label( {    text : "attr1" } ),
    template : new sap.ui.commons.TextField( { value : "{attr1}" } )
});
var attr2Column = new sap.ui.table.Column( {
    label : new sap.ui.commons.Label( {    text : "attr2" } ),
    template : new sap.ui.commons.TextField( { value : "{attr2}" } )
});
var attr3Column = new sap.ui.table.Column( {
    label : new sap.ui.commons.Label( {    text : "attr3" } ),
    template : new sap.ui.commons.TextField( { value : "{attr3}" } )
});
vcardsTable.addColumn(attr1Column);
vcardsTable.addColumn(attr2Column);
vcardsTable.addColumn(attr3Column);























Names of the vCard properties can be found in the service metadata.

By default, the table of vCards is empty but when the ‘Add’ button is clicked, a new row should be added to the table. Since the table is bound to the results[] array, it also means that a new entry should be added to the array. The added entry should represent an empty entity for the Vcards entity type. To create such an entity the already mentioned createEntityForEntityType() function should be called passing the name of the entity type for vCards. The code snippet below shows the implementation of a function that is called when the ‘Add’ button is clicked for the table of vCards.


addVcard : function() {
    // create vCard entity
    var vCardEntity = createEntityForEntityType(this.edmMetadata, "Vcard");
    var vCardItem = jQuery.extend(true, {}, vCardEntity);
    // add the created vCard to the table
    var model = this.getView().getModel();
    var vcards = model.getProperty("/Customer/vcards/results");
    vcards.push(vCardItem);
    model.refresh();
}























In the end of the function, the refresh() method is called for the model. The refresh of the model also includes a refresh of the bound UI controls. In our case, the table with vCards will be refreshed and a new row will be added to it.

The entire implementation of callbacks for ‘Add’ and ‘Remove’ buttons of the UI tables can be found in the attached startProcess.txt.zip file.

Implementing a UI for Starting a Process

On the sample UI, a customer clicks the ‘Submit’ button to submit his data, which automatically starts the process using the customer data as the process start data. The code snippet below shows a function that is called when the ‘Submit’ button is clicked.


startProcess : function() {
    var startData = {};
    startData.ProcessStartEvent = {};
    var jsonModel = this.getView().getModel();
    startData.ProcessStartEvent.Customer = jsonModel.getProperty("/Customer");
    this.processStartODataModel.create("/StartData", startData, null,
            function() {
                alert("Your data has been successfully submitted.");
            },
            function(oEvent) {
                alert("An error occurred while submitting the data.");
            });
}























The implementation of the function is quite straightforward. Customer data is retrieved from the JSON model and wrapped into a process start event, which is required by the BPM Process Start OData service. After that, the created JSON object is used as request body for the POST request that is sent for StartData entity set. To send the request the ODataModel that has been created for the BPM Process Start OData service is used.

Conclusion

This part has shown the implementation of a UI to start a process. The technical details of the BPM Process Start OData service have been described and it was shown how to consume the service from an SAPUI5 application. A UI to start a process can be used as the entry point in the application having a BPM process in the back end.

The attached startProcess.txt.zip and utility.txt.zip files contain the implementation of the Process Start UI described in this blog post. These files can be used to ‘play’ with the UI and are not intended to be used for production purposes.

To report this post you need to login first.

8 Comments

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

  1. Trimurthulu Bandaru

    Thanks vitaly. simple and ready to implement guide.

    when I tried to invoke the BPM start process OData service, getting http 404 error.

    server version is : 7.4 SP04

    can you please tell me whether this version supports or not.

    (0) 
    1. Vitaly Yarmolik Post author

      Hi Trimurthulu,


      The BPM Process Start OData service is available starting from SAP NetWeaver 7.4 SP 06. Which means that in order to use the service your SAP NetWeaver should be updated to the corresponding version.


      Best Regards,

      Vitaly

      (0) 
  2. N D Trimurthulu Bandaru

    Hi Vitaly,

    I tried the above mentioned steps for process start and able to see process start data.when I try to start process with POST method, getting OData exception as

    EXCEPTION]

    org.apache.olingo.odata2.api.exception.ODataApplicationException: The URL is too short

    Request URI: /bpmodata/startprocess.svc/StartData

    Can you please suggest what is going wrong here.

    Thanks

    -Trim

    (0) 
  3. Karthik S

    Hi Vitaly,

    Nice Blog. I have few queries in starting the process. When customer data is submitted in UI,the request will  post the details. But how can I use this service to initiate my Start Process in BPM. How can  I map the service as event trigger in BPM start event? Can you explain this elaborately?

     

    Correct me if I am wrong.I am a beginner in SAP BPM.

     

     

    Regards,

    Karthik S

    (0) 

Leave a Reply