Many questions and descriptions here in SCN focus on the usage of the BRF+ via the workbench as interface for the creation and maintenance of objects of the BRF+. But there is also another way to get these things done namely the BRF+ API. This blog shall introduce you into some basic usage scenarios of the API. A comprehensive description of the API can be found in the book BRFplus – The Book of Carsten Ziegler and Thomas Albrecht.
The first question that might arise up to now is: Why should I use an API if I have the comfort of the BRF+ workbench with its quite usable Webdynpro UI?
The answer is: There are scenarios where the BRF+ workbench cannot be used for the maintenance. One example is the maintenance of the rules on the productive environment when DSM is not in place, In case you are using BRF+ applications of storage type S or C your system settings will usually prevent their maintenance on the productive system. There is a workaround by using an application exit but then you really have to take care on the synchronization process between the development and the productive system as those applications are still part of the regular transport process. This can get quite tricky and is not the best way to go.
Now you might say that a master data application might solve the issue but that one is not intended to be transported except for the XML export and import functionality which might not be the preferred way of your IT operations team. So this might be right time to switch to a generative approach using the BRF+ API. This approach might also be of favor when you want to (deeply) integrate an artefact of the BRF+ (e. g. a decision table) into an existing application so that the user is not even aware of using the BRF+ but on the other hand still being able to use all the nice features of the artefact.
Before the story gets a little bit too theoretical I want to introduce a business scenario where this approach can be used.
The Business Scenario
As my background is the field of insurance so is my scenario: Let us assume we have a SAP module (like SAP Policy Management) that allows you to manage master policies more specific the fleet master policies. Within these master policies the insurer and the insured company agree on the insurance of the company cars. Usually the insured company pays a certain premium per car and the basis for the premium calculation is written down in the master policy. This basis depends on certain properties of the cars to be insured. Let us use the following very simplified example for such a table:
|Weight of car in tons||Performance of the car in kW||Premium amount in EUR|
|<= 1.5||<= 80||250|
|<= 2.5||<= 90||350|
|<= 3.5||<= 110||400|
Each insured car finally gets one single policy issued with the premium corresponding to the properties of car and the agreement in the fleet master policy e. g. for a car with less than 1.5 tons and a performance of 80 kw you pay a premium of 250 €. Even this simplified description leads us to the point that a decision table might be a very good choice to tackle the scenario. But here come the problems:
- The premium conditions are entered on the productive environment after the negotiation between the insurer and the insured company has been concluded.
- No Decision Service Management is available.
- The user does not want to switch from the master policy management application to the BRF+ application in order to enter the data of the master policy. He wants to have one single transaction.
So a possible the solution for that scenario consists of two tasks:
- Enhance the UI of the policy management application in order to allow the user to display and edit the data in the decision table. For this topic I want to refer to the corresponding document available here in SCN: http://scn.sap.com/docs/DOC-4578
- Implement a functionality in the system that creates a decision table (including its “surroundings” like application, function etc.) in background for each master policy and make it available for the UI. This task also contains the creation of the functionality to maintain the data in the decision table (plus the nice features like check for overlaps). This is the part that the blog focuses on in the subsequent sections.
Before starting with the technical details just a short disclaimer: the usage of the API for the maintenance of the BRF+ objects is some quite advanced topic so if you decide to use it you should know what you are doing (which is in most cases a quite good approach 🙂 ). Especially when you are integrating the functionality into an existing application you have to be careful e. g. about the commit handling, the transaction handling etc. of the application and the BRF+ API and the interplay between them. Also intensive testing of the integrated components plays an important role.
In addition the coding snippets shown below do not have a sophisticated error handling so for a real usage some adoptions have to be made.
But now enough for that part and let us start with the real stuff … the coding with the BRF+ API!
In order to make the decision table available for the enhanced UI of the master policy management we will implement a handler class ZCL_BRFPLUSAPI_FLEET for the single operations that have to be triggered via the BRF+ API. This means that as a rough guide we have the following methods for the:
- creation of the BRF+ application with a function (in functional mode) and a decision table assigned to the function
- read the decision table data
- insert and update data in the decision table
- delete the complete application
- service functionalities like check for gaps or overlaps in the decision table
- processing of the decision table
As the structure for the decision table is constant there is no need to create the single data objects of the columns whenever a new decision table is created so as a prerequisite we have an additional BRF+ application of storage type S that holds the corresponding data objects for the weight, the performance and the premium amount as reusable data objects.
Creating the decision table
In order to create the decision table we first have to create a BRF+ application. We will use an application of type master data for the example as this is the obvious storage. For the task we design one method that creates the application including its sub-objects and returns a reference to it:
Within that method we first fetch a reference to the BRF+ factory which is the central point when creating BRF+ objects:
As already shown we then delegate to a method that creates the application with its basic features and returns the reference to it. The method contains the following logic (the numbers refer to the highlighted sections in the following screenshot):
- We call GET_APPLICATION on the BRF+ factory and get back a reference to an empty application object. Next we enqueue the application object itself by using the corresponding method of the interface IF_FDT_TRANSACTION.
- After that we set the basic parameters like application component and so on using the methods that are available on the application object. For every field that you can see on the BRF+ workbench one method is available in the application API.
- After that we call a specific API method that creates the master data application based on the properties we set into the object.
There are also methods for the other types of applications like customizing applications.
- As we have now finished the application specific actions we activate the application via the method IF_FDT_TRANSACTION~ACTIVATE. Depending on the success or failure we save and dequeue the application or just dequeue it. In case of a success the application is now available in the BRF+ workbench.
Some remarks on this first task:
- The API also allows a deep activation and saving of objects (meaning that you trigger the saving e. g. on application level and all subsequent objects are saved too). This alternative will be shown in the following screenshots.
- The naming of the application was determined using the class CL_FDT_SERVICES. This class offers methods that create GUIDs for your names either with or without a specific namespace and was called in the method GET_UNIQUE_NAME in the screenshot above.
- Most of the BRF+ API methods throw the exception CX_FDT_INPUT. You should always catch and handle it
Now let us go back to the main method for the creation operation. Next we want to create the decision table in order to have it in place when we create the function and assign it as top-level expression. But before we can do so we need to get access to the data objects used in the decision table i. e. their references that we have stored in the S-application for reuse:
Within this method we once again use the BRF+ factory to fetch the references to these objects:
If you know the IDs of the data elements (that I stored as constants in an interface) the reference is just one call of GET_DATA_OBJECT away. Having these references we have access to all the attributes of the data objects e. g. their type.
Having the BRF+ factory the application object and the references to the data objects that build the columns of the decision table we can now go on and create the decision table via another private method:
The creation of a decision table is roughly speaking the same as the creation of an application with the following steps (the numbers refer to the highlighted sections in the following screenshot):
- Creation a decision table object via the factory, enqueuing it and setting the basic properties. Each attribute that can be set is represented by a method of the decision table API.
- Filling of the decision table columns and setting their properties (e. g. is it a condition or a result column)
- Setting the corresponding objects to the decision table object
- In addition we also stored the object IDs of the context objects that will be used in the next task when creating the function
As you can see we did not yet activate and save the object.
Now we have the references to the application object, the (empty) decision table object and the data objects. We can therefore finish the creation operation by creating a function and activating the function andits sub-objects:
This method encapsulates the following steps (the numbers refer to the highlighted sections in the following screenshot):
- First, as usual, we create a reference to a function object via the BRF+ factory. After enqueuing it we assign it to an application and use the methods of the object to set the basic attributes of a function object like the name and versioning. Last but not least we set the mode of the function to “functional mode”. As with every BRF+ API the object reference has methods for each attribute that can be set.
- Next we assign the context and result data objects as well as the expression to the function. Remember that we fetched the object IDs of the context parameters when we constructed the condition columns of our decision table
- As third step we activate the function. This time we set the optional parameter IV_DEEP to ABAP_TRUE which leads to an activation of the function and its inactive sub-objects (in our case the decision table)
- Last but not least we save and dequeue the function in case of a successful activation. Once again we use the IV_DEEP parameter of the methods to propagate the action.
That’s it – executing the create method CREATE_MASTERDATA_APPLICATION of the handler class ZCL_BRFPLUSAPI_FLEET will now create an application with function and empty decision table from scratch. The method returns the reference to the application object so we can for example store the GUID of the application (stored in the public attribute MV_ID of the reference to the application) in our master policy in order to be able to retrieve the application and its sub-objects at a later point in time.
The key take-aways of this first section are:
- Every BRF+ object has an API that can be used to create and maintain it.
- In order to get an object reference to one of the APIs we need the BRF+ factory class CL_FDT_FACTORY.
- Some global BRF+ service functionalities are implemented in the class CL_FDT_SERVICES
Setting and Getting the Data
After the successful creation of the decision table we want to offer methods in our handler class in order to read the entries of the decision table as well as to set data into the decision table.
As a starting point let us assume that that we have the GUID of the application and have to retrieve the reference to decision table via that GUID. So we have to implement a method that fetches the references to the objects that belong to the application specified via the GUID:
The content of the method consists of two major parts namely the fetching of the function object and then the fetching of the decision table object.
For the function object the following steps are performed (the numbers refer to the highlighted sections in the following screenshot):
- First we get a reference to the query object of the BRF+ specific for functions. As for the BRF+ API a query object for each artefact exists
- Then we construct the selection parameters in our case the parameters of the application identified by its ID and specify that we are looking for a master data object
- After that we fire the query and get the ID of the function as a result.
- As a last step we use another important method of the BRF+ factory namely the method GET_INSTANCE_GENERIC that returns us a reference to the function object that we have to cast to the function-specific interface.
As we have a 1:1 relationship between the function and the decision table we can directly fetch the reference to the decision table by using the method GET_EXPRESSION of the function API that returns the ID of the decision table object:
After casting to the right interface we have the reference to the decision table that we can use for getting and setting the data. So we enhance the handler class ZCL_BRFPLUSAPI_FLEET with two additional methods for the getting and setting of data from/into the decision table object:
The implementation of the GET method is straightforward as we call the corresponding GET method of the decision table API:
The SET method is nearly as straightforward as the GET method so we call the SET method of the API but as we make a change to the table we have to enqueue/dequeue as well as activate and save the object in analogy to the case of its initial creation:
As you can see the setting and getting of the data itself is not difficult but it is certainly also of interest what the table data has to look like in order to be able to call these two methods.
The following coding snippet gives you some insight how this can be achieved:
First we create a reference to our handler class and fetch the reference to the decision table object (the application ID is a parameter of the report).
Second we fetch the type names of the single columns using the BRF+ factory as shown in the screenshots below
Then we fill the table parameters with the values for the condition columns where we specify the table column and row the operators for the comparison and the concrete value:
After that we fill the result column which is more straightforward due to the direct assignment of the result value without options for comparisons:
This way we have to fill the table line by line and finally set it into our decision table using the handler class:
The key take-aways of this second section are:
- Having the ID of an BRF+ object enables you to search for other BRF+ objects using the query functionality (IF_FDT_QUERY) available via the BRF+ factory.
- You can either instantiate a BRF+ object via the corresponding method for the object on the factory or you use the static generic method GET_INSTANCE_GENERIC of the factory.
- Every API has methods to set and get the data and properties stored in the object. The concrete parameters depend on the specific object type.
Summary and Outlook
Within this blog a scenario was presented which is an example for the usage of the BRF+ API to create and maintain BRF+ objects. We created an application, a function and an empty decision table in storage type “master data”. Then we determined the ways how to fetch the reference to the created objects via the ID of the BRF+ application and how to set/get data to/from the decision table object.
As there are several more functionalities that you can address via the BRF+ API that might be of interest and are listed in the function list of the handler above a further blog is available that describes e. g. the API to check for gaps and overlaps in the decision table: Handling of Applications with the BRF+ API (Part 2)