Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
ceedee666
Active Contributor

Introduction

In part 1 of this tutorial (CRM Rapid Applications - An Advanced Tutorial (Part 1)) I described how to implement a basic application using the CRM Rapid Application framework (Rapid Applications - SAP Library). In this part of the tutorial I will show how the BRFplus (SAP Business Rules Management) can be used to perform data validations in CRM Rapid Applications.

Designing the BRFplus Application

As described in the requirements in the first part of this tutorial the attributes in the example application should be checked according to the following rules:

  1. "Attribute 1" is mandatory, "Attribute 2" is optional.
  2. Allowed values for "Attribute 1" are "A", "B" and "C",
  3. Depending on the value of "Attribute 1" the following values are allowed for "Attribute 2"
    Attribute 1Attribute 2
    A1 - 99
    B100 - 299
    C300 - 999

The basic approach to check the attributes in BRFplus will be the following (thanks to christian.lechner for helping me out with the initial design):

  1. Create a BRFplus application with one BRFplus function CHECK_ATTRIBUTE_VALIDITY. The function takes a table of type ZCD_RAE_ATTRIBS_ATTR as input and returns if the attributes are valid and optionally an error message.
  2. The functions is implemented using a single rule set CHECK_ATTRIBUTE_VALIDITY_RS.
  3. In the rule set the attribute validity is checked in three steps using different expressions (e.g. table operations, formulae or decision tables):
    1. Check if the mandatory "Attribute 1" is present. If yes, store its value in a local variable in the rule set. Otherwise set an error message and exit.
    2. Check if the optional "Attribute 2" is present. If yes, store its value in a local variable in the rule set. If more the one "Attribute 2" is present set an error message and exit
    3. Check the attribute value ranges using the local variables and a decision table. If the value ranges are valid return success other set an error message and exit.

Especially allowing an optional "Attribute 2" while trying to check the value ranges in the decision table required some special handling. There are two reasons for this. First, it is necessary to convert the string values of the attributes into number. Second, optional attributes are not easy to handle in a decision table. I'll discuss both topics in more detail in the subsequent sections.

Implementing the BRFplus Application

Implementing the validity checks described above in a BRFplus application require to some changes to the implementation approach an experienced ABAP developer would take. The reasons for these are twofold. First, BRFplus has some special properties, like e.g. the handling of data objects, that are counter-intuitive for an ABAP developer. Second, an even more important, is the need to think in rules and expressions instead of objects, attributes and methods. This was, at least for me, the biggest difference.

In the following sections I'll describe the necessary steps in BRFplus as well as the underlying rational to the approach as detailed as possible. This way I hove to simplify the first steps in BRFplus for developers by helping them to avoid common mistakes and trap doors.

Creating the BRFplus Application

The first step in order to implement the validity checks in BRFplus is to create a BRFplus application. In order to create a the application start the BRFplus workbench using transaction BRF+. In the BRFplus workbench us "Create Application" to create a new application. for this blog I created the application ZCD_RAPIDAPP_EX as a local application.

Creating the DDIC Objects and BRFplus Data Objects

With the application in place the next step is to create the required BRFplus data objects. BRFplus offers two options for creating data objects like elements, structures and tables. Either these data objects can be created in BRFplus using build in data types or they can be created on the basis of existing DDIC object. As mentioned before BRFplus handles data objects differently then an ABAP developer would expect. In particular it is not possible to reuse a data object across functions. As a ABAP developer one would naturally try to reuse a data structure like ATTRIBUTE_1_DATA e.g. as the data type of a variable and the line type of a table data object. However, this is not possible in BRFplus. Each time a data type is used in BRFplus a separate data object needs to be created for it. In order to reduce the manual modelling effort I will therefore base the data objects in BRFplus on DDIC objects.

Most of the required DDIC objects where already created in the first part of this blog. The only additional DDIC object necessary is the structure ZCD_BRF_RAPID_APP_RESULT_S that I will use as the data type for the result of the BRFplus function. The following table shows the details of this structure:

ComponentComponent Type
ARE_ATTRIBS_VALIDBOOLE_D
ERROR_MESSAGEBAPIRET2

With the necessary DDIC objects in place it is now possible to create the required data objects. The first data object that I created is the table object ATTRIBUTE_TABLE. Data objects are created by  right clicking on the application in the repository explorer and selecting "Create -> Data Object -> Table".

