You are on page 1of 48

Creating a Simple Business Object in BOPF

21.12.2009

Table of Contents 1. Authors ................................................................................................................................... 3 1. Scope of the Document ...................................................................................................... 4 2. Introduction to BOPF ......................................................................................................... 4 2.1. Business Object Processing Framework...................................................................... 4 2.2. Implementation Considerations ................................................................................... 4 2.3. Business Object ........................................................................................................... 5 2.4. How to check the Business Object .............................................................................. 5 3. Creating a Simple BO ........................................................................................................ 5 3.1. BO Creation ................................................................................................................. 5 3.2. Maintaining BO Settings ............................................................................................. 6 3.3. Business Object Nodes ................................................................................................ 7 3.4. Creating and Generating the DDIC Elements ........................................................... 10 4. Adding a Sub Node to the BO .......................................................................................... 13 5. Query ................................................................................................................................ 15 5.1. Creation of a Query ................................................................................................... 15 6. Alternative Keys ............................................................................................................... 23 6.1. Creation of Alternative Keys ..................................................................................... 23 7. Validation ......................................................................................................................... 26 7.1. Creation of a Validation ............................................................................................ 26 7.2. Implementation of Validation .................................................................................... 30 8. Determination ................................................................................................................... 34 8.1. Creation of a Determination ...................................................................................... 34 8.2. Implementing a Determination .................................................................................. 38 9. Action ............................................................................................................................... 40 9.1. Creation of Action ..................................................................................................... 40 9.2. Implementing an Action ............................................................................................ 42 10. Associations .................................................................................................................. 43 10.1. Association to a Delegated node ............................................................................ 44 10.2. Creating Association to Dependent Object ............................................................ 44 11. Testing the Business Object .......................................................................................... 46

1. Authors
Role Name

Author Author Reviewer

Santosh Kumar Goud Laddipelly Frank Mock DL Suite_V&C_Architecture Team

1. Scope of the Document


This document should be a general help for people who want to do first steps with BOPF in the Business Suite. It will cover the main steps that are needed to define a BO in the BOPF framework. The main aim of this document is that it should be useful to everyone who is using the BOPF for first time ever. Here we are showing how to Create a Business Object by name ZMY_CUSTOMER Add nodes to the BO Create the DDIC elements for a BO Create a query for the BO Create an Alternative Key for the BO Create a Validation for the BO Create a Determination for the BO Create an Action for the BO Create an Association for additional nodes

2. Introduction to BOPF
2.1. Business Object Processing Framework
The Business Object Processing Framework (BOPF) is a framework used to implement Enterprise Services Oriented Architecture (eSOA)-compliant business objects. It provides integrated functionality for business object implementation and leads to a common programming model by design. BOPF controls the application businesses logic as well as the data retrieval of the buffer and persistency layer. The main design principles are a clear separation of the business logic and the buffering of data as well as a clear structuring of the business logic in small parts with a clear separation of changing and checking business logic. This framework offers an incremental and modular approach to your business objects implementation. You can quickly set up an initial, running prototype of your business object with its most basic services already enabled (such as create, retrieve, updated, delete, save and query). BOPF supports advanced enhancement and configuration options at every level, such as defining the specific business logic and performance optimization attributes that are unique to your business object.

2.2. Implementation Considerations


BOPF provides flexibility and adaptability while implementing your business object by offering a complete overview of your business objects internal structure, business logic and behavior. The framework also offers convenient standardization and flexibility. You can implement your business object using BOPFs built-in buffers and data access classes (which you can use via configuration), or implement your own. BOPF also integrates ABAP unit test capabilities for an overall higher quality of your business objects implementation. The advantages of implementing BOPF are as follows: Supports your business object implementation with multiple generic functions and full ESOA-compliance Gives you a complete overview of your internal business object structure, business logic and behavior

Offers you the possibility to implement your Business Object in an incremental and modular way Leads to a high reuse of your business methods Provides you with a running prototype in a very short time frame Engineering approach for business object implementation; many parts are configured, not implemented Providing a common transaction model Central user interface to configure your business object, which provides: o Seamless integration with the ABAP development workbench o Same look and feel as that of the backend systems o Forward navigation support and creation of assigned classes, data structures and database tables o Versioning of the business object model and configuration

2.3.

Business Object

Business Object represents A view on a well defined & outlined business content Well known in the business world (for example, in an international standard or industry best practice) A self-contained (capsule), independent business concept Transaction to access BOPF in Business Suite is /BOBF/CONF_UI.

2.4.

How to check the Business Object

There are some additional checks which can be utilized while creating the BO Standard Check which contains only short-running configuration checks ( ) Extended Check which contains also long-running configuration checks ( ) Performance Check which checks the configuration of the BO (in the menu path Business ObjectCheckPerformance Check) Check & Correct which is able to automatically correct some minor errors of the business object configuration. (in the menu path Business ObjectCheckCheck & Correct). In contrast to it, the standard/ extended check does not change your business objectss configuration. You can use these checks at any point of time during the creation of the Business Object. It is strongly recommended to run the extended check at least before the transport of the Business Object. The extended check indicates, if the execution of the Check & Correct function is necessary.

3. Creating a Simple BO
This chapter is about the creation of a new business object by the help of the BOBF Configuration UI.

3.1.

BO Creation

When you create a Business Object in a Business Suite have to create the BOPF BO model manually via the BOPF Configuration UI tool. 5

1. Start the BOPF Configuration UI (transaction /BOBF/CONF_UI from your development system) 2. Create a Business Object by clicking create icon or by pressing F5 3. Enter the Business Objects name you want to create and press enter (leave the super business object field empty). In our example it is named ZMY_CUSTOMER. 4. You will be entering into a BO level as shown in the figure below:

5. Give a small description about the BO e.g., My first BOPF BO 6. Maintain the BO prefix ZMY. The prefix is used when BOPF proposes names for repository elements. This will be done later on. A Business Object must either have a prefix or a namespace (or both) in order to clearly separate its BOPF and DDIC entities from other Business Objects.

