E2E: BOPF-SADL-GW-SAPUI5 – Implicit View Building
This is the third step of the series. You’ll find an overview in the document Introduction.
In this step I’ll show how to create the second entity set; the one for the product list page of the application which is mapped to a BOPF BO. It will be tested in the Gateway client and used to build the page. So let’s start.
The product entity set will be mapped to the business object /BOBF/EPM_PRODUCT. The product BO has a language composition to the product name and a foreign key association to the Business Partner. In this example I am not going to create just another entitiy set but show how you create views implicitly with SADL following 1 to 0..1 associations.
The video illustrates the following sections.
Modifying the Gateway Service
We will modify the service created in the previous step Mapping Entity Sets with the Gateway Service Builder (transaction SEGW). Again we define the data model, then implement the service using SADL and test it.
Definition of the Data Model
As already described in the previous step, we need an entity type and an entity set. Unfortunately there is not yet a metadata importing feature for BOPF. In 7.40 it must be defined manually. The tool offers only the convenience to create the entity set together with the entity type.
The entity type I created for the product consists of some properties which can be provided by the ROOT node of the product BO – like product ID, supplier ID, price and currency. In addition we want to have the product name which is an attribute of a sub node and finally the supplier name – which is an attribute of another BO, the business partner BO.
BOPF uses GUIDs as database key which are not really readable. So for readable identifiers – like the business partner or product ID – you can define alternative keys in BOPF. The PRODUCT_ID is such an alternative key in BO /BOPF/EPM_PRODUCT (more about alternative keys, see here).This is what we will use as key in the entity type definition. Again we should carefully mark the attributes, for example it is not necessary that the URL for the picture is sortable.
The entity set has already been created, but we have to set the attributes:
We want to support the CRUD operations on the entity set, so we need these attributes.
Again we select the function Map to Data Source in the right mouse menu of the Service Implementation Folder -> ProductHeaderSet. Again we have to select the mapping type: Business Entity.
Value help supports us entering the name. This time the Business Entity Source is ‘BOPF Business Object’, the Business Entity is the root node of the BOPF BO Product: /BOBF/EPM_PRODUCT~ROOT.
Finally the tool opens the mapping editor. On the left hand side I get the OData data model of the product entity set. On the right hand side, I find the source model, hence the root node of the BOPF BO.
As in the previous step we map the elements of the root node with drag and drop from right to left. The properties ProductName and SupplierName don’t have a source in the root node but in associated nodes.
Open the composition PRODUCT_NAME and you get the attributes to map.
Note that SADL does not yet support BOPF language compositions in 7.40 out of the box. You have to redefine the filter in the mapping. Add the filter definition in square brackets to the association name. The name of the attribute follows preceded by a dot: <association name>[filter condition].<attribute name of the navigation target node>. In our example this is PRODUCT_NAME[LANGUAGE_CODE == SY-LANGU].NAME.
Last but not least open the association TO_SUPPLIER and map the company name.
That’s it. Save and activate the service. The provider classes are updated with the activation and you can test the new entity set.
Testing the Service
Back to the Gateway client you can test the new entity set. Select the product entity set in the drop down menu button Entity Sets and execute the GET request.
A list of products is returned. Enhance the URI by the product id of one of them following the OData syntax <service root>/<entity set>(‘<key>’) and execute the get request again.
The selected product is returned.
You can use the response to create a request – just press the button Use as request. The body is copied to the request editor on the left hand side. Now you can manipulate it: change the price for example und execute a PUT (update) request.
It is also possible to create a new product using an existing one as template. Just delete the DbKey property which is provided by the BOPF framework and adapt the references using the ID of the new product.
Creation is an operation on the entity set. So just enter the entity set name in the URL, select the POST method and execute the request. A new product has been created.
To learn more about SAP NetWeaver Gateway go here.
It is possible to assign authorizations to BOPF nodes, see the tutorial How to Use Authority Checks in Business Object Processing Framework. If this is the case, the service adaptation engine uses the definition to enrich the select on the database. In principle this is the same as in the previous step.
The service we created provides the expected list and so it is ready to be used in the UI application.
Creating the SAPUI5 page
The video illustrates the creation of the SAPUI5 page.
Creating the page for the products is quite similar to the one for the categories page. It is another master page. But now we have to introduce the navigation from the categories page to the product page using the selected category as filter criteria. Let’s start and go quickly through the creation of the view.
Select New/View in the right mouse menu of the SAPUI5 project to launch the view creation wizard. This is similar to the categories creation, so I do not repeat it here. Just take care to select XML view.
The wizard creates two new files: the one for the products view and the one for the products controller.
The Product View Definition
The view is again a list but this time we choose to define the data binding in the controller, hence no path to the ProductHeaderSet here. Beside this as we do not want to relaunch the application at each time we want to select a different category – even not for test purposes – we introduced a toolbar with a back button and a handler function.
The index.html File
Before we attack the controller, we want to integrate the page into the application and to navigate to it. So let’s have a look at the index.html file.
We just have to create a variable for the page and add the page to the application as master page.
The Categories Controller
In the previous step we have already registered a callback function (listItemTriggered) in the categories view when a category has been selected. We have to implement this callback function in the categories controller to navigate to the products page.
Functions registered on an event have an input object containing the context of the event. In the case of a selection event the context contains a reference to the selected item for example.
So let’s see the listItemTriggered function.
We need a reference to the application which we get from the SAPUI5 framework function sap.ui.getCore. The splitter application which we are using has a navigation method allowing switching the master pages. This switch triggers an event onBeforeShow. Later on we have to register to and handle this event in the product controller.
For now we have to care for the selected category. As I already mentioned it is part of the context of the navigation event. The input parameter of the callback function for the select event has as parameter the source of the event. The later one has an attribute bindingContext containing the selected category amongst others. We put the complete binding context into the context of the navigation event which will be used in the products controller to set the correct filter for the list.
The Product Controller
In the product controller we bind the data model to the ProductHeaderSet. In this section we clone the view definition to use it later on as template. Then we bind the list items to the attribute ProductId of the ProductHeaderSet. For the categories page we defined the binding in the view. This is an example for defining it in the controller – if you need more dynamics.
Now to the registration and implementation of the callback function of the navigation event.
For pure ABAP developers there are some unfamiliar concepts in the code: anonymous functions, closures and this and that. Let’s go quickly through the code. In the onInit callback function we register for the event triggered by the navigation. As callback we do not use a named function, but declare it inline. This is quite useful because very often the callback functions are not reused by different events. Having said this, this may be confusing for developers who are used to read functions in a procedural way. But anyway once you are familiar with it, it is really comfortable.
With this inline definition of functions it comes the closure concept. If it would be possible to define local methods in ABAP methods, then closure would mean that we can use the local variables of the enclosing method in the inline defined method – even if it is a callback of an event and executed at a completely different point in time.
And finally a word to this and that: this points to he context of a function. The context of the inline defined function is a different one than the context of the enclosing function – not very surprising. If in the inner function you need access to the context of the enclosing function, you have to copy it to a variable. Very often this variable is called that.
Now together with the closure concept you have access to the local variables of the enclosing function. You are in a nice position: you can access the context of the inner function with this and the context of the enclosing one with that.
For me all this has been quite hard stuff to learn. I hope that I’ve been somehow understandable – and as comparisons are always somehow false and true this is not all about closures and contexts. For more information start with Wikipedia.
But now to the code itself.
We register an anonymous function for the onBeforeShow event. The event parameter contains a reference to the selected category in the context attribute. We define a filter using the selected category. Then we update the list binding attaching the filter. That’s it.
That ‘this is it’ has been quite a high hurdle for me in the beginning. I desperately searched for a method to bind the filter somehow to the http request. It was hard to learn that binding both URI and filter to the view early enough before the view triggers the request is sufficient.
The rest is straight forward: the splitter application offers a method to navigate back which is used in the callback function of the back button.
If you want to test the new page, you have to submit the code in the Team menu. Then you can run the index.html file on the ABAP server.
Now selecting a category navigates to the product page showing all products of that category.
So far for the product page. We defined the ProductEntitySet, mapped it to three BOPF nodes using SADL and used it in our application to implement the product page.
Now we are going to create the detail page where we will use navigation properties.
Need for some background, visit the spaces BOPF Application Framework, SAP Gateway or SAPUI5 Developer Center.
I was just wondering why transient attributes cannot be mapped from the business entity properties to the GW properties.
I just published BOPF-SADL Mapping – Demystifying Limitations. I hope that this article answers your question.