In the following dialogue I set the name and description for the table data object. Furthermore, I set the binding type to "DDIC Table" and selected the DDIC type ZCD_RAE_ATTRIBS_ATTR_T. This table type was automatically created during the modelling of the Rapid Application in part one of the tutorial.

After clicking on create a number of data objects are automatically created. Besides the table data object ATTRIBUTE_TABLE the structure ZCD_RAE_ATTRIBS_ATTR and the two data elements ZZ_ATTRUTE and ZZ_VALUE are created. The following screen shot shows the created data object:

In addition to the table data object I also created the following data objects

Data ObjectDDIC TypeDescription
Structure ATTRIBUTE_1_DATAZCD_RAE_ATTRIBS_ATTRData object for local variable in the rule set to store the values of Attribute 1.
Structure ATTRIBUTE_2_DATAZCD_RAE_ATTRIBS_ATTRData object for local variable in the rule set to store the values of Attribute 2.
Structure CHECK_RESULTSZCD_BRF_RAPID_APP_RESULT_SData object for the result of the function CHECK_ATTRIBUTE_VALIDITY.

Creating the Function and the Rule Set

With the data objects in place the next step is to create the CHECK_ATTRIBUTE_VALIDITY function and the rule set implementing this function. A function is created by right clicking the BRFplus application and selecting "Create -> Function". Once the function is create make sure it is set to "Event Mode" (cf. the following screen shot).

In the signature of the function the function context (ie. the input data to the function) as well as the result data object are defined. For the CHECK_ATTRIBUTE_VALIDITY function I choose the table data object ATTRIBUTE_TABLE as the context and the structure data object CHECK_RESULT as the result data object. Note that the context of a function can consists of more then one data object. However, for this example application on the attribute table is needed.

After creating the function the next step is to create the CHECK_ATTRIBUTE_VALIDITY_RS rule set implementing the function. Again, a function can have multi rule sets assigned but for the example application only one rule set is needed. Rule sets can be created by selection the tab "Assigned Rulesets" and clicking on "Create Ruleset". Once the rule set is created I added the two data objects ATTRIBUTE_1_DATA and ATTRIBUTE_1_DATA as variable to the rule set.

Creating Auxiliary Expressions

Before modelling the rules implementing the rule set the next step is to create some auxiliary expressions. These auxiliary expression are necessary to implement the rules. As mentioned in the application design the input data to the BRFplus application will be the table data object ATTRIBUTE_TABLE. To create the BRFplus rules the following auxiliary expressions are necessary:

  1. A table expression IS_ATTRIB_1_VALID to check if exactly on attribute named "Attribute 1" is contained in the input table.
  2. A table expressions GET_ATTRIB1_VALUE to select the data of "Attribute 1" form the input table.
  3. A table expression IS_ATTRIB_2_VALID to check if zero or one attribute named "Attribute 2" is contained in the input table.
  4. A table expression IS_ATTRIB_2_SET to check if exactly one attributes named "Attribute 2" is contained in the input table.
  5. A table expressions GET_ATTRIB2_VALUE to select the data of "Attribute 2" form the input table.

From the application design most of the table expressions should be pretty clear. The first table expressions is needed to check if the "Attribute 1" is contained in the attribute table. If this is the case, the second table expression is used to select the data of "Attribute 1". The rules three and five will be used in a similar fashion. The fourth rule is needed in the decision table to distinguish between the case where the "Attribute 2" is set from the one where it is not set.

The following screen shots show the implementation of the two table expressions IS_ATTRIB_1_VALID and GET_ATTRIB1_VALUE. IS_ATTRIB_1_VALID uses the operation "Has exactly". Using this operation it checks if the attribute table contains exactly one row where the value of ZZ_ATTRIBUTE is equal to Attrib1. Note that BRFplus automatically provides the possible values for the data object in the value help. I modelled the possible values using the Rapid Application Tool in the first part of the tutorial.

The GET_ATTRIB1_VALUE function uses the operation "First line" to select the first row where the value of ZZ_ATTRIBUTE is equal to Attrib1.

The other table expressions are implemented accordingly.