3.2.

Maintaining BO Settings

Now we have to maintain the necessary settings required on the BO-level which can be done by the following Menu path Extras Propose Repository Names which displays the image as shown below. At this point in time we are proposing names for repository objects at the BO level only, whereas the same procedure should be followed at the node level as well. Here we only select the constant interface at the BO-level. The constant interface carries constants for all the elements of the BO that are needed to access the BO (for e.g., constants for node, keys, associations, etc.).

As buffer class and data access class we use the default implementations provided by BOPF which are already maintained in the corresponding fields. Alternatively we could also generate our own classes. If we would do so, we would propose the names for theses classes as well. After selecting the entry Constant Interface Name press ok.

Till now we have just named the constant interface. Now we have to generate the same by the following menu path ExtrasGenerate Repository ObjectsGenerate Constant Interface. As a result the interface is generated and activated.

3.3.

Business Object Nodes

The root node is created by default for every BO. In order to configure it, double click on the root in the navigation pane on the left hand side of the screen as shown in the figure (highlighted in red) to enter into the root node:

Give a small description about the root node You can also change the root node name depending on your convenience We keep the flags Node Can Be Loaded Separately and Node Can Be Locked Separately.

Now we propose the names for a couple of DDIC elements. For each node of the business object BOPF needs these elements during the handling of the business objects data and for the persistency of this data. We propose the names by following the menu path Extras Propose Repository Names: Data Structure: DDIC structure which contains the persistent attributes (fields) of the node Transient Data Structure (Data Structure tr.): DDIC structure which contains the transient attributes of the node. In contrast to the persistent attributes, transient attributes are only stored in the working memory and not in the persistency (e.g. database). Combined Structure: DDIC structure which contains the technical key fields and the Data Structure and the Transient Data Structure as include Combined Table Type: internal table with Combined Structure as line type. The table type is used by BOPF to hold the data in memory and during communication with a consumer, e.g. UI Database Table: The database table which contains the node data. In the tutorial we use a simple 1:1 relationship between nodes and database tables, i.e. each node is stored in its own database table. Alternative approaches are possible.

You can see the figure below which displaying all the names as selected.

Here you can also change the names of the data structures and database table based upon your requirements before the generation of the DDIC Elements. For this tutorial we change the proposed names in order to reflect the BO name in the structures. Thus change the names as follows: Combined Structure name to ZMY_S_CUST_ROOT Combined Table Type name to ZMY_T_CUST_ROOT Data Structure to ZMY_S_CUST_ROOT_D Data Structure (tr.) to ZMY_S_CUST_ROOT_DT Database Table to ZMY_D_CUST_ROOT

3.4.

Creating and Generating the DDIC Elements

After proposing the names for the required data types they can be generated respectively created manually. The Data Structure and the Transient Data Structure always have to be created manually since they contain the application specific fields of a node. Thus the next step is to create these DDIC structures. 1. Create Data Structure ZMY_S_CUST_ROOT_D Create the Data Structure by double clicking the name ZMY_S_CUST_ROOT_D Create the structure in the DDIC as shown in the following figure

10

2. Create Data Structure transient ZMY_S_CUST_ROOT_DT Create the Data Structure by double clicking the name ZMY_S_CUST_ROOT_DT Create the structure in the DDIC as shown in the following figure

Dont forget to activate the structures! 3. Now we can generate the remaining data structures using the BOPF generation feature by following the menu path Extras Generate Repository Objects Generate Dictionary Elements by which a window pops up to confirm the elements to be generated.

11

Generate the data types by selecting Combined Data Structure, Combined Table Type and Database Table in the popup as shown in the figure. Now you can check whether the structures are generated properly by double clicking them and navigating into the DDIC.

Note: You have to regenerate your constant interface after creating every new elements in order to add the new or changed elements. Your Business Object can be already used. You can just test it by the help of the generic BOPF Test UI application - click on the execute button or press F8.

12

You can see the hierarchical tree of the Business Object created by you. Here double click the root node click on create button in the right panel. Now you can create and save the data.

4. Adding a Sub Node to the BO


You can enter additional nodes and sub nodes to your BO via the context menu in the Business Object Detail Browser as shown in the figure below. Here you have to select the Node Type Standard Node for adding a normal Business Object Node Delegated Node for adding a Dependent Object to your node structure Business Object Representation Node for adding a cross BO reference to your BO model

After this step there will be a pop up asking for the name of the sub node. Here enter the name and the data model as shown below and press the Final button.

13

The Guided Procedure also allows to maintain an attribute mapping, but this is not required in the Business Suite as we do not have any proxy Business Object. We also dont maintain a persistence mapping since the database table we use will have the same fields as the nodes data structure. Now you can see the sub node attached to the BO in the node structure in the Business Object Detail Browser and you can create the data structure ZMY_S_BANK_DETAILS_D for the Bank Details node as shown in the following figure. Double click structure name in the node maintenance screen or go to SE11 and create the structure.

14

Afterwards repeat the steps from chapter 4 to generate the Combined Data Structure, the Data Table and the Database Table.

5. Query
5.1. Creation of a Query
A query allows you to perform searches on business object nodes. For each node one or several queries might be created. They provide the initial point of access to business objects. Each query has an associated parameter structure. The result of the query can be 1. a set of all the node instance IDs or 2. a set of node instances including IDs and data or 3. a set of records in an internal table that match the query criteria. Here in our example we are creating a query which is used to select customer root nodes with using the data structure of the root node as query parameter structure and the Combined Data Table as result table (option 3 from the list above). You can create a query by accessing the tree on your left hand side as shown in the diagram.

15

After selecting the Create Query command a pop up comes up where you have to enter the name of the query and the description. Fill the fields as shown in the figure below.

16

In the query we define a Query Result Type, i.e. the query implementation has to fill an internal table that is type with Result Table Type. After query execution, BOPF directly returns the table to the caller of the query. The result table is not buffered in BOPF. In contrast, a query that does not specify a Result Table Type only returns the node IDs. Using these node IDs BOPF then triggers internally the retrieve method in order to read the node data if that is requested by the caller. As result, the BOPF buffer is filled with all node instances corresponding to the queried node IDs. Thus the Result Table Type in a Query should be used if the result must not be buffered in BOPF and you want to achieve the best performance and memory consumption. Now we create the query implementation: After you maintained the fields as shown in the figure above press the finalize button. In the query details screen double click on the name of the query class. Process the pop-ups to create the class, redefine the query method in the

17

created class and copy the code snippet listed below into it. Afterwards save and activate the class.
METHOD /bobf/if_frw_query~query. DATA: ls_key TYPE /bobf/s_frw_key, lt_selection TYPE /bobf/t_frw_query_selparam, ls_selection TYPE REF TO /bobf/s_frw_query_selparam, ls_sorting TYPE /bobf/s_frw_query_sorting, lv_index TYPE i, lv_max_rows TYPE i, lv_where TYPE string, lt_where TYPE STANDARD TABLE OF string, lv_order TYPE string, lt_order TYPE STANDARD TABLE OF string, lt_range_key TYPE RANGE OF /bobf/conf_key, ls_range_key LIKE LINE OF lt_range_key, ls_comp TYPE cl_abap_structdescr=>component, lt_comp TYPE cl_abap_structdescr=>component_table, ls_range_r TYPE REF TO data, lo_range TYPE REF TO cl_abap_structdescr, lt_range TYPE RANGE OF string, "#EC NEEDED ls_range LIKE LINE OF lt_range, lt_result_db TYPE STANDARD TABLE OF zmy_d_cust_root, ls_result TYPE zmy_s_cust_root, lt_result TYPE zmy_t_cust_root, lx_root TYPE REF TO cx_root. FIELD-SYMBOLS: <ls_result_db> TYPE zmy_d_cust_root, <ls_range> TYPE any, <lt_range> LIKE lt_range. CLEAR: et_key, et_data, es_query_info. * build where condition for key filter IF it_filter_key IS NOT INITIAL. LOOP AT it_filter_key INTO ls_key. ls_range_key-option = 'EQ'. ls_range_key-sign = 'I'. ls_range_key-low = ls_key-key. INSERT ls_range_key INTO TABLE lt_range_key. ENDLOOP. lv_where = 'DB_KEY IN LT_RANGE_KEY'. APPEND lv_where TO lt_where. ENDIF. * build where condition from selection IF it_selection_parameters IS NOT INITIAL. lt_selection = it_selection_parameters. SORT lt_selection BY attribute_name. LOOP AT lt_selection REFERENCE INTO ls_selection. AT NEW attribute_name. ls_comp-name = ls_selection->attribute_name. ls_comp-type ?= cl_abap_typedescr=>describe_by_data( lt_range ). APPEND ls_comp TO lt_comp. ENDAT. ENDLOOP.

18

lo_range = cl_abap_structdescr=>create( lt_comp ). CREATE DATA ls_range_r TYPE HANDLE lo_range. ASSIGN ls_range_r->* TO <ls_range>. LOOP AT lt_selection REFERENCE INTO ls_selection. AT NEW attribute_name. IF lt_where IS NOT INITIAL. lv_where = 'AND'. APPEND lv_where TO lt_where. ENDIF. CONCATENATE '<LS_RANGE>-' ls_selection>attribute_name INTO lv_where. ASSIGN (lv_where) TO <lt_range>. ENDAT. MOVE-CORRESPONDING ls_selection->* TO ls_range. INSERT ls_range INTO TABLE <lt_range>. AT END OF attribute_name. IF ls_selection>attribute_name = /bobf/if_conf_c=>sc_attribute_name_key. ls_selection->attribute_name = 'DB_KEY'. ENDIF. CONCATENATE ls_selection->attribute_name 'IN' lv_where INTO lv_where SEPARATED BY space. APPEND lv_where TO lt_where. ENDAT. ENDLOOP. ENDIF. * build order by table LOOP AT is_query_options-sorting_options INTO ls_sorting. IF ls_sorting-ascending = abap_true. CONCATENATE ls_sortingattribute_name 'ASCENDING' INTO lv_order SEPARATED BY space. ELSE. CONCATENATE ls_sortingattribute_name 'DESCENDING' INTO lv_order SEPARATED BY space. ENDIF. APPEND lv_order TO lt_order. ENDLOOP. * default order if paging is active IF sy-subrc <> 0 AND is_query_options-paging_optionspaging_active = abap_true. lv_order = 'DB_KEY ASCENDING'. APPEND lv_order TO lt_order. ENDIF. IF is_query_options-paging_options-paging_active = abap_true AND is_query_options-paging_options-start_key IS NOT INITIAL. IF lt_where IS NOT INITIAL. lv_where = 'AND'. APPEND lv_where TO lt_where. ENDIF. lv_where = 'DB_KEY GT IS_QUERY_OPTIONS-PAGING_OPTIONS-START_KEY'. APPEND lv_where TO lt_where. ENDIF. IF is_query_options-maximum_rows > 0. lv_max_rows = is_query_options-maximum_rows. IF is_query_options-paging_options-paging_active = abap_true AND

19