In addition to the table expressions a value range expression CONTAINS_ONLY_NUMBER and a formula expression CONVERT_ATTRIBUTE_TO_NUMBER are needed. The CONVERT_ATTRIBUTE_TO_NUMBER expression uses the CONTAINS_ONLY_NUMBER expression and the build in expression TONUMBER to convert the values of Attribute 2 in the internal number representation of BRFplus. Only if the data is in this format checking the values ranges of Attribute 2 works as required. The following screen shots show the implementation details of these expressions:


Testing the Expressions

With the auxiliary functions in place it is a good time to introduce the simulation tool that is part of the BRFplus workbench. This tool can be used to simulate the execution of functions, rules and expressions during development. In order to, for example, simulate the execution of a expressions simply click on "Start Simulation" in the "Detail" section of the table expression.

Next, on the simulation screen simply accept the default values.

In the following screen it is now possible to provide input data for the simulation. As one would expect it is also possible to store the entered data as test variants or to upload test data from an excel. In my simple example I simply entered the test data manually. By clicking on "Execute and Display Processing Steps" the function is executed and the result as well as the executed processing steps are displayed. Especially when developing complex expressions or functions the simulation is helpful to test the development and analyse errors.

Creating the Decision Table

Using the auxiliary expressions it is now possible to define the decision table CHECK_ATTRIBUTE_VALUES. In the table settings of the decision table I used to "Insert Column" button to add the field ZZ_VALUE from the rule set variable ATTRIBUTE_1_DATA as the first column, the expression IS_ATTRIB_2_SET as the second column and the expression CONVERT_ATTRIBUTE_TO_NUMBER as the third column. As the result column of the decision table I selected a simple boolean value.

Using this set up I modelled the following rules in the decision table, which basically checks the third requirement of the application design.

ZZ_VALUEIS_ATTRIB_2_SETCONVERT_ATTRIBUTE_TO_NUMBERResult
A;B;Cfalse...true
AtrueBetween 1 and 99true
BtrueBetween 100 and 299true
CtrueBetween 299 and 999true

The following screen shot shows the implementation of this decision table in the BRFplus workbench.

Creating the Rules in the Rule Set

Finally, all the necessary building block to implement the rule set are in place. Using the rule set the following logic (mention already in the application design) will be implemented:

  1. Check if the mandatory "Attribute 1" is present. If yes, store its value in a local variable in the rule set. Otherwise set an error message and exit.
  2. Check if the optional "Attribute 2" is present. If yes, store its value in a local variable in the rule set. If more the one "Attribute 2" is present set an error message and exit
  3. Check the attribute value ranges using the local variables and a decision table. If the value ranges are valid return success other set an error message and exit.

The following screen shot shows the implementation of the first step in the logic implement in the rule set. The first rule uses the IS_ATTRIB_1_VALID table expression to check if the Attribute 1 is present. If this is the case the CHECK_RESULT-ARE_ATTRIBS_VALID is set to true and the variable ATTRIBUTE_1_DATA to the result of the GET_ATTRIB1_VALUE table expression. The second rule is an exit condition that checks if CHECK_RESULT-ARE_ATTRIBS_VALID is false. If this is the case the error message of the CHECK_RESULT is set to some message class value and the rule execution is terminated.

Note that the combination of the expressions IS_ATTRIB_1_VALID and GET_ATTRIB1_VALUE assures the correct data is selected. If IS_ATTRIB_1_VALID returns true only one Attribute 1 is present in the input data. So GET_ATTRIB1_VALUE which selects the first row containing the value Attribute 1 will always select the right value.

The following screen shot show the implementation of the second and third step of the logic. Rules three and four are similar to the rules one and two. This time only Attribute 2 is checked instead of Attribute 1. The fifth rule finally uses the decision table CHECK_ATTRIBUTE_VALUES to check the validity of the attribute values.

Integrating BRFplus in the Rapid Application

Implementing the rule set completes the implementation of the BRFplus application. The final step that is missing is to integrate the BRFplus application with the Rapid Application. BRFplus simplifies this integration by providing an ABAP code generator. In order to use this code generator it is necessary to switch the user mode to Expert in the personalization of the BRFplus workbench.