is_query_options-paging_options-start_row IS NOT INITIAL. lv_max_rows = 0. ENDIF. ENDIF. TRY. SELECT * FROM zmy_d_cust_root UP TO lv_max_rows ROWS INTO CORRESPONDING FIELDS OF TABLE lt_result_db WHERE (lt_where) ORDER BY (lt_order). "#EC CI_DYNTAB "#EC CI_DYNWHERE es_query_info-count = sy-dbcnt. LOOP AT lt_result_db ASSIGNING <ls_result_db>. MOVE-CORRESPONDING <ls_result_db> TO ls_result. ls_result-key = <ls_result_db>-db_key. INSERT ls_result INTO TABLE lt_result. ls_key-key = <ls_result_db>-db_key. INSERT ls_key INTO TABLE et_key. ENDLOOP. CATCH cx_sy_sql_error INTO lx_root. ASSERT ID /bobf/dac CONDITION 0 = 1. RAISE EXCEPTION TYPE /bobf/cx_dac EXPORTING previous = lx_root mv_node = is_ctx-node_key. ENDTRY. * fill export parameters IF is_query_options-paging_options-paging_active = abap_true AND is_query_options-paging_options-start_row IS NOT INITIAL. IF is_query_options-paging_options-start_row > 1. DELETE lt_result TO is_query_options-paging_options-start_row - 1. ENDIF. IF is_query_options-maximum_rows > 0. lv_index = is_query_options-maximum_rows + 1. DELETE et_key FROM lv_index. ENDIF. ENDIF. et_data = lt_result. ENDMETHOD.

Note: You have to regenerate your constant interface after creating every new object so as to maintain the constants for all the elements. Now you can test the query function using the BOPF test tool. Once the test tool has opened, press enter and select the query as shown in the figure below. Double click the query, maintain selection criteria as you want and execute it by press continue.

20

If you execute the query, you will recognize, that the results are only displayed in a popup (see next picture).

At the time of writing this document it is not possible to take over the result of a query with a Result Table Type into the main window. Thus we will quickly create an additional query, which does not use the Result Table Type just to allow you to use the test tool. In order to create the query go back into the BOPF Configuration UI and create a query again for the root node with the settings shown in the figure below:

21

Please be aware of the difference between this query and the one with Result Table Type: The new query does not specify an implementation class and remember the difference in the buffer handling of the result: the results of this query are always buffered until the end of the transaction (in most use cases this is not desirable). The query is executed by the data access class of that node (/BOBF/CL_DAC_TABLE). This class has a generic query implementation, which can be used when 1. The search parameters map to the nodes attributes and 2. No Result Table Type is used In the future the data access class may also support the Result Table Type, but at the time of writing that document it is not supported. Now you can test the BO again as described above and using the newly created query.

22

6. Alternative Keys
6.1. Creation of Alternative Keys
An Alternative Key is a defined set of attributes of a business object node that identifies a single (unique key) or a set of (non unique key) node instance. Alternative Keys are used typically to model semantic keys of BO node. From a definition point of view an Alternative Key is quite similar to a query. One major difference is that a query searches by definition on the database only, whereas an Alternative Key can search first within the transactional buffer and might afterwards also search on the database if necessary. If the before image is requested it is identical to a query. The second distinction is that an Alternative Key can be a key for the corresponding node. That means for each combination of field values of the Alternative Key leads to exactly one result and therefore to one Node ID. That information can be used to optimize the search in the transactional buffer because as the search can be stopped if all requested node instances are found. The third difference is that a query is defined as such over fields that can be located everywhere within the BO Model. In some cases the query fields are even not part of the Model at all. However the fields of an Alternative Key are all defined as fields of one node. To create an Alternative Key we can use the tree on the left side of the screen as shown in the figure below.

Maintain the name of the Alternative Key and provide a small description for your understanding. In our example the name of the Alternative Key is CUSTOMER_ID. In addition you maintain the Data Type, the Data Table Type and the Secondary Key.

23

In general Alternative Keys can be defined in two different ways 1) If an Alternative Key comprise several fields, you have to maintain a DDIC structure in the Data Type field. In this case, each field in the structure has to map to a field in the nodes Combined Data Table. 2) If an Alternative Key comprises a single field only, you can maintain a Data Element in the Data Type field. In this case, the Name of the Alternative Key has to map to a field in the nodes Data Type. Following this tutorial you define the Alternative Key in this way. The Data Type field contains the Data Element /BOBF/DEMO_CUSTOMER_ID and the name of the Alternative Key CUSTOMER_ID maps to the field CUSOMTER_ID in structure ZMY_S_CUST_ROOT_D. But you could also maintain a structure with a single field here. In the Data Table Type field you maintain an internal table which uses the type maintain in the Data Type field as line type. In order to follow the example you need to maintain table ZMY_T_CUSTOMER_ID that uses the data element /BOBF/DEMO_CUSTOMER_ID as line type. You also maintain a Secondary Key in order to achieve a good performance when using the alternative key. The secondary key you maintain here refers to the nodes Combined Table Type (not to the Data Table Type of the Alternative Key). Thus you have to maintain the secondary key in the nodes Combined Data Table. BOPF takes over the secondary key maintenance for you when you use the feature to generate DDIC Elements. You will do that now: After you maintained the Alternative Key as shown in the figure above, generate the relevant DDIC elements by following the menu path ExtrasGenerate Repository ObjectsGenerate DDIC Elements. Maintain the settings in the popup as shown in the picture below and click the generation button.

24

If you now look into the definition of the Combined Data Table Type of the node in the DDIC you will see that a secondary key with the name CUSTOMER_ID and the component CUSTOMER_ID was created.

25

Note: You have to regenerate your constant interface after creating every new object so as to maintain the constants for all the elements Now you can test the Alternative Key using the test tool. When you open the test tool by pressing F8 you can find also the Alternative Key CUSTOMER_ID created by you in the Meta Data and Instance Tree: Double click the Alternative Key CUSTOMER_ID by which a pop up is opened Click on the Append Row button and give a customer Id which is already existing in the database Click on continue to see the effect

7. Validation
7.1. Creation of a Validation
A Validation is an element of a business object node that describes some internal checking business logic on the business object. There are two types of Validations 1. Action Validation to check if an action is allowed 2. Consistency Validation to check the consistency of the Business Object 26

An Action Validation is assigned to object-specific actions (e.g. Release) and to the framework actions Create, Update, Delete and Save. An Action Validation is carried out when an action is called but before it is performed. A Consistency Validation can be used to check the consistency of a business object. They can be triggered after a modification (Create, Update, Delete) of a node or during the execution of the framework action check. To create a validation you can use the Business Object Detail Browser. During the creation of a validation you also have to decide if you want to create a Consistency Validation or an Action Validation. In our example you create a Consistency Validation which is used to check the uniqueness of the Customer ID after entering it.

In order to create the validation highlight the root node. In the context menu execute command CreateCreate ValidationConsistency Validation. In the appearing popup enter the name of the Validation you wish to create - in our case it is CHECK_ROOT_CONSISTENCY class name ZCL_CUST_V_CHECK_ROOT_CONS in field Class

27

In the next step mark the request nodes for the validation as shown in the following figure. Request Nodes are the trigger for the execution of a validation. This means if a node instance of the configured request nodes is changed the execution of the validation is triggered. NOTE: Only Consistency Validation does have Request Nodes. Action Validation does not have request nodes as the execution of Action Validations is triggered by the execution of the action.

28

In the next step mark the Node Category for which the validation is executed. Each node instance belongs to only one node category. Such a category allows you to group model elements, like validations determination, into different configurations. At runtime BOPF decides based on the node category of an instance which configuration needs to be applied and executes the corresponding elements. In most cases you may have only one node category the default one - which is maintained automatically by BOPF. In these cases you will not get in touch with it. However in this step you have to assign the validation to the node category. For the example select the node category Root.

29

The Validation Sequence on the next step cant be maintained sine you dont have another validation created yet, which could be executed before or after the current validation. Thus processed with Finalize Guided Procedure.

7.2.

Implementation of Validation

A validation has to implement the interface /BOBF/IF_FRW_VALIDATION. This interface has got three methods: Check, Check Delta and Execute. Method CHECK is used to adjust the set of node instances for which a validation should be invoked. This is only a reduction of the instances, and therefore no new instances must be added. Implementing this method is optional. Method CHECK_DELTA inspects the delta between the old and the new state of a node instance. It is intended to remove instances that do not need to be validated because the relevant changes were not made. An inclusion of new node instances must not be done. This check is intended to narrow down the instances to carry out a validation since BOPFs triggering of validation only acts on the node level and not on the node attribute. Therefore, BOPF cannot determine if a change is relevant for a validation. Implementing this method is optional. Method EXECUTE is used to perform check of the conditions to be checked. Node instances that are violating the conditions are reported back as failed and messages can be created to report on the cause of the failing validation In the example of this tutorial you reuse the existing validation implementation /BOBF/CL_LIB_V_ALT_KEY. The class checks the uniqueness of alternative keys. Remember that you have maintained the alternative key CUSTOMER_ID on the Root node earlier. This alternative key maps to the CUSTOMER_ID field you now want to check for uniqueness. Thus you can reuse the class. 30

You can find the class in the BOPF Library Browser. The BOPF Library Browser can be reached via the entry screen of the BOPF Configuration UI as shown in the following figure.

Within the Library Browser open branch /BOBF/LIB_LIBRARY and double click on the class name /BOBF/CL_LIB_V_ALT_KEY. Afterwards more details in the class are available.

31

As you can see there are many classes within the BOPF Library Browser which are all provided for reuse. Thus make yourself familiar with them as you need. Now lets reuse the class. Thus go back into your business object and open the validation CHECK_ROOT_CONSISTENCY you have created above.

32

In order to create the validation implementation double click on the class name ZCL_CUST_V_CHECK_ROOT_CONS which you have named earlier during the creation of the validation. Proceed the popups to create the validation. Once the validation has been created, you have to change the Super Class of you created validation class. Switch the Super Class of ZCL_CUST_V_CHECK_ROOT_CONS to /BOBF/CL_LIB_V_ALT_KEY. During the switch you are asked to keep the redefinitions. Dont keep them, discard them.

33

After the switch you can redefine the methods /BOBF/CL_LIB_V_ALT_KEY~CREATE_MSG_DUP_KEY: is used to create (error) messages for duplicate keys /BOBF/CL_LIB_V_ALT_KEY~FILTER_RELEVANT_ALT_KEYS: is used to remove alternative keys which shall not be checked by this implementation. Class /BOBF/CL_LIB_V_ALT_KEY can perform uniqueness checks for all alternative keys which are maintained on the node for which the class is executed and which are configured as unique. If you want to execute the check not for each of these alternative keys you can remove those alternative keys which are not relevant in this method implementation. In the example you implement in this tutorial you dont need to redefine any method. For simplicity reasons you can reuse the messages provided by the library class. Additionally you have only one alternative key configured in your BO that you want to check. Thus after switching the Super Class active your class and go back into the BOPF Configuration UI of your BO. Note: You have to regenerate your constant interface after creating every new object so as to maintain the constants for all the elements. You can use the extended check for any errors and also check and correct if recommended. Now you can test the Validation using the test tool. Open the test tool by pressing F8, maintain the Customer ID and see whether you get messages.

8. Determination
8.1. Creation of a Determination
A Determination is an element of a business object node that describes internal changing business logic on the business object. It can be used to trigger business logic based on the internal changes (in contrast to an action). A determination is mostly used to compute data that can be derived from the values of other attributes. There are two types of determinations: persistent and transient determinations. The category indicates whether a determination alters persistent or only transient data. Within this tutorial you will create a transient determination which calculates the age of the customer after he/she was loaded from the database or the birthdate was changed. To create a determination you have to select the option Create Determination in the Business Object Detail Browser.

34

In the appearing popup provide: A name for the determination you wish to create followed by a small description about the determination. In our example it is CALCULATE_AGE Choose the determination category. In our case it is a transient determination, because only transient fields or nodes are affected by the determination Choose the change mode: Use Only Read Mode for determinations with category Transient and Exclusive Write Mode for determinations with category Persistent. Thus for this determination you use Only Read Mode. Give the class name which has to be implemented to maintain your determination. In our example it is ZCL_CUST_D_CALCULATE_AGE

35

Proceed to the next step in the guided procedure and maintain the Request Nodes: Request Nodes are the triggers for the execution of a determination. This means if a node instance of the configured Request Nodes gets changed/ loaded the execution of the determination is triggered. You also have to select which operation on the configured Request Nodes exactly should trigger the execution. Possible operations are Create, Update, Delete, Load or Determine. For this tutorial make your selection as shown in the figure below. Optionally you could also select Read Nodes. The BOPF loads the configured Read Nodes before executing the determination. If the implementation of the determination takes advantage of the mass-enabeld core services, it does not make sense to maintain them (see BOPF performance guideline for more information)

36

On the next step of the guided procedure you need to maintain the BOPF events at which the determination is triggered. The determination for calculating the age shall be trigger after customer root node instances are loaded from the database into the BOPF buffer or after a consumer has changed the birthdate of a customer. Thus the triggering events After Loading and After Modify need to be selected.

37

Business Logic
Determination Times & Trigger Conditions
Trigger condition Determination Time Before Retrieve
Only for Transient Determinations Only for transient nodes

Create

Update

Delete

Load1

Determine

After Loading After Modfiy During Check&Determine After Validation Before Save: X X X X X X

Only for Persistent Determinations

Before Consistency Check Finalize Draw numbers During Save: Before Writing Data

X X X X

X X (X)2 X

X X (X)2 X

After Commit
After Failed Save Attempt

X
X

X
X

X
X

1) Trigger Condition Load is only available, if at least one of the request nodes is a transient one. 2) There is usually no need to take numbers during update or delete.
SAP 2007 / Page 20 AG 2009. All rights reserved. / Page 20 Confidential

Figure 1: Overview of triggering events for determinations

On the next step of the guided procedure you could maintain sequence dependencies between determinations. Since you dont have another determination that screen is empty and you dont need to maintain anything. Thus click the finalize button to complete the guided procedure.

8.2.

Implementing a Determination

To make the Determination effective we have to implement the class, so double click on the class name ZCL_CUST_D_CALCULATE_AGE which you have named earlier during the creation of the determination. Proceed the popups to create the class. A determination implementation has to implement interface /BOBF/IF_FRW_DETERMINATION which contains the following methods. CHECK: checks if the execution of the determination is necessary. In contrast to the check_delta method, this check take the semantic into account. Implementing this method is optional. CHECK_DELTA (analogous to validation): In this method you can compare the old image of the data with the current image of the data and decide if the execution of the validation is necessary or not dependend on the changed attribute values. Implementing this method is optional. EXECUTE: This method contain the real business logic of the determination. For your example determination paste the following code into method EXECUTE.
METHOD /bobf/if_frw_determination~execute. DATA:

38

lt_chg_fields lr_root lt_root lv_age

TYPE /bobf/t_frw_name, TYPE REF TO zmy_s_cust_root, TYPE zmy_t_cust_root, TYPE datum.

io_read->retrieve( EXPORTING iv_node = it_key = iv_fill_data = IMPORTING et_data = ).

is_ctx-node_key it_key abap_true lt_root

APPEND 'AGE' TO lt_chg_fields. LOOP AT lt_root REFERENCE INTO lr_root. lv_age = sy-datum - lr_root->date_of_birth. lr_root->age = lv_age+0(4) - 1. io_modify->update( EXPORTING iv_node iv_key is_data it_changed_fields ). ENDLOOP. ENDMETHOD.

= = = =

is_ctx-node_key lr_root->key lr_root lt_chg_fields

Method io_modify->update collects all updates internally without passing the changes immediately to the BOPF buffer. The BOPF buffer is updated later, after the execute method was finished. If you need an buffer update early you have to call io_modify->end_modify which triggers the buffer update. However, BOPF automatically calls this method after the execute method was finished. The number of determinations you configure for a certain event can have a strong impact on the performance of your BO. Especially the modifications that are done within a determination have an impact on the performance. Thus, the more determinations you use (and by that the more modifications) the slower may be the performance of your BO. Thus from a performance perspective you may use only one determination for a triggering event. Also explicit calls to method io_modify->end_modify within your determination implementation may impact the performance of your BOs. On the other hand side the reuse potential of a determination is higher, if the determination is very fine grained, e.g. responsible for a single field update. Thus the recommendation for BOs with high performance requirements is: For each relevant triggering event configure only one determination. Avoid calling io_modify->end_modify explicitly if possible. Reuse is shifter from the determination itself to classes which are called within the determination, i.e. within the determination implementation delegate the responsibility to other classes which you design for reuse. You can then reuse/call these classes within different determinations. The example determination that you have implemented in this tutorial you use a fine grained determination for simplicity reasons only. For a real life determination you may follow the recommendations above. 39

Now you can test the Determination using the test tool. Open the test tool by pressing F8 and set/change the birthdate of a customer. The field Age is automatically calculated.

9. Action
9.1. Creation of Action
An action is an element of a business object node that describes an operation performed on that node. An action can be used to allow the external triggering of business logic (in contrast to a determination). BOPF supports different actions cardinalities: static actions, single node instance action or multiple node instance action. When you use single or multiple node instance actions the consumer must specify the node instance keys on which the action is to be performed. For static actions the node instances keys are not used. The action execution can be influenced by action validations (see above). When a consumer calls an action, BOPF checks whether action validations are configured for the called action. If this is the case, these action validations are executed before the action implementation is called. Within the action validation you can reduce the number of node instance keys that are afterwards passed to the action implementation. In addition you can configure an action to get executed only, if an corresponding action validation does not return a failed key. This configuration is done in the action configuration screen. The example in this tutorial does not use that option. In the example here you will create an multiple instance action on the Bank Details nodes which locks the given bank accounts. To create a action we have to select the option Create Action from the Business Object Detail Browser as shown in the figure below.

40

In the displayed popup provide the following information: Give the name of the action you wish to create followed by a small description about the action. In our example it is LOCK_BANK_ACCOUNT Set the Action Cardinality to Multiple Node Instances. Set the Change Mode to Exclusive Write Mode. Maintain a class name which implements the action. In the example maintain ZCL_CUST_A_LOCK_BANK_ACCOUNT.

Skip the next step of the guided procedure (you dont need to maintain read or write nodes). On the third step select the node category as shown in the figure below.

41

Afterwards finalize the guided procedure.

9.2.

Implementing an Action

To make the Action effective you have to implement the class. Therefore double click on the class ZCL_CUST_A_LOCK_BANK_ACCOUNT and follow the popups to create the class. Actions have to implement interface /BOBF/IF_FRW_ACTION which contains the following methods: RETRIEVE_DEFAULT_PARAMETERS is used to get context dependent default values for the parameters of an action. PREPARE method is used to adjust the set of node instances the action is invoked on. This includes removing and adding instances. EXECUTE method implements the action. In this tutorial you create an action to set the lifecycle status to locked, the coding we have used is as shown in the figure
METHOD /bobf/if_frw_action~execute. DATA: lt_bank_details lt_chg_fields lr_bank_details io_read->retrieve( EXPORTING iv_node = it_key = iv_fill_data = IMPORTING et_data = ). TYPE zmy_t_cust_bank_details, TYPE /bobf/t_frw_name, TYPE REF TO zmy_s_cust_bank_details.

is_ctx-node_key it_key abap_true lt_bank_details

APPEND zif_cust_zmy_customer_c=>sc_node_attribute-bank_detailslc_status TO lt_chg_fields. LOOP AT lt_bank_details REFERENCE INTO lr_bank_details. lr_bank_details->lc_status = '01'. " locked io_modify->update( EXPORTING iv_node = is_ctx-node_key iv_key = lr_bank_details->key is_data = lr_bank_details it_changed_fields = lt_chg_fields ). ENDLOOP. ENDMETHOD.

Now you can test the action using the test tool. Open the test tool by pressing F8. Select a customer, navigate to the customers bank detail node and execute the action.

42

10.

Associations

BO nodes are linked by associations. BOPF supports different association types. The most important one is the Composition association by which the BO node hierarchy is defined. When you create a child node BOPF automatically creates a composition association between the parent and the child node. In addition it creates two further associations: one from the child node to the parent node (TO_PARENT) and one up to root node (TO_ROOT). The composite association by default gets the name of the created node. Besides composition associations BOPF supports: Foreign Key associations: The key of the target node instance is contained in an attribute of the source node. Reverse Foreign Key associations: The key of the source node is contained in an attribute of the target node. A Reverse Foreign Key association determines the keys of those target nodes which contain the source node key as foreign key. The BOPF composition association belongs to this type. Specialization associations: A Specialization is a filtered composition. It filters the composition by some constant values (e.g. role code). At runtime the check is performed against a field in the target node. Reverse Specialization associations: Is a kind of filtered Foreign Key association. The target node key is contained in a specialized source node. This association determines the target node key contained in the specialized source node. Cross-BO associations: The target node of a Cross-BO-Association is located on another BO then the source node. Composition to Delegated Node: The composition to the delegated node is a special composition. BOPF uses Association Binding in order to resolve associations. This means no implementation is needed when Association Binding is used. During the binding you maintain those attributes which need to be evaluated in order to identify the target node keys. The following association types support Association Binding: Composite, Association to parent, Association to root, Specializations, Reverse Specializations, Foreign Key Associations, Reverse Foreign Key Associations, Cross-BO-Assoications. Each association has a cardinality. BOPF supports the following cardinalities [1:0..1], [1:1], [1:0..n] and [1:1..n]. BOPF does not checked automatically whether a node meets the cardinality constraints maintained in BOPF. The BO implementation has to implement this 43

check. However, for mandatory child nodes cardinalities: [1:1] or [1:1..n] you can reuse the library validation /BOPF/CL_LIB_V_MANDATORY_NODES (out of the BOPF library). More informations about associations can be found in the following document: https://wiki.wdf.sap.corp/wiki/download/attachments/223184988/How+to+implement+a+BO PF+Business+Object+in+the+Business+Suite.doc?version=1

10.1. Association to a Delegated node


BOPF distinguishes between Business Objects and so called Dependent Object (DO). A Dependent Object is something different than a Business Object. It has its own model but it can only be used by embedding it into a Business Object. You cant instantiate a Dependent Object outside of a Business Object. A couple of reusable Dependent Objects are available in software component BS_FND: Text Collection, Attachment Folder and Address. When you embed a Dependent Object into a Business Object (=Host Business Object) the Dependent Objects model gets part of the Business Objects model. Thus the Business Object consumer accesses the nodes of the Dependent Object through the hosting Business Object. However, BOPF only merges the model of the Dependent Object into the model of the Business Object at runtime. At design time in the BOPF Configuration UI the models are not merged. This process is called the Blackbox Delegation, that is, the model information for the Dependent Objects are only known at runtime and not during design time of the host object. In order to embed a Dependent Object into a Business Object you have to create a Delegated Node in the Business Object. During runtime, BOPF replaces the Delegated Node with the complete subset of the Dependent Objects. At runtime, BOPF delegates the calls to the Dependent Objects node to the Dependent Object. In this tutorial you will embed the Text Collection Dependent Object into the Customer.

10.2. Creating Association to Dependent Object


Within this section you will embed the Dependent Object /BOBF/TEXT_COLLECTION into you Customer BO. Thus open your Customer BO in BOPF and select the root node in the Business Object Detail Browser. From the context menu select the entry as shown in the following figure.

44