Once the expert mode is set the "Create Code Template" button becomes visible in the BRFplus function. The code generated using the button contains nice comments as documentation. Consequently, the generated code is basically self-explanatory. The following code snippet contains the method EXECUTE_CHECKS_USING_BRFPLUS which I omitted in the first part of the tutorial. Lines 13-35 is the code generated by BRFplus with its comments removed. Lines 37-45 is some addition error handling I added for the integration with the CRM Rapid Application framework.


METHOD execute_checks_using_brfplus.
    "Code template generated by BRF+
    CONSTANTS:lv_function_id TYPE if_fdt_types=>id VALUE '0050568F55091ED499BCB76706ABF315'.
    DATA:lv_timestamp TYPE timestamp,
         lt_name_value TYPE abap_parmbind_tab,
         ls_name_value TYPE abap_parmbind,
         lr_data TYPE REF TO data,
         lx_fdt TYPE REF TO cx_fdt,
         la_attributes_table TYPE zcd_rae_attribs_attr_t,
         la_check_result TYPE zcd_brf_rapid_app_result_s.
    FIELD-SYMBOLS: <la_any> TYPE any,
                   <error_message> TYPE bapiret2.
    GET TIME STAMP FIELD lv_timestamp.
    ls_name_value-name = 'ATTRIBUTES_TABLE'.
    la_attributes_table = i_attribute_properties.
    GET REFERENCE OF la_attributes_table INTO lr_data.
    cl_fdt_function_process=>move_data_to_data_object( EXPORTING ir_data             = lr_data
                                                                 iv_function_id      = lv_function_id
                                                                 iv_data_object      = '0050568F55091ED499BD0B2AE3281315' "ATTRIBUTES_TABLE
                                                                 iv_timestamp        = lv_timestamp
                                                                 iv_trace_generation = abap_false
                                                                 iv_has_ddic_binding = abap_true
                                                       IMPORTING er_data             = ls_name_value-value ).
    INSERT ls_name_value INTO TABLE lt_name_value.
    GET REFERENCE OF la_check_result INTO lr_data.
    ASSIGN lr_data->* TO <la_any>.
    TRY.
        cl_fdt_function_process=>process( EXPORTING iv_function_id = lv_function_id
                                                    iv_timestamp   = lv_timestamp
                                          IMPORTING ea_result      = <la_any>
                                          CHANGING  ct_name_value  = lt_name_value ).
      CATCH cx_fdt INTO lx_fdt.
        APPEND INITIAL LINE TO r_error_messages ASSIGNING <error_message>.
        <error_message>-message = lx_fdt->get_text( ).
    ENDTRY.
    "Fill error message table
    IF la_check_result-are_attribs_valid = abap_false.
      APPEND INITIAL LINE TO r_error_messages ASSIGNING <error_message>.
      <error_message>-id = 'ZCD_RAPID_APP_EX'.
      <error_message>-number = '004'.
      <error_message>-type = 'E'.
    ENDIF.
    IF la_check_result-error_message IS NOT INITIAL.
      APPEND la_check_result-error_message TO r_error_messages.
    ENDIF.
  ENDMETHOD.

The final Application

Finally, the following screen shot show the complete example application with some error messages returned from the value check in BRFplus.

Summary

To implement the BRFplus application I used a bottom up modelling approach. I started modelling the basic building block and combined them in the very end. The reason I used this approach is that I think it helps understanding which parts are necessary and why they are necessary to build an BRFplus application. Besides that, BRFplus also support a top down approach, where you basically create the necessary objects as you need them.

One thing that always puzzled me while working on this blog was the questions if performing the value checks in BRFplus is worth the effort. After all, the simple validity rules could be checked in just a few lines of ABAP code. In my opinion using the BRFplus approach is useful if either of the following hold

  • the business logic changes frequently
  • developers start to build customizing tables to enable to change the business logic independent of the program code
  • business users want to be able to change the rules themselves.

In the example application I could easily add a third attribute and value checks for it without touching any of the ABAP code. The change could be performed by just modelling in the Rapid Application and the BRFplus application. This is in my opinion a very important factor as it will reduce development and test effort.

As this blog was my first endeavour in the area of BRFplus I would be happy to discuss my approach in the comments section. I'm sure there are areas where my design could be improved.

In summary, this two part blog showed that the combination of CRM Rapid Applications and BRFplus is a very effective approach to develop small business applications from scratch.

Christian

1 Comment
Labels in this area