This command will create a Delegated Node directly underneath the root node. In the details screen for the Delegated Node maintain the following fields: Node Name: Names of the Delegated Node. Use the name Note. Node Prefix: The node prefix is used by BOPF at runtime in order to identify the Dependent Object which is called by a consumer. Example: The Collection used here could additionally be embedded underneath the Bank Details node. Lets assume this for a while. When you access the embedded Text Collection via the BOPF APIs you need to tell BOPF which embedded Text Collection you want to access the one underneath the Root node or the one underneath the Bank Details node. You use the Delegated Node to provide BOPF this information. Thus both embeddings of the Text Collection need to have a Node Prefix, to be more precise a different Node Prefix. Description: Maintain Customer note Referenced Business Object: Select /BOBF/TEXT_COLLECTION When you create the Delegated Node as described above BOPF automatically creates the required association to the root node of the Dependent Object. This is possible since the Text Collection Dependent Object supports a standard linkage to a hosting Business Object. The standard linkage is supported for each Dependent Object that fulfills the following requirement: The embedded Dependent Object must have an alternative key on its root node that uses /BOBF/S_LIB_K_DELEGATION as DATA_TYPE and /BOBF/T_LIB_K_DELEGATION as DATA_TABLE_TYPE. Furthermore this alternative key must be set to "Not-unique" to enable one-to-many usages of it. Further details about the delegation concept can be found here: https://wiki.wdf.sap.corp/wiki/display/BOPF/BS+BOPF+FAQ+and+Features#BSBOPFFAQa ndFeatures-Delegation Note: Dont forget to regenerate the BOPF constant interface every time when you add or delete something in the BO. Afterwards you can test the embedded Dependent Object in the Test Tool. For this purpose open the Test Tool (F8) for the Customer and create a new customer or select an existing one. Navigate to node Root Note and press the Create Button. This will create the root node of 45

the Text Collection (you dont have to maintain anything here). Subsequently navigate to the content node and maintain a text.

11.

Testing the Business Object

There are two methods of testing the Business Object in the BOPF 1. Using the test tool 2. Using reports You can test the Business Object using the test tool by pressing F8 in the Business Object Configuration UI by which a separate SAP GUI window is opened showing the test tool (transaction /BOBF/TEST_UI). This method was used several time trough out the tutorial. The other method is using a manually written report. The report accesses the Business Object via the Service Manager and the Transaction Manager. They provide the APIs you need to access a Business Object from any consumer to trigger queries, to retrieve data, to modify data and to execute actions. By triggering these operations, the determinations created in the design time will get executed. The first report performs a query on the Customer Root node and retrieves the Bank Details for each Root node in the result set.
* Data declaration DATA: lo_customer lt_root_key lt_root lt_bank_detail

TYPE TYPE TYPE TYPE

REF TO /bobf/if_tra_service_manager, /bobf/t_frw_key, zmy_t_cust_root, zmy_t_cust_bank_details.

* Get Service Manager for Customer BO * - use the constant interface maintained in the BO lo_customer = /bobf/cl_tra_serv_mgr_factory=>get_service_manager( iv_bo_key = zif_cust_zmy_customer_c=>sc_bo_key ). * Trigger the query on the root node lo_customer->query( EXPORTING iv_query_key = zif_cust_zmy_customer_c=>sc_query-rootselect_by_elements iv_fill_data = abap_true IMPORTING et_key = lt_root_key et_data = lt_root ). * Retrieve Bank Details node belonging to the queried root nodes lo_customer->retrieve_by_association( EXPORTING iv_node_key = zif_cust_zmy_customer_c=>sc_node-root iv_association = zif_cust_zmy_customer_c=>sc_association-rootbank_details it_key = lt_root_key iv_fill_data = abap_true IMPORTING et_data = lt_bank_detail ).

46

The next report creates a Customer Root Node.


* data declaration DATA: lo_transaction_mgr lo_customer lt_root ls_root lr_root lt_mod ls_mod

TYPE TYPE TYPE TYPE TYPE TYPE TYPE

REF TO /bobf/if_tra_transaction_mgr, REF TO /bobf/if_tra_service_manager, zmy_t_cust_root, zmy_s_cust_root, REF TO zmy_s_cust_root, /bobf/t_frw_modification, /bobf/s_frw_modification.

* Set customer data ls_root-customer_id = '4711'. ls_root-first_name = 'Max'. ls_root-last_name = 'Mustermann'. GET REFERENCE OF ls_root INTO lr_root. * Fill modification structure ls_mod-key = /bobf/cl_frw_factory=>get_new_key( ). ls_mod-node = zif_cust_zmy_customer_c=>sc_node-root. ls_mod-change_mode = /bobf/if_frw_c=>sc_modify_create. ls_mod-data = lr_root. APPEND ls_mod TO lt_mod. * Get Service Manager for Customer BO * - use the constant interface maintained in the BO lo_customer = /bobf/cl_tra_serv_mgr_factory=>get_service_manager( iv_bo_key = zif_cust_zmy_customer_c=>sc_bo_key ). * Call the Service Manager to create the customer lo_customer->modify( EXPORTING it_modification = lt_mod ). * Get the Transaction Manager to save the changes lo_transaction_mgr = /bobf/cl_tra_trans_mgr_factory=>get_transaction_manage r( ). * Save the changes lo_transaction_mgr->save( ).

The last report calls the action LOCK_BANK_ACCOUNT on all Bank Detail nodes belonging to queried root nodes.
* Data declaration DATA: lo_customer lt_root_key lt_bank_detail_key

TYPE REF TO /bobf/if_tra_service_manager, TYPE /bobf/t_frw_key, TYPE /bobf/t_frw_key.

* Get Service Manager for Customer BO * - use the constant interface maintained in the BO lo_customer = /bobf/cl_tra_serv_mgr_factory=>get_service_manager( iv_bo_key = zif_cust_zmy_customer_c=>sc_bo_key ). * Trigger the query on the root node

47

lo_customer->query( EXPORTING iv_query_key = zif_cust_zmy_customer_c=>sc_query-rootselect_by_elements IMPORTING et_key = lt_root_key ). * Retrieve Bank Details node belonging to the queried root nodes lo_customer->retrieve_by_association( EXPORTING iv_node_key = zif_cust_zmy_customer_c=>sc_node-root iv_association = zif_cust_zmy_customer_c=>sc_association-rootbank_details it_key = lt_root_key IMPORTING et_target_key = lt_bank_detail_key ). * Executing the action lo_customer->do_action( EXPORTING iv_act_key = zif_cust_zmy_customer_c=>sc_action-bank_detailslock_bank_account it_key = lt_bank_detail_key ).

48

You might also like