BRFPlus - Custom Expression Types and Action Types PDF
BRFPlus - Custom Expression Types and Action Types PDF
CUSTOMER
Document Version: 1.0 - 15 October 2013
1
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
Christian Auth is a senior developer in the SAP NetWeaver Business Rule Framework plus
project.
He joined SAP in 2002. Before his assignment in BRFplus, he worked in various development
groups in SAP Business ByDesign.
Michael Baer is a senior developer in the SAP NetWeaver Business Rule Framework plus
project.
Michael joined SAP in 2008. In BRFplus, he has been working on various back-end topics.
Piyush Deora is a senior developer in SAP Netweaver Business Rule Framework plus project.
Piyush joined SAP in 2008. He has been working on various user interface and third party
integration topics.
2013-07-29
2
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
Table of Contents
1 Introduction ........................................................................................................................................... 6
1.1 Overview ................................................................................................................................................. 6
1.2 Expression Types and Action Types ...................................................................................................... 6
2 Specification/Design .......................................................................................................................... 10
3 Database Layout ................................................................................................................................. 12
4 Transport Objects ............................................................................................................................... 17
5 Interface Creation ............................................................................................................................... 21
6 Class Creation ..................................................................................................................................... 26
7 New Methods ....................................................................................................................................... 30
7.1 LOAD_BUFFER_DB ............................................................................................................................. 30
7.2 LOAD_BUFFER .................................................................................................................................... 32
7.3 SET_BUFFER....................................................................................................................................... 33
7.4 SAVE_BUFFER_DB ............................................................................................................................. 33
7.5 Method in Action Type or Expression Type Specific Interfaces ........................................................... 34
7.5.1 IF_FDT_ACTN_EMAIL=>GET_BODY ............................................................................................ 34
7.5.2 IF_FDT_ACTN_EMAIL=>GET_RECIPIENTS................................................................................. 35
7.5.3 IF_FDT_ACTN_EMAIL=>GET_PARAMETERS ............................................................................. 35
7.5.4 IF_FDT_ACTN_EMAIL=>GET_SUBJECT ...................................................................................... 35
7.5.5 IF_FDT_ACTN_EMAIL=>SET_BODY ............................................................................................ 35
7.5.6 IF_FDT_ACTN_EMAIL=>SET_RECIPIENTS ................................................................................. 36
7.5.7 IF_FDT_ACTN_EMAIL=>SET_PARAMETERS .............................................................................. 36
7.5.8 IF_FDT_ACTN_EMAIL=>SET_SUBJECT ...................................................................................... 37
8 Redefined Methods ............................................................................................................................. 39
8.1 Class CL_FDT_MAINTENANCE .......................................................................................................... 39
8.1.1 DELETE_FROM_DB ....................................................................................................................... 39
8.1.2 CHECK ............................................................................................................................................ 39
8.1.3 COPY ............................................................................................................................................... 39
8.1.4 RESTORE_BUFFER ....................................................................................................................... 40
8.1.5 SAVE_WITH_VERSION .................................................................................................................. 40
8.1.6 TRANSPORT ................................................................................................................................... 41
8.1.7 GET_CHANGE_DETAILS ............................................................................................................... 42
8.2 Interface IF_FDT_EXPRESSION ......................................................................................................... 43
8.2.1 GET_USED_EXPRESSIONS.......................................................................................................... 44
8.2.2 GET_DSM_AVAILABILITY .............................................................................................................. 45
8.2.3 GET_CONTEXT_DATA_OBJECTS ................................................................................................ 45
8.3 Interface IF_FDT_ADMIN_DATA ......................................................................................................... 46
8.3.1 TO_STRING .................................................................................................................................... 46
8.4 Interface IF_FDT_DATA_EXCHANGE_INTERNAL ............................................................................. 47
9 Check Methods ................................................................................................................................... 48
3
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
4
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
5
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
1 Introduction
1.1 Overview
Purpose
This guide applies to SAP NetWeaver Decision Service Management (any release) or SAP NetWeaver
Business Rule Framework plus (BRFplus) shipped with SAP NetWeaver 7.0 Enhancement Package 3 or
SAP NetWeaver 7.3 Enhancement Package 1 or higher. This is a technical document for developers and
consultants who seek to enhance the capabilities of BRFplus.
Abstract
The guide uses an example of an action type for sending an email to illustrate how to create a custom action
type or expression type. The example covers all aspects such as specification/design, database table
creation, code generation, and user interface. After reading this guide, you should be able to create custom
action types and expression types.
Caution
SAP delivers the content of this guide on the SAP Community Network (SCN) for use with SAP
NetWeaver Decision Service Management or Business Rule Framework plus.
SAP does not provide support for customers using this content to develop their own action
types and expression types; all risk is assumed by the customer. SAP is not liable for
consequences of or damages resulting from the customer’s use of the information contained in
this document.
Expression Types
Expression types define the computational power of BRFplus. Each expression type is a self-contained
computational unit with a well-defined logic. In general, it uses input (context data objects or nested
expressions) to calculate, determine, or derive output (result). Expression types define the ABAP object
class and the ABAP object interface, as well as the user interface for expressions. An expression is
considered an instance of an expression type behaving in accordance with to the expression type's logic.
Expressions form the building blocks of rules in BRFplus. An expression is assigned to a function; whenever
the function is processed, the expression and its nested expressions are evaluated. Expressions can be
used in rulesets. Rulesets contain rules that subscribe to function processing (publish-subscribe). When
functions are processed, registered rules/expressions are evaluated and actions are performed.
6
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
Action Types
Action types define the interactive part of BRFplus. They are a special expression types with no output
(except of the ID of the action performed). However, they have side effects. Instead of the output they
perform the action defined in the logic of the action type. Each action type can have an arbitrary number of
follow up actions to define an action chain. Similar to expressions, actions can use nested expressions and
context data as input. Usually, action types are more application-dependent than expression types; therefore
only a few action types are provided in the standard. Corresponding to the available expression types,
additional action types can be created.
The following diagram illustrates the class and interface hierarchy used for action types and expression
types.
It shows that action type classes are sub classes of the generic action type class CL_FDT_ACTION. Same
as with expression types that are sub classes to the generic expression type class CL_FDT_EXPRESSION.
Finally, action types are a special category of expression types. This becomes obvious in the class and
interface diagram as CL_FDT_ACTION inherits from CL_FDT_EXPRESSION same as IF_FDT_ACTION
includes IF_FDT_EXPRESSION. CL_FDT_MAINTENANCE with its interfaces IF_FDT_TRANSACTION and
IF_FDT_ADMIN_DATA ensures that all action types and expression types provide a consistent and unique
set of methods and attributes.
7
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
8
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
Although BRFplus provides a set of action types and expression types such as Decision Table, Formula,
Message Log, there are good reasons to develop your own action types or expression types.
User interface simplification
Generic BRFplus action types and expression types may provide too many features making the
UI more complex in specific use cases.
The process of creating expression types and action types comprises the following steps:
Specification/Design
Database Layout
Transport Objects
Interface Creation
Class Creation
New Methods
Redefined Methods
Check Methods
Process Methods
Methods for Code Generation
Methods for Lean Trace Display
Data Exchange
Creation of the Action Type or Expression Type as an Object in BRFplus
Testing the Action Type or Expression Type
Creation of the User Interface
Differences between action types and expression types are illustrated in the text.
Note
Look at the code and the database tables of BRFplus standard action types and expression
types.
Action type classes implement IF_FDT_ACTION, while expression type classes implement
IF_FDT_EXPRESSION.
9
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
2 Specification/Design
The first step is to define the capabilities of the new action type or expression type. What is it supposed to
do? How should the user interface look like? What parameters should be dynamic? This question is
important for the database layout. Dynamic parameters enable you to reference an expression or context
data object that returns the value to be used. In this case the action type or expression type may be more
complex to use and develop.
The example custom action type in this document is the email action type. With this action type, it is possible
to create email actions. An email is an action that sends an email. It includes the following input fields:
Recipient(s)
Subject
Body
Recipient parameters
Message parameters
&1& is a placeholder for a dynamic value. An expression or context data object may be nested to enrich the
message with a value from the rules processing.
10
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
Note
The configuration of an application server and prerequisites for sending emails are described in
SAP Note 455140.
11
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
3 Database Layout
You must create database tables in order to save the attributes of the action type or expression type. The
database tables follow strict conventions to benefit automatically from features BRFplus provides, such as
transport or version management. Look at the tables starting with FDT_ACTN for action types or FDT_EXPR
for expression types to see the database tables of the BRFplus standard action types and expression types.
Procedure
1. A good example for our email action type is database table, FDT_ACTN_1010:
Structure FDT_INC_C_KEY_0002 is used for the key. This is a generic key structure used by all
customizing and local action and expression tables. It includes the object ID and a version field. You
can use it for the new email action table. When there is no additional key needed, create a structure
for the attributes and include it in the new table. It is a good idea to use the same abbreviation in the
include and in the table name, such as ACTN_1010 in the previous example. If additional key fields
are needed, a new include for these key fields is created and added to the table.
2. An example is database table, FDT_ACTN_1110:
Also note that the Group field is used. This group information is not used currently but may be used
in the future. You maintain it as illustrated in the example.
3. Our new include, FDT_INC_ACTN_6000_DATA, for the attributes:
12
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
13
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
5. For your tables, use another name, but not FDT_EXPR* or FDT_ACTN* which is reserved for
objects in the BRFplus standard.
Define it as a customizing table. BRFplus supports customizing objects with customizing database
tables and other objects.
Note
The naming conventions for database tables as given in the previous table are mandatory and
must be observed. Some internal mechanisms of BRFplus rely on this naming convention. Any
deviations from the given naming convention results in errors, and the custom expression type
cannot be integrated into the BRFplus framework.
Create a table for each object category with BCF being optional.
14
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
6. BCF stands for Business Content Framework. This is a tool for shipping content in SAP Business
ByDesign. If you have not heard of BCF so far or had to work with it, you probably do not need to
create a table for this object category.
Since customizing and master data are client-dependent, you must include the client in the key. For
the other object categories, create client independent-tables. You replace the key include
FDT_INC_C_KEY_0002 with FDT_INC_KEY_0002:
15
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
Technical settings from BRFplus tables should be analyzed when creating custom action types and
expression types, especially with respect to buffering configuration.
16
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
4 Transport Objects
Customizing, system and BCF table content can be transported. Therefore you need to assign the database
table to transport objects. For the BRFplus standard tables, the following standard transport objects are
used:
Customizing FDT0000
System FDT0001
BCF (optional) FDT0002
If you defined tables for your custom action type or expression type, you must create new transport objects
and assign them to the customer action type or expression type definition.
An entry for BCF is optional – it applies only to Business Content Framework.
You can use transaction SOBJ to see the definition of the standard BRFplus transport objects and all
database tables assigned to it.
Note
There are three standard transport objects. Click Position… and enter FDT to find the BRFplus
standard transport objects. Double-click on the name of a transport object to see how it is
defined. Select the line and click Piece List to see all tables assigned to the transport object.
17
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
Guidelines
You must define your custom transport objects in a similar way as the standard transport objects with the
help of transaction SOBJ. The following guidelines apply to the definition of your custom transport objects.
You only can reuse standard transport objects in custom action types or expression types when the
new action type or expression type is a redefinition of an existing action type or expression type and
does not include new tables.
18
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
Assign only the new tables for your custom action type or expression type to your transport objects.
You must not assign tables shipped by the BRFplus tool to your transport objects.
Use only one transport object per action type or expression type.
Like the standard transport objects, the new custom transport objects need to be type T.
The definition of a primary table in SOBJ is not mandatory for your custom transport objects. So the
setting of the primary table can be performed as follows:
If there is a database table that contains one entry for each ID stored in your
set of tables, this table should be marked as the primary table. However, this is
for information purposes only. The information is not needed within the
transport environment.
Such a table will exist, when you use your transport object for one expression
type or action type. Assume you have a header and an item table for this
expression type; the header table should be the primary table.
If there is no such table, you do not need to define a primary table.
The standard BRFplus “before export” and “after import” methods must be used in the custom
transport objects.
For C tables:
AFTER_IMP FDT_AFTER_IMPORT_C Cross Object = X
BEFORE_EXP FDT_BEFORE_EXPORT_C Cross Object = X
ZDMPRELOCK FDT_PRELOCK Cross Object = ‘ ‘
Starting with release SAP_BASIS 7.40 you also need to apply the following settings in the AIM
Details section, which can be reached from the method definition area in transaction SOBJ.
Define the corresponding BRFplus transport object as “Reference to
Other AIM”.
19
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
You assign the transport objects that have been defined in transaction SOBJ to the new action
type and expression type under Transport Objects using transaction BRFplus.
20
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
5 Interface Creation
You must create an ABAP objects interface for the specific attributes of the action type or expression type.
Action type interfaces need to include IF_FDT_ACTION.
Expression type interfaces need to include IF_FDT_EXPRESSION.
The inclusion of these interfaces will introduce many methods to the new action type or expression type. In
the example of the email action the prefix IF_FDT_ACTN is used, which should not be used for custom
action types. Instead you must use a special customer namespace (for example, /CUS/IF_FDT_ACTN*) or
the local namespace (for example, ZIF_FDT_ACTN*).
Note
Look at the comprehensive interfaces IF_FDT_ACTION and IF_FDT_EXPRESSION to find
examples from other action types and expression types.
Procedure
21
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
3. We recommend you to create some types in the interface. These types are found easily and are
decoupled from the database.
TYPES:
BEGIN OF s_parameter,
POSITION TYPE n LENGTH 1,
parameter_id TYPE if_fdt_types=>id,
END OF s_parameter .
TYPES:
ts_parameter TYPE SORTED TABLE OF s_parameter WITH UNIQUE KEY position .
TYPES BODY TYPE FDT_ACTN_6000-BODY .
TYPES SUBJECT TYPE FDT_ACTN_6000-SUBJECT .
TYPES RECIPIENT TYPE FDT_ACTN_6000-RECIPIENTS .
TYPES:
t_recipient TYPE STANDARD TABLE OF recipient WITH NON-UNIQUE KEY table_line .
4. Create SET and GET methods for the expression type or action type specific attributes. You may
need to create additional methods in accordance with the action type or expression type involved.
22
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
5. To support versioning of the message properties (look at the database layout), you need to offer an
optional timestamp as an importing parameter for the GET methods.
If an attribute should be returned it may be returned for the last (current) version. This is the case
when no timestamp is supplied. It may be returned for a specific version when a timestamp is
supplied. Then the correct version for the timestamp will be determined and is used for the database
read. The timestamp may not find a version. In this case a CX_FDT_INPUT exception should be
returned.
Interface section of the GET methods for the Email action type:
METHODS get_body
IMPORTING
!iv_timestamp TYPE if_fdt_types=>timestamp OPTIONAL
RETURNING
value(rv_body) TYPE body
RAISING
cx_fdt_input .
METHODS get_parameters
IMPORTING
!iv_timestamp TYPE if_fdt_types=>timestamp OPTIONAL
EXPORTING
!ets_message_parameter TYPE ts_parameter
!ets_recipient_parameter TYPE ts_parameter
RAISING
cx_fdt_input .
METHODS get_recipients
IMPORTING
!iv_timestamp TYPE if_fdt_types=>timestamp OPTIONAL
RETURNING
value(rt_recipient) TYPE t_recipient
RAISING
cx_fdt_input .
METHODS get_subject
23
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
IMPORTING
!iv_timestamp TYPE if_fdt_types=>timestamp OPTIONAL
RETURNING
value(rv_subject) TYPE subject
RAISING
cx_fdt_input .
Interface section of the SET methods for the Email action type:
METHODS set_body
IMPORTING
!iv_body TYPE body
RAISING
cx_fdt_input .
METHODS set_parameters
IMPORTING
!its_message_parameter TYPE ts_parameter OPTIONAL
!its_recipient_parameter TYPE ts_parameter OPTIONAL
PREFERRED PARAMETER its_recipient_parameter
RAISING
cx_fdt_input .
METHODS set_recipients
IMPORTING
!it_recipient TYPE t_recipient
RAISING
cx_fdt_input .
METHODS set_subject
IMPORTING
!iv_subject TYPE subject
RAISING
cx_fdt_input .
Note
In the code examples, the following naming conventions are used.
o R = Returning
o E = Exporting
o I = Importing
o RT = Returning table
o RS = Returning structure
o IF = Interface
o CL = Class
6. Create several aliases (that will be used in the following code or even by generic BRFplus methods).
24
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
IF_FDT_ADMIN_DATA~MV_CUSTOMIZING_OBJECT MV_CUSTOMIZING_OBJECT
IF_FDT_ADMIN_DATA~MV_ID MV_ID
IF_FDT_ADMIN_DATA~MV_LOCAL_OBJECT MV_LOCAL_OBJECT
IF_FDT_ADMIN_DATA~MV_MASTERDATA_OBJECT MV_MASTERDATA_OBJECT
IF_FDT_ADMIN_DATA~MV_OBJECT_TYPE MV_OBJECT_TYPE
IF_FDT_ADMIN_DATA~MV_SYSTEM_OBJECT MV_SYSTEM_OBJECT
IF_FDT_EXPRESSION~MV_ACTION MV_ACTION
IF_FDT_EXPRESSION~MV_EXPRESSION_TYPE_ID MV_EXPRESSION_TYPE_ID
IF_FDT_EXPRESSION~MV_RULE MV_RULE
In the example of the email action type, you do not need any attributes at this point. For other action
type or expression types, attributes may be used.
25
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
6 Class Creation
You must create an ABAP objects class for the action type or expression type.
Action type classes need to inherit from CL_FDT_ACTION.
Expression type classes need to inherit from CL_FDT_EXPRESSION.
Inheritance ensures that many features do not need to be implemented manually. In the example of the
email action, the prefix, CL_FDT_ACTN, must not be used for custom action types. Instead a special
customer namespace (for example, /CUS/CL_FDT_ACTN*) or the local namespace (for example,
ZCL_FDT_ACTN*) should be used.
Note
Look at the classes inheriting from CL_FDT_ACTION and CL_FDT_EXPRESSION to find
examples from other action types and expression types.
Procedure
1. Include a forward declaration for IF_FDT_TYPES. IF_FDT_TYPES contains many type definitions
you can reuse in your types, signature and code.
26
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
TYPES:
BEGIN OF s_buffer,
t_recipient TYPE if_fdt_actn_email=>t_recipient,
subject TYPE if_fdt_actn_email=>subject,
body TYPE if_fdt_actn_email=>body,
ts_message_parameter TYPE if_fdt_actn_email=>ts_parameter,
ts_rec_parameter TYPE if_fdt_actn_email=>ts_parameter,
END OF s_buffer.
Note
You may need to add a forward declaration to the interface as shown in the example. You can
do this in the section for forward declarations in the class properties.
27
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
Some methods and attributes need to be provided to follow a specific implementation pattern that
makes use of many concepts in BRFplus. Big parts of the code for the implementation can be copied
and are provided with the following pages of this document.
4. Create the following methods (private section):
METHODS load_buffer
IMPORTING
!iv_timestamp TYPE if_fdt_types=>timestamp OPTIONAL
!iv_version TYPE if_fdt_types=>version OPTIONAL
PREFERRED PARAMETER iv_version
RETURNING
value(rs_buffer) TYPE s_buffer
RAISING
cx_fdt_input .
METHODS load_buffer_db
IMPORTING
!iv_version TYPE if_fdt_types=>version OPTIONAL
RETURNING
value(rs_buffer) TYPE s_buffer .
METHODS save_buffer_db .
METHODS set_buffer
IMPORTING
!is_buffer TYPE s_buffer .
Note
You can define a preferred parameter in the section directly or you navigate to the parameter
on the method tab. Place your cursor on the parameter to be switched to preferred. Then press
the detail view button and check the preferred field in the upcoming dialog.
In the last entry (GC_ACTN_6000), the constant (FDT_ACTN_6000) must be replaced by the specific
database table name of the action type or expression type. Other action types and expression types
have more constants defined. For each database table, a constant is necessary. It is important to use
the customizing table name (not system or master data) for the constant value.
28
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
Note
When you look at the standard action types and expression types, you find constants for the
database tables in the class. You can find which tables belong to a specific action type or
expression type.
These macros will be used in many methods of nearly all action and expression types. These
includes are currently not in the package interface. Therefore, you may need to copy the macros that
are needed by you directly into the macro section of your class.
29
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
7 New Methods
This chapter deals with the implementation of the new methods you created. All the methods follow specific
patterns that have been applied to all action types and expression types provided in the BRFplus standard.
We strongly recommend you to follow these patterns; by doing so, you automatically benefit from many
features. Also, it can help when you compare your code with existing and similar classes.
7.1 LOAD_BUFFER_DB
The purpose of the method is to load the object data from the database into the object buffer (returning
parameter RS_BUFFER). Not all data are loaded; only the data for the specified version (IV_VERSION) or
the latest version, which is the working version. The method makes use of a helper object
(IF_FDT_PERSISTENCE) that is responsible for reading data
Of the correction object ID
In the correct version
In the correct database table
All of the above works when the patterns are applied. The method supports a buffering mechanism so it may
return data from the database buffer (MS_BUFFER_DB). For newly created action and expression types it is
good practice to copy the method from an existing class and adjust with the correct data structure and
constants for database table names.
No data from other tables for texts, documentation, name have to be read. They will be read by super
classes. In this class, the focus is on the application or expression type specific attributes. That is true for this
method and for all methods of the class.
DEFINE db_to_buffer_format.
END-OF-DEFINITION.
For each database table from which you wish to read data, you create a variable. When the data are flat,
create a structure. When data are deep, create a table. For the latter case, look at other classes to reference
the pattern.
lo_persistence = get_persistence( ).
lo_persistence->get_versions(
IMPORTING ev_last_db_version = lv_last_db_version ).
30
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
IF iv_version IS SUPPLIED.
lv_version = iv_version.
ELSE.
lv_version = lv_last_db_version.
ENDIF.
This part deals with initialization and buffer management. It can be copied without any modification.
* FDT_ACTN_6000
lo_persistence->read_single( EXPORTING iv_version = lv_version
iv_tabname = gc_actn_6000
IMPORTING es_value = ls_actn_6000 ).
In this part we perform a read of a single record from our database table. Use the constant we have created
for the database table. LO_PERSISTENCE will ensure the right database table is used for reading
(customizing, system) and the select is done with the correction version and identifier. When the data has
been read, it is moved into our buffer structure. In the example, a conversion of the recipients list from the
database format to buffer format is done. This part depends on the specific attributes of the action or
expression type. Many action and expression types read data from more than one class. Some set default
values in case there is no value in DB.
The rest of the method can be overtaken without any change. This part finalizes the buffer management.
31
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
7.2 LOAD_BUFFER
The purpose of this method is to return the correct buffer information in accordance with the version or
timestamp provided. Data may be returned from:
The object buffer MS_BUFFER
The database buffer (see LOAD_BUFFER_DB) or
The database (see LOAD_BUFFER_DB)
The code of the method is always the same. There is no action type or expression type specific aspect.
For the email action type, copy the following code:
32
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
ENDIF.
7.3 SET_BUFFER
The purpose of the method is to copy data to the object buffer.
For our example, copy the code:
ms_buffer = is_buffer.
7.4 SAVE_BUFFER_DB
The purpose of the method is to write data to the database. It corresponds to LOAD_BUFFER_DB and
follows similar ideas by using interface IF_FDT_PERSISTENCE to ensure writing data
For the correct identifier
In the correction version
To the correct database table
The best approach for this method is to simply copy from a good example and adjust in accordance with the
specific attributes of the action type or expression type.
For the email action type, create the following code:
For each database table a structure or an internal table needs to be created. Internal tables are needed in
case of additional key fields; there may be many entries in the database for one identifier version
combination. Look at other classes and patterns applied if you need an internal table.
IF_FDT_PERSISTENCE offers additional features to divide the data into lines written into the database and
lines that need to be deleted from database.
lo_persistence = get_persistence( ).
* FDT_ACTN_6000
ls_actn_6000-body = ms_buffer-body.
33
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
ls_actn_6000-subject = ms_buffer-subject.
LOOP AT ms_buffer-ts_message_parameter INTO ls_parameter.
CASE ls_parameter-position.
WHEN 1.
ls_actn_6000-msg_param_1 = ls_parameter-parameter_id.
WHEN 2.
ls_actn_6000-msg_param_2 = ls_parameter-parameter_id.
WHEN 3.
ls_actn_6000-msg_param_3 = ls_parameter-parameter_id.
WHEN 4.
ls_actn_6000-msg_param_4 = ls_parameter-parameter_id.
WHEN 5.
ls_actn_6000-msg_param_5 = ls_parameter-parameter_id.
WHEN 6.
ls_actn_6000-msg_param_6 = ls_parameter-parameter_id.
WHEN 7.
ls_actn_6000-msg_param_7 = ls_parameter-parameter_id.
WHEN 8.
ls_actn_6000-msg_param_8 = ls_parameter-parameter_id.
ENDCASE.
ENDLOOP.
LOOP AT ms_buffer-ts_rec_parameter INTO ls_parameter.
CASE ls_parameter-position.
WHEN 1.
ls_actn_6000-rec_param_1 = ls_parameter-parameter_id.
WHEN 2.
ls_actn_6000-rec_param_2 = ls_parameter-parameter_id.
WHEN 3.
ls_actn_6000-rec_param_3 = ls_parameter-parameter_id.
WHEN 4.
ls_actn_6000-rec_param_4 = ls_parameter-parameter_id.
ENDCASE.
ENDLOOP.
This part deals with data conversion from buffer to database structure. Subsequently, data are written into
the database.
ms_buffer_db = ms_buffer.
mv_ms_buffer_loaded = abap_true.
mv_ms_buffer_db_loaded = abap_true.
The remainder follows a generic pattern and you can copy it without modification.
7.5.1 IF_FDT_ACTN_EMAIL=>GET_BODY
This is a simple GET method for the email body. All GET methods follow the same pattern.
34
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
IF iv_timestamp IS SUPPLIED.
ls_buffer = load_buffer( iv_timestamp = iv_timestamp ).
ELSE.
ls_buffer = load_buffer( ).
ENDIF.
rv_body = ls_buffer-body.
7.5.2 IF_FDT_ACTN_EMAIL=>GET_RECIPIENTS
IF iv_timestamp IS SUPPLIED.
ls_buffer = load_buffer( iv_timestamp = iv_timestamp ).
ELSE.
ls_buffer = load_buffer( ).
ENDIF.
rt_recipient = ls_buffer-t_recipient.
7.5.3 IF_FDT_ACTN_EMAIL=>GET_PARAMETERS
IF iv_timestamp IS SUPPLIED.
ls_buffer = load_buffer( iv_timestamp = iv_timestamp ).
ELSE.
ls_buffer = load_buffer( ).
ENDIF.
ets_message_parameter = ls_buffer-ts_message_parameter.
ets_recipient_parameter = ls_buffer-ts_rec_parameter.
7.5.4 IF_FDT_ACTN_EMAIL=>GET_SUBJECT
IF iv_timestamp IS SUPPLIED.
ls_buffer = load_buffer( iv_timestamp = iv_timestamp ).
ELSE.
ls_buffer = load_buffer( ).
ENDIF.
rv_subject = ls_buffer-subject.
7.5.5 IF_FDT_ACTN_EMAIL=>SET_BODY
This is a simple SET method for the email body. All SET methods follow the same pattern.
1. The current buffer values are read.
35
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
ls_buffer = load_buffer( ).
CHECK ls_buffer-body NE iv_body. ">>>
ls_buffer-body = iv_body.
set_buffer( ls_buffer ).
notify_change( ).
7.5.6 IF_FDT_ACTN_EMAIL=>SET_RECIPIENTS
ls_buffer = load_buffer( ).
CHECK ls_buffer-t_recipient NE it_recipient. ">>>
ls_buffer-t_recipient = lt_recipient.
set_buffer( ls_buffer ).
notify_change( ).
7.5.7 IF_FDT_ACTN_EMAIL=>SET_PARAMETERS
ls_buffer = load_buffer( ).
CHECK ( its_message_parameter IS SUPPLIED AND
its_message_parameter NE ls_buffer-ts_message_parameter ) OR
( its_recipient_parameter IS SUPPLIED AND
its_recipient_parameter NE ls_buffer-ts_rec_parameter ).
IF its_message_parameter IS SUPPLIED.
LOOP AT its_message_parameter INTO ls_parameter.
* ls_parameter-position = sy-tabix.
* INSERT ls_parameter INTO TABLE lts_parameter.
36
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
CLEAR lts_parameter.
IF its_recipient_parameter IS SUPPLIED.
LOOP AT its_recipient_parameter INTO ls_parameter.
ls_parameter-position = sy-tabix.
INSERT ls_parameter INTO TABLE lts_parameter.
" check for valid ID
IF ls_parameter-parameter_id IS NOT INITIAL.
cl_fdt_admin_data=>check_id( EXPORTING iv_id = ls_parameter-parameter_id
IMPORTING ev_id_unknown = lv_unknown ).
IF lv_unknown EQ abap_true.
get_name ls_parameter-parameter_id ls_msg-msgv1.
MESSAGE e320(fdt_expressions) WITH ls_parameter-parameter_id ls_parameter-
position INTO ls_msg-text.
append_message ls_msg lt_msg.
ENDIF.
ENDIF.
ENDLOOP.
ls_buffer-ts_rec_parameter = lts_parameter.
ENDIF.
set_buffer( ls_buffer ).
notify_change( ).
7.5.8 IF_FDT_ACTN_EMAIL=>SET_SUBJECT
ls_buffer = load_buffer( ).
CHECK ls_buffer-subject NE iv_subject. ">>>
ls_buffer-subject = iv_subject.
set_buffer( ls_buffer ).
notify_change( ).
37
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
Note
o SET methods allow also invalid data. Checking data validity takes
place during activation; before activation, invalid data go into the
buffer and DB, which gives freedom when building the content.
o There are some methods that are specific to the custom action and
expression. These are not described in detail; if you are in doubt,
check the system.
38
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
8 Redefined Methods
This chapter deals with the mandatory redefinition of methods.
super->delete_from_db( ).
lo_persistence = get_persistence( ).
lo_persistence->delete( iv_tabname = gc_actn_6000 ).
You only need to use the constant with the database name from which the data are to be deleted. Class
inheritance ensures data from other tables are deleted by super classes.
8.1.2 CHECK
The purpose of this method is to check the object. It is discussed in chapter 9 Check Methods.
8.1.3 COPY
This method copies the buffer of the class. This involves only the attributes added by the class, not the
attributes copied by the super class. The method follows a pattern used by all action types and expression
types in the BRFplus standard.
In our example, the following code is created:
Adapt the class name to create a copy with the correct type:
IV_DEEP enables creation of a deep copy. When the action or expression uses other objects such as
expressions, action, data objects, which are nearly always the case, those objects will be copied in case the
deep flag is set to ABAP_TRUE. In detail, the deep object management works as follows:
Used unnamed objects are copied always
Used named objects in the same application are copied only when IV_DEEP = ABAP_TRUE
39
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
lo_email->set_buffer( ls_buffer ).
ro_copy ?= lo_email.
Using the COPY_ON_REQUEST method, you ensure each object is copied once.
Example
There is an object A using objects B and C. Object B uses object C, too.
Now we copy A to A*. This results in A passing the copy to B and C which results in copies B*
and C*.
However, B also passes the copy to C, which must not result in another copy of C (C**) but in
C*. COPY_ON_REQUEST detects that C was already copied to C* and returns C* instead of
creating another copy.
8.1.4 RESTORE_BUFFER
This method rolls back the object buffer to the database buffer. The method follows a generic pattern and
can be copied without any changes.
super->restore_buffer( iv_buffer_db ).
IF iv_buffer_db EQ abap_true.
CLEAR ms_buffer_db.
mv_ms_buffer_db_loaded = abap_false.
ms_buffer_db = load_buffer_db( ).
ENDIF.
CLEAR ms_buffer.
mv_ms_buffer_loaded = abap_false.
ms_buffer = load_buffer( ).
8.1.5 SAVE_WITH_VERSION
The purpose of the method is to distribute the save information in the layers of the inheritance hierarchy. The
method follows a generic pattern and can be copied without any changes.
40
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
IF iv_transport_request IS SUPPLIED.
super->save_with_version( iv_version = iv_version
iv_last_db_version = iv_last_db_version
iv_transport_request = iv_transport_request ).
ELSE.
super->save_with_version( iv_version = iv_version
iv_last_db_version = iv_last_db_version ).
ENDIF.
* we only need to save the data of this class when there is a change in
* the attributes or when the version needs to be changed
CHECK iv_version NE iv_last_db_version OR ms_buffer NE ms_buffer_db.
save_buffer_db( ).
8.1.6 TRANSPORT
This method writes an object to a transport request. The implementation follows a simple pattern that you
can copy. Services from IF_FDT_PERSISTENCE are used.
Our example contains the following code:
lo_persistence = get_persistence( ).
lo_persistence->transport( iv_transport_request = iv_transport_request
iv_tabname = gc_actn_6000 ).
You only need to use our constant with the database name from which the data is to be transported. Class
inheritance ensures data from other tables are written to transport by super classes.
Note
The following is important with regard to the TRANSPORT method:
You must not create transport piece list entries manually for the table entries of self-
implemented expression types.
Caution
Please review your implementation of the TRANSPORT method before you start transporting
your content.
We recommend that you first use of a transport copies to a test system to ensure your
expression types are implemented so they can be transported without problems. This will avoid
the possibility of broken data being transported to the whole system landscape.
41
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
8.1.7 GET_CHANGE_DETAILS
This method returns information on changes for two given versions or timestamps. Some of the changes are
processing relevant (for example, changed email subject) and some are not processing relevant (for
example, changed action text).
Method Parameters
Parameter Type Purpose
42
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
The code in class CL_FDT_ACTN_EMAIL will help you understand how the method should work. You can
copy and adapt code from there.
Note
You can create an application with versioning switched on by default to test the method for your
custom type and how it works in combination with nested objects.
lt_recipient = if_fdt_actn_email~get_recipients( ).
lv_subject = if_fdt_actn_email~get_subject( ).
lv_body = if_fdt_actn_email~get_body( ).
if_fdt_actn_email~get_parameters( IMPORTING ets_message_parameter = lts_msg_param
ets_recipient_parameter = lts_rec_param ).
8.2.1 GET_USED_EXPRESSIONS
The purpose of this method is to return all UUIDs of expressions which are used by this object. In the
example of the Email action only the parameters hold UUIDs, which could be data objects or expressions.
So you get those UUIDs and check them for expressions.
IF iv_timestamp IS SUPPLIED.
rts_expression_id = super-
>if_fdt_expression~get_used_expressions( iv_timestamp = iv_timestamp ).
ELSE.
rts_expression_id = super->if_fdt_expression~get_used_expressions( ).
ENDIF.
* ------------------------------------------------------
IF iv_timestamp IS SUPPLIED.
if_fdt_actn_email~get_parameters(
EXPORTING iv_timestamp = iv_timestamp
IMPORTING ets_message_parameter = lts_msg_parameter
ets_recipient_parameter = lts_rec_parameter ).
ELSE.
if_fdt_actn_email~get_parameters(
IMPORTING ets_message_parameter = lts_msg_parameter
ets_recipient_parameter = lts_rec_parameter ).
ENDIF.
LOOP AT lts_msg_parameter INTO ls_parameter WHERE parameter_id IS NOT INITIAL.
CLEAR lv_obj_type.
cl_fdt_admin_data=>check_id( EXPORTING iv_id = ls_parameter-parameter_id
IMPORTING ev_object_type = lv_obj_type ).
44
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
IF lv_obj_type EQ if_fdt_constants=>gc_object_type_expression.
INSERT ls_parameter-parameter_id INTO TABLE rts_expression_id.
ENDIF.
ENDLOOP.
8.2.2 GET_DSM_AVAILABILITY
The purpose of this method is to define the release from which you want to start supporting your own
expression type or action types. Specify the start release you want in the returning parameter.
When you want your defined expression type or action type to be available from SAP_BASIS 7.02, enter 702
in the field for the returning parameter. All managed systems with an SAP NetWeaver release equal to or
greater than 7.02 will support your expression type.
METHOD if_fdt_expression~get_dsm_availability.
rv_start_release = 702.
ENDMETHOD.
Caution
For your defined expression type or action types, you need a working implementation for the
generation mode with no switch to interpretation mode.
You define a start release, and all higher releases must support your expression types or
action types. You cannot define gaps for releases that do not support your defined
expression types or action types.
As owner of your defined expression types or action types you are responsible for ensuring
that the generated code works correctly in the managed system and does not contain syntax
errors.
Note
Relevant for SAP NetWeaver Decision Service Management only.
You must retrieve metadata such as database tables from the managed system, not your local
system.
Review CL_FDT_TYPEDESCR to implement the retrieval of metadata. Focus on the uses of
the class and sub-classes in the standard expression types and action types such as
CL_FDT_ACTN_MESSAGE_LOG.
8.2.3 GET_CONTEXT_DATA_OBJECTS
The purpose of this method is to return all UUIDs of data objects which are used by this object. In the
example of the email action, only the parameters hold UUIDs, which could be data objects or expressions.
45
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
IF iv_timestamp IS SUPPLIED.
rts_object_id = super->if_fdt_expression~get_context_data_objects(
iv_timestamp = iv_timestamp
iv_deep = iv_deep
iv_used = iv_used ).
ELSE.
rts_object_id = super->if_fdt_expression~get_context_data_objects(
iv_deep = iv_deep
iv_used = iv_used ).
ENDIF.
* ------------------------------------------------------
CHECK iv_used = abap_true.
IF iv_timestamp IS SUPPLIED.
if_fdt_actn_email~get_parameters(
EXPORTING iv_timestamp = iv_timestamp
IMPORTING ets_message_parameter = lts_msg_parameter
ets_recipient_parameter = lts_rec_parameter ).
ELSE.
if_fdt_actn_email~get_parameters(
IMPORTING ets_message_parameter = lts_msg_parameter
ets_recipient_parameter = lts_rec_parameter ).
ENDIF.
LOOP AT lts_msg_parameter INTO ls_parameter.
CHECK ls_parameter-parameter_id IS NOT INITIAL.
CLEAR lv_obj_type.
cl_fdt_admin_data=>check_id( EXPORTING iv_id = ls_parameter-parameter_id
IMPORTING ev_object_type = lv_obj_type ).
IF lv_obj_type EQ if_fdt_constants=>gc_object_type_data_object.
INSERT ls_parameter-parameter_id INTO TABLE rts_object_id.
ENDIF.
ENDLOOP.
Mode Description
Brief The result is a brief representation of the object. It does not return additional details such
as the name of the object. This is the default mode.
Complete The result of the method is the complete description of the object with details such as
object name.
If there is no valid information provided, you can return a default string such as “Action Type ...”. Review and
debug the code in other action types and expression types for examples.
Add the following piece of code at the end of the method to truncate the string to the maximum length.
CONDENSE rv_string.
* Truncate the description string length to the max
* length allowed if applicable.
IF iv_max_length LE strlen( rv_string ).
truncate_string( EXPORTING iv_max_length = iv_max_length
CHANGING cv_string = rv_string ).
ENDIF.
8.4 Interface
IF_FDT_DATA_EXCHANGE_INTERNAL
You need to implement two methods:
EXPORT_XML
IMPORT_XML
47
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
9 Check Methods
CHECK
This method is called to check the object. A successful check is required to activate an object. The result of
the method is a list of information, warnings, or error messages.
It is important to understand the meaning of the importing parameter IV_ACTIVATION_CHECK. When set to
ABAP_TRUE the check has to be performed as an activation check; the active versions of the referenced
objects must be included within the check, (for example, a case expression that has a result data object).
The result data object may be numeric in its active version and Boolean in its inactive version, which is the
latest state of the object. To activate the result data object used, it must be Boolean, or an error message is
returned.
Usually, this method is implemented to reuse the specific check methods used in the SET methods. Detailed
checks are performed such as validation of the email addresses supplied or UUIDs used. In this example,
the code of the check method looks as follows:
lt_recipient = if_fdt_actn_email~get_recipients( ).
lv_subject = if_fdt_actn_email~get_subject( ).
lv_body = if_fdt_actn_email~get_body( ).
if_fdt_actn_email~get_parameters( IMPORTING ets_message_parameter = lts_msg_param
ets_recipient_parameter = lts_rec_param ).
49
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
10 Process Methods
PROCESS
This method is the heart of the expression type since it defines its expressiveness, that is, what you can do
with it as an end user.
In BRFplus we have two different modes for processing a service:
1. Interpretation
Interpretation mode is used for test purposes or when generation mode is not available. It is
slower than generation mode, but it works in all cases without preparation.
2. Generation
Generation mode is a performance-optimized way to process the service. A class is generated
that represents the service. The generation can take time, but this can be done beforehand and
the processing is not affected.
The method IF_FDT_EXPRESSION~PROCESS has to be redefined to enable the processing. The following
table describes all parameters available for processing.
Parameter Description
In this method, the definitions of the object for the supplied timestamp (IV_TIMESTAMP) use the given
context (IO_CONTEXT) to produce a result (RO_RESULT). When a trace is requested (IO_TRACE)
execution steps have to be logged in the trace. When the object uses other objects (for example, use of
variables in an email body), those objects can be processes with help of the processor (IO_PRCESSOR).
The PROCESS method in the action type email consists of several steps.
50
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
With help of method GET_VALUE, you can resolve UUIDs used in the definitions of the object. The email
action type, for example, may use variable returned by other expressions or contained in the context.
TRY.
CREATE OBJECT lo_message.
lo_message->set_subject( ls_buffer-subject ).
lv_main_doc = ls_buffer-body.
lo_message->set_main_doc( lv_main_doc ).
LOOP AT ls_buffer-t_recipient ASSIGNING <ls_recipient>.
lo_message->add_recipient( <ls_recipient> ).
IF lv_rec_trace IS NOT INITIAL .
CONCATENATE lv_rec_trace <ls_recipient> INTO lv_rec_trace SEPARATED BY ';'.
ELSE.
MOVE <ls_recipient> TO lv_rec_trace.
ENDIF.
ENDLOOP.
LOOP AT ls_buffer-ts_rec_parameter INTO ls_parameter.
get_value( EXPORTING iv_id = ls_parameter-parameter_id
io_context = io_context
iv_timestamp = iv_timestamp
io_processor = io_processor
IMPORTING er_value = lr_data ).
cl_fdt_expression=>get_type( EXPORTING iv_id = ls_parameter-parameter_id
IMPORTING ev_data_object_type = lo_do_type ).
IF lo_do_type EQ if_fdt_constants=>gc_data_object_type_element.
ASSIGN lr_data->* TO <la_data>.
lv_value = get_string_from_data( <la_data> ).
lt_message = check_recipients( iv_recipient = lv_value ).
IF cl_fdt_services=>contains_eax_message( lt_message ) EQ abap_false.
51
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
lo_message->add_recipient( lv_value ).
IF lv_rec_trace IS NOT INITIAL .
CONCATENATE lv_rec_trace lv_value INTO lv_rec_trace SEPARATED BY ';'.
ELSE.
MOVE lv_value TO lv_rec_trace.
ENDIF.
ELSE.
write_trace_info_1 '222' lv_value lv_id.
ENDIF.
CLEAR lt_message.
ELSE.
ASSIGN lr_data->* TO <lt_data>.
LOOP AT <lt_data> ASSIGNING <lv_value>.
lo_typedescr = cl_abap_typedescr=>describe_by_data( <lv_value> ).
IF lo_typedescr->kind EQ cl_abap_typedescr=>kind_struct.
ASSIGN COMPONENT 1 OF STRUCTURE <lv_value> TO <lv_string>.
ELSEIF lo_typedescr->kind EQ cl_abap_typedescr=>kind_elem.
ASSIGN <lv_value> TO <lv_string>.
ENDIF.
lt_message = check_recipients( iv_recipient = <lv_string> ).
IF cl_fdt_services=>contains_eax_message( lt_message ) EQ abap_false.
lo_message->add_recipient( <lv_string> ).
ELSE.
write_trace_info_1 '222' <lv_string> lv_id.
ENDIF.
CLEAR lt_message.
ENDLOOP.
ENDIF.
ENDLOOP.
"lo_message->set_update_task( abap_true ).
IF cl_fdt_function_gen_process=>gv_action_in_update_task EQ abap_true.
lo_message->set_update_task( abap_true ).
ENDIF.
lo_message->send( ).
" Record Trace with the detail of recipient. <PD>
split_recipient_string(
EXPORTING iv_string = lv_rec_trace
IMPORTING ev_msg_1 = lv_msg_1
ev_msg_2 = lv_msg_2
ev_msg_3 = lv_msg_3
ev_msg_4 = lv_msg_4 ).
Finally, write the result and process the follow up actions. Actions write their UUIDs as a result. In this case
you can copy the following lines. Expressions write values defined with data objects. You may check the
52
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
processing methods of expression type classes such as CL_FDT_CASE or CL_FDT_RANGE to learn more
about this.
53
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
rv_generating = abap_false.
11.2 GENERATE_PROCESS
The generation of an expression (method IF_FDT_EXPRESSION~GENERATE_PROCESS) is only
performed if the method IF_FDT_EXPRESSION~IS_GENERATING returns abap_true. To implement the
generation of an expression, the environment of code generation of BRFplus functions must be understood.
The coding is generated for a complete function. The coding for the complete function [all the used
expressions (except the function call expression) and the assigned rulesets] is included in one
generated class. In a specific time period, where the function and all used objects (including
rulesets) did not change, two generated classes may exist. One class is for processing without lean
trace and one with lean trace. The generation occurs when the function is processed and no
generation is available for the requested timestamp and lean trace usage. (The generation can be
started via tool report).
The generation of a function is started by the BRFplus function object. Each BRFplus object is
responsible for the generation of its own functionality. An object using other objects delegates the
generation of the respective sub-object. During generation of an expression, it is not determined if
the coding is included into the surrounding coding of the parent object or if it will be placed in its own
method. Therefore, the generation of each object has to follow some rules so that each code piece
can coexist with other code pieces in one method. The coding for an entire function is composed by
combining the coding snippets for each used expression into one class (usually into one method). In
this case, you must ensure that the variable names for helper variables are unique for the complete
generated method. To ensure this, the following technique must be used:
To ensure a unique variable name for each generated data, the declaration method
CL_FDT_EXPR_SERVICES=>GEN_GET_NEXT_VARIABLE_NAME is called. This method uses
the input string to find a variable name, which is derived from the name and is unique in the
generated class (if the string was not used before the string is returned, a number is added which
makes the string unique). If the ID of the object is passed for which the helper variable is used, a
check is made to determine whether the object is a constant expression. If it is, a check runs to see if
a variable for the constant was declared before; if it was, this variable name is returned. Variables for
constant expressions are defined as class constants.
At some places a generation manager object is needed. When the method
IF_FDT_EXPRESSION~GENERATE_PROCESS of your expression is called an instance of the
generation manager is present as an importing parameter and you pass it to the desired parameter
list.
If you want to use the lean trace feature your generated coding needs to support this. Respective IF
statements in your coding are necessary to distinguish between the coding generated for processing
with or without the lean trace feature. The generation infrastructure ensures basic information is
added to the trace (such as result) without any expression type or action type specific code. We
recommend avoiding trace-specific code in custom action types and expression types.
54
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
Recommendation
We recommend using the first technique. This is the one used in the current BRFplus code
generation.
The following methods from the BRFplus standard can be used during code generation.
11.2.1 IF_FDT_DATA_OBJECT->GENERATE_CREATE_DATA_REF
This method creates a data statement for a BRFplus data object. It can be used with data objects of type
element, structure or table.
Explanation of the parameters:
Parameter Description
Code Example
lo_mail_body_do->generate_create_data_ref(
EXPORTING iv_variable_name = lv_mail_body_name
iv_timestamp = lv_timestamp
io_generation_mngr = io_generation_mngr
IMPORTING et_source_code = lt_data_def_code ).
APPEND LINES OF lt_data_def_code TO et_source_code.
11.2.2 IF_FDT_DATA_OBJECT=>GENERATE_CONVERT_TO
55
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
This method generates coding to convert the data from one data object to another data object. It can be
used with data objects of type element, structure, or table.
Explanation of the parameters:
Parameter Description
Code Example
lo_tmp_result_do->generate_convert_to(
EXPORTING iv_variable_name_source = lv_tmp_result_name
io_target_data_object = lo_result_do
iv_variable_name_target = lv_result_do_name
iv_timestamp = lv_timestamp
io_generation_mngr = io_generation_mngr
IMPORTING et_source_code = lt_conv_code ).
APPEND LINES OF lt_conv_code TO et_source_code.
11.2.3 CL_FDT_EXPR_SERVICES=>
GENERATE_MOVE_FROM_EXTERNAL
This method generates the coding to move data from an external format (for example, DDIC) to BRFplus
format. The external format can be BRFplus.
Explanation of the parameters:
Parameter Description
56
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
Code Example
Cl_fdt_expr_services=>generate_move_from_external(
EXPORTING iv_dobj_id = lv_dobj_id
iv_source_name = iv_source_do_name
iv_target_name = iv_target_do_name
iv_timestamp = lv_timestamp
IMPORTING et_source_code = lt_move_code ).
APPEND LINES OF lt_move_code TO et_source_code.
11.2.4 CL_FDT_EXPR_SERVICES=>
GENERATE_MOVE_TO_EXTERNAL
This method generates the coding to move data from BRFplus to an external format. The external format can
be BRFplus.
Explanation of the parameters:
Parameter Description
Code Example
Cl_fdt_expr_services=>generate_move_to_external(
EXPORTING iv_dobj_id = lv_dobj_id
iv_source_name = iv_source_do_name
iv_target_name = iv_target_do_name
iv_timestamp = lv_timestamp
IMPORTING et_source_code = lt_move_code ).
APPEND LINES OF lt_move_code TO et_source_code.
57
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
11.2.5 CL_FDT_EXPR_SERVICES=>
GENERATE_GET_CONTEXT_NAME
Code Example
Cl_fdt_expr_services=>generate_get_context_name(
EXPORTING iv_id = lv_recipient_id
IMPORTING ev_name = lv_recipient_name
ev_unknown = lv_unknown ).
11.2.6 CL_FDT_EXPR_SERVICES=>
GEN_GET_NEXT_VARIABLE_NAME
Code Example
Get the variable name for the email body and create the data declaration:
lv_body_name =
Cl_fdt_expr_services=>generate_get_context_name(iv_desired_name = ‘lv_body’ ).
lv_line = ` DATA ` && lv_body_name && ` TYPE string.`.
append lv_line to et_source_code.
58
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
11.2.7 CL_FDT_EXPR_SERVICES=>
GEN_GET_NAME_FOR_GENERATION
This method returns the common name for timestamp / trace object used in generation.
Explanation of the parameters:
Parameter Description
Code Example
lv_trace_name = Cl_fdt_expr_services=>gen_get_Name_for_generation
(iv_symbolic_name = ‘GC_ATTR_NAME_TRACE_OBJ’ ).
lv_line = ` CLEAR ` && lv_trace_name && `->ms_record-value.
append lv_line to et_source_code.
This method returns if the generation takes place with lean trace or without.
Explanation of the parameter:
Parameter Description
Code Example
Ensure generation occurs with the tracing option; clear the record work area:
Cl_fdt_expr_services=>gen_generate_trace(
IMPORTING ev_generate_trace = lv_trace_used )
IF lv_trace_used EQ ABAP_TRUE.
lv_trace_name = Cl_fdt_expr_services=>gen_get_Name_for_generation
(iv_symbolic_name = ‘GC_ATTR_NAME_TRACE_OBJ’ ).
lv_line = ` CLEAR ` && lv_trace_name && `->ms_record-value.
append lv_line to et_source_code.
ENDIF.
59
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
11.2.9 CL_FDT_EXPR_SERVICES=>GENERATE_RANGE_PROCESS
IV_FUNCTION_ID Function ID
IV_EXPRESSION_ID Calling expression ID
IV_VARIABLE_NAME Variable name for the range result (optional)
IV_CREATE_VARIABLE Create a data declaration for the result
IV_TIMESTAMP Generation timestamp
IV_TEST_PARAMETER Test parameter ID
ITS_RANGE Range table
IV_CASE_SENSITIVITY TRUE: Generate case sensitive (optional)
IV_IS_SV_RANGE TRUE: Range is a simple value range (optional)
ET_SOURCE_CODE Generated source code
EV_DEEP_TRACED TRUE: Deep tracing took place
CTS_USED_CONTEXT_ID Table of used context IDs
Code Example
cl_fdt_expr_services=>generate_range_process(
EXPORTING iv_function_id = iv_function_id
iv_expression_id = mv_id
iv_variable_name = lv_cond_ok
iv_create_variable = abap_false
iv_timestamp = lv_timestamp
iv_test_parameter = <ls_cond>-s_param_range-parameter_id
its_range = <ls_cond>-s_param_range-ts_range
iv_is_sv_range = abap_true
IMPORTING et_source_code = lt_condition_code
CHANGING cts_used_context_id = cts_used_context_id ).
APPEND LINES OF lt_condition_code TO et_source_code.
11.2.10 CL_FDT_EXPR_SERVICES=>
GENERATE_SIMPLE_VALUE_PROCESS
This method generates the coding for a direct value usage inside the expression.
60
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
Code Example
cl_fdt_expr_services=>generate_simple_value_process(
EXPORTING iv_variable_name = lv_def_res_name
iv_create_variable = abap_false
is_value = s_default_result_value
iv_timestamp = lv_timestamp
IMPORTING et_source_code = lt_def_res_code ).
APPEND LINES OF lt_def_res_code TO et_source_code.
11.2.11 CL_FDT_EXPRESSION=>GENERATE_GET_VALUE
This method generates the coding for any subexpression or data object used in the expression.
Explanation of the parameters:
Parameter Description
IV_FUNCTION_ID Function ID
IV_ID (Sub)expression or data object ID
IV_VARIABLE_NAME Variable name of result from subexpression OR variable
name for the data object
IV_CREATE_VARIABLE Create a data declaration for the result or the data object
IV_TIMESTAMP Generation timestamp
IO_GENERATION_MNGR Generation manager instance
IV_CALLING_EXPR_ID Expression ID (from the calling expression)
IV_TARGET_DO_ID Target data object (optional, triggers a convert_to)
IV_TARGET_ELEMENT_TYPE Target data object element type (optional)
ET_SOURCE_CODE Generated source code
EV_DIRECT_RESULT_NAME Generated class constant name
EV_DEEP_TRACED TRUE: Expression was deep traced
EV_CONTEXT_OR_CONST TRUE: IV_ID belongs to a constant or to a context ID
61
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
Code Example
11.2.12 CL_FDT_EXPRESSION=>
GENERATE_TRACE_SUB_EXPRESSION
Code Example
IF io_generation_mngr->mv_trace_generation EQ abap_true.
lv_position = <Create a new unique name for this position. For already existing
position names check the attributes of class CL_FDT_TRACE>.
62
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
generate_trace_sub_expression(
EXPORTING iv_position_name = lv_trace_position
iv_result_name = lv_result_name
iv_id = <ID of the Procedure Call Expression>
iv_parent_id = mv_id
iv_with_value = abap_true
IMPORTING et_source_code = lt_trace_code ).
APPEND LINES OF lt_trace_code TO et_source_code.
ev_deep_traced = abap_true.
ENDIF.
Note: lv_result_name is the variable, which stores during code generation the name of the variable, which
contains in the generated code the result of the Procedure Call.
63
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
This chapter deals with some methods you can use to manipulate the appearance of your lean trace records
in the BRFplus Workbench. You do not have to implement these methods. If you don’t, the lean trace
records will be displayed in a standardized way as nodes of an expandible tree by the lean trace Web
Dynpro component, FDT_WD_LEAN_TRACE. This component is included in the Show Trace functionality of
the function in the BRFplus Workbench or in the Lean Trace Tool.
However, if you want to display the lean trace nodes in a specific order or in a structured way, or if you want
to extend the description for a particular node, you may create the following:
CHANGE_TRACE_NODE
CREATE_TRACE_CHILD_NODES
12.1 CHANGE_TRACE_NODE
This method changes the name of the trace node after its default is set. The interface of the method must
contain the following parameters:
Note
You should only change the name of the trace node.
All other fields may be overwritten by the standard methods.
Code Example
METHOD CHANGE_TRACE_NODE.
TRY.
“Change the name of the node
IF cs_node-value_valueref IS BOUND.
ASSIGN cs_node-value_valueref->* TO <lv_bool>.
IF <lv_bool> = abap_true.
MESSAGE i316(fdt_wd_tools) WITH cs_node-name INTO lv_name.
ELSE.
MESSAGE i317(fdt_wd_tools) WITH cs_node-name INTO lv_name.
ENDIF.
cs_node-name = lv_name.
ENDIF.
CATCH cx_sy_assign_error.
"Keep the node name as it is.
ENDTRY.
ENDMETHOD.
12.2 CREATE_TRACE_CHILD_NODES
This method arranges the records traced within your expression in a certain manner.
The following example illustrates how to sort nodes and extend their default names.
Note
To create a node, use IO_LEAN_TRACE_HELPER->create_node(…). It contains all
relevant fields by default.
To nest nodes, create a node and use it as parent node of another node.
To create nodes without a reference to a record, use the CREATE_NODE( ..) method.
To do so, use the IV_NAME attribute instead of IS_RECORD.
Delete all records you have treated in this method from CTS_RECORD.
Code Example
METHOD CREATE_TRACE_CHILD_NODES.
65
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
ENDMETHOD.
66
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
13 Data Exchange
This section explains the methods and the procedure to allow user defined expression types to participate in
FDT XML Export / Import for the custom action email.
13.1 EXPORT_XML
This method exports the objects in XML format, reads the value from the database using GET methods, and
sets it in the XML.
There might be elements inside your buffer that are optional. For example, in the case expression, the user
can put a simple value as test parameter or an ID that could be a constant. Therefore, within the buffer there
will be the simple test value or the ID field filled, but not both. Both XML elements are optional.
In this case, you should put an, “IF… is initial”, statement around the method CONVERT_ABAP_TO_XML.
You will see how to define optional XML elements within your DTD (Implementation of method GET_DTD).
Recommendation
You can shrink the lines of code needed for this method if you make use of a macro such as
the following:
DEFINE export_xml.
convert_abap_to_xml( io_parent = io_parent
iv_name = &1
iv_namespace_prefix = gc_my_namespace_prefix
ia_abap = &2 ).
END-OF-DEFINITION.
67
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
This might be useful when you have many objects inside your buffer. You would only have to
use the following:
es_namespace-prefix = gc_my_namespace_prefix.
es_namespace-uri = if_fdt_data_exchange=>gc_xml_namespace_uri.
For the namespace URI, you can use the default BRFplus namespace URI.
13.2 IMPORT_XML
This method reads the XML file and imports the objects from XML. It reads the value from XML and sets the
database using SET methods. After you set one XML object to ABAP, you must raise the event
if_fdt_data_exchange_internal~object_id_as_attribute with the corresponding ID as export
parameter iv_id. You don’t have to do this, when importing objects without an ID (for example, a simple
value of type cl_fdt_expr_sv=>s_value).
super->if_fdt_data_exchange_internal~import_xml( io_parent ).
ENDIF.
69
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
13.3.1 GET_DTD
Since the implementation of method GET_DTD requires a deeper understanding of how a DTD has to be
built, this chapter focuses on another example in which the different elements of DTD are detailed.
The purpose of this method is to define DTD for User Defined Expressions used for validating the XML
during import. For BRFplus internal expression types and action types, the DTD is defined in the XSLT
transformation, FDT_APPEND_INTERNAL_DTD. It might be useful to look at this transformation while
developing method GET_DTD of your own expression type. You can see a simple expression type (CASE )
is defined. This might help you understand how to build the DTD for your expression type. The tricky part for
a custom expression type is that you cannot update the BRFplus internal XSLT transformation to work with
your expression type. You must create the DTD definition manually with coding. This task is completed by
method GET_DTD.
Your expression type has two parameters with IDs, PARAMETER1 and “PARAMETER2; one simple value
(type CL_FDT_EXPR_SV=>S_VALUE) called SIMPLE_VALUE, and one table with multiple lines called
DEMO_TABLE. (The line type of this table is not important since it should be defined the same way as, for
example, the structure SIMPLE_VALUE is defined). Concerning the BRFplus default XSLT transformation,
you can figure out that the DTD has been defined as follows:
70
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
The interrogation symbol (?) indicates that this element is optional in the XML. All sub-elements are
separated by a comma, which simply means they occur in sequence.
The DEMO_TABLE is different since it has the same element embedded multiple times (in this case,
ITEM). The structure of the ITEM XML element could be defined again, for example:
You would have modeled a DTD for a table, DEMO_TABLE, with line type simple value. Remember that
your elements consist of sub-elements that you must define.
If you compare the sub-XML elements of DEMO_TABLE to the ones in SIMPLE_VALUE, you will notice that
they are not separated by a comma but by a |. The separator sign defines the grouping of the sub-elements,
whereas the | defines a choice and the comma defines a sequence. Within the XML, the iterating sub-XML-
element of DEMO_TABLE could be ITEM (upper case) or item (lower case).
The occurrence sign differs as well from SIMPLE_VALUE since it is a “*” meaning the element (either ITEM
or item) can occur never, once, or multiple times inside XML element DEMO_TABLE.
As previously mentioned, you must create this definition manually with ABAP/4 code.
Method GET_DTD supplies two important objects in order to define the DTD, namely:
IO_CONTENT_PARTICLE Type ref to IF_IXML_CONTENT_PARTICLE
IO_DOC_TYPE Type ref to IF_IXML_DOCUMENT_TYPE
If you are looking at the structure of an element inside the transformation, it can be defined as embedded
particles.
The outer particle is:
<!ELEMENT CUST_EXTY1:PARAMETER1
. . . >
It can be split into a left particle (the red one) and a right element description (the blue one). Initially, we will
focus on the left particle.
The underlined elements of this particle are split into a prefix and a name. You can create this particle with
the following code:
71
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
prefix = cl_fdt_actn_email=>gc_my_namespace_prefix
grouping = if_ixml_content_particle=>co_sequence
occurrence = if_ixml_content_particle=>co_one ).
Recommendation
We use namespace to avoid ambiguity and also if you define the same element twice in XSLT,
then the complete validation fails. To avoid ambiguity, we recommend using customer-specific
namespace.
.
The grouping and occurrence parameters will be explained later. For this first particle they should always be
co_sequence and co_one. After having created this particle, you have to add it as content to the main
particle which you get as an import parameter:
This is all you have to do for the left particle. For the right particle, you have to create an element description
object. You can do this with the following code:
You must pass the correct name and prefix corresponding to your left particle.
First, you create the content for this object. The main particle embedded as element description is the
surrounding brackets.
grouping = if_ixml_content_particle=>co_sequence
occurrence = if_ixml_content_particle=>co_one ).
Now you can create the content particle that is embedded inside the brackets-particle for PARAMETER1.
Note
If you do not pass a “prefix” parameter the particle is created with its name (in this example,
#PCDATA).
Now that you are finished with the element description (with #PCDATA embedded), you can proceed to add
the element description as child to the IO_CONTENT_PARTICLE.
If you look at the SIMPLE_VALUE, you must add not only one particle (#PCDATA) to the brackets-particle
but actually four other particles. You have to set the grouping signs and occurrence signs appropriately.
For the XML element SIMPLE_VALUE, the coding is as follows:
lo_outer_cp = io_doc_type->create_content_particle(
name = 'SIMPLE_VALUE’
prefix = cl_fdt_actn_email=>gc_my_namespace_prefix
grouping = if_ixml_content_particle=>co_sequence
occurrence = if_ixml_content_particle=>co_one ).
lo_element_descr-
>set_content_spec( content_spec = if_ixml_element_decl=>co_mixed ).
lo_element_descr-
>set_grouping( grouping = if_ixml_content_particle=>co_sequence ).
lo_element_descr-
>set_occurrence( occurs = if_ixml_content_particle=>co_one ).
73
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
name = ''
grouping = if_ixml_content_particle=>co_sequence
occurrence = if_ixml_content_particle=>co_one ).
lo_cp_element = io_doc_type->create_content_particle(
name = 'ELEMENT_TYPE'
prefix = cl_fdt_actn_email=>gc_my_namespace_prefix
grouping = if_ixml_content_particle=>co_sequence
occurrence = if_ixml_content_particle=>co_zero_or_one ).
After defining the structure of the SIMPLE_VALUE XML element, you then define the sub-elements. As this
is done the same way as with the definition of PARAMETER1 (element description, #PCDATA) the
appropriate coding is not covered here.
Recommendation
The order of defining the XML-elements is relevant and you must adhere to the same sequence
they are exported via method EXPORT_XML.
The following tables show the outcome of each constant used for grouping and occurrence:
74
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
Grouping
Constant Result
if_ixml_content_particle=>co_sequence Appended separator for this particle is a
comma (CUST_EXTY1:ELEMENT_TYPE?, )
if_ixml_content_particle=>co_choice Appended separator for this particle is a |
(CUST_EXTY1:ITEM| CUST_EXTY1:item )
Occurrence
Constant Result
if_ixml_content_particle=>co_one The corresponding XML element occurs
only once in the XML (#PCDATA
nothing is appended)
if_ixml_content_particle=>co_one_or_more The corresponding XML element occurs
one or multiple times in the XML
(CUST_EXTY1:ELEMENT_TYPE+,)
if_ixml_content_particle=>co_zero_or_more The corresponding XML element occurs
zero or multiple times in the XML
( (CUST_EXTY1:ITEM|
CUST_EXTY1:item)* here the
occurrence is set in the bracket particle)
if_ixml_content_particle=>co_zero_or_one The corresponding XML element occurs
zero or once (optional XML element) in
the XML
(CUST_EXTY1:ELEMENT_TYPE?,)
13.3.2 GET_ELEMENT_DOMAIN_LIST
This method defines the domain list of an element. This method must be redefined when the element is
bound to DDIC; the value help can read from the domain values.
METHOD if_fdt_data_exchange_external~get_element_domain_list.
ls_element_domain-node_name = 'ABC:RECIPIENT'.
ls_element_domain-type = 'if_fdt_actn_email=>t_recipient'.
INSERT ls_element_domain INTO TABLE et_element_domain_list.
ls_element_domain-node_name = 'ABC:BODY'.
ls_element_domain-type = 'if_fdt_actn_email=>body'.
INSERT ls_element_domain INTO TABLE et_element_domain_list.
ls_element_domain-node_name = 'ABC:SUBJECT'.
ls_element_domain-type = 'if_fdt_actn_email=>subject'.
INSERT ls_element_domain INTO TABLE et_element_domain_list.
ENDMETHOD.
The output parameter for this method is ET_ELEMENT_DOMAIN_LIST. The method lists the domain or type
of user defined XML element.
75
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
13.3.3 GET_VERSION_CHANGE_LIST
This method maintains the changes in different XML versions. The name and structure of XML elements can
change in different versions, which may prevent the import of older versions. This method allows you to track
the changes in different versions, and know which XML version to use.
We need to define this method for any changes and add values to ET_VERSION_CHANGE. During runtime,
we call this method to determine the objects for which the modification needs to be made, and if not defined
then the modification is skipped.
For example, if the changes were made for expression type email, we need to add for that version.
METHOD if_fdt_data_exchange_external~get_version_change_list.
ENDMETHOD.
The output parameter for this method is ET_VERSION_DOMAIN_LIST. The method lists the domain or type
of user defined XML element.
13.3.4 MODIFY_XML_VERSION_CHANGES
This method transforms one version to another, where the version is updated (1.06 to 1.07) or downgraded
(1.07 to 1.06).
This method allows you to adhere to the XML downgrade and upgrade from different releases. For example,
if your previous release has Element-Recipient that was changed to Recipient(s), you need to delete the old
element and insert new one (recipients) so the DTD is validated correctly. The value of the new element is
defaulted; vice versa for downgrade.
In our example, if the Recipient changes from a single value to a multiple value, then the changes would be
as follows:
METHOD if_fdt_data_exchange_external~modify_xml_version_changes.
lo_ixml = cl_ixml=>create( ).
lo_document = lo_ixml->create_document( ).
IF iv_from_version LT iv_to_version.
* Case of Version Upgradation
* For Version 1.06 -> 1.07 upgradation.
IF iv_from_version EQ '1.01'
76
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
ENDMETHOD.
The input parameters for this method are as follows:
IO_PARENT
Provides a table of the object IDs for export
IV_FROM_VERSION
Lower boundary BRFplus XML version in version change
IV_TO_VERSION
Upper boundary BRFplus XML version in version change
The output parameter is as follows:
ET_MESSAGE
Provides a list of failure and success messages
77
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
Procedure
78
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
Note
For most action types and expression types you can find constants in IF_FDT_CONSTANTS.
Transaction FDT_RESERVED gives an overview of UUIDs included into the BRFplus shipment
and reserved UUIDs.
You cannot and you do not have to change those objects.
79
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
REPORT fdt_demo_report_actn_email.
lo_factory = cl_fdt_factory=>if_fdt_factory~get_instance(
if_fdt_constants=>gc_application_tmp ).
* make the email action the top expression (most simple test)
lo_function ?= lo_factory->get_function( ).
lo_function->if_fdt_transaction~enqueue( ).
lo_function->if_fdt_admin_data~set_name( cl_fdt_services=>get_unique_name( ) ).
lo_function->set_expression( lo_email->mv_id ).
80
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
To create your own user interfaces for expression types and action types you have a basic understanding
about Web Dynpro (WD) ABAP. Tutorials and videos about WD ABAP are available in SCN.
Component Description
Web Dynpro The WD component visualizes and controls (react on user actions) the UI. It is
Component the Controller and View of the well-known MVC pattern. The WD component is
designed to display the detail part of the expression type/action. The general
and toolbar sections are provided by the BRFplus UI framework. The lifecycle
and transactional functionalities arehandled by this framework.
The WD component implements two WD interfaces that control the lifecycle of
the component.
Model Class The model class is the connector between the UI and the backend. It
represents the model entity of the MVC pattern. It is a standard ABAP OO-
class that inherits from CL_FDT_WD_MAINTENANCE_MODEL and retrieves
and updates the data that are maintained in the UI. The data are stored in
model nodes, which are technically structured WD context nodes. The model
class stores the translatable text elements used in dynamic UI screens.
UI Class The UI OO class determines the model class and the WD component for an
expression type/action (Registry). It ensures that customer expression
types/actions are protected against future enhancements of the BRFplus UI
framework through versioning.
Services The UI Infrastructure provides various services you use in your UI. One major
service is the query component that enables the user to select BRFplus
objects. You need this component if your expression type/object refers to other
BRFplus objects.
81
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
Note
Since the shipped WD component for the email action type creates UI parts during runtime
(dynamically), the component is not discussed, but those parts relevant to understand the
framework. Some features are discussed without referring to the implementation of the email
action type to make this tutorial easier to understand.
82
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
Model Nodes
Model nodes are actually data containers filled in the model class by accessing the backend.
There is a root node, MODEL, under which all model nodes are stored. You have to create this root node for
each of your action or expression type WD components.
Each model node (RECIPIENTS) is bound to a DDIC structure (check the
FDTS_WD_ACTN_EMAIL_RECP_MODEL and FDTS_WD_ACTN_EMAIL_MSG_MODEL structures to get
an idea), which defines its attributes. The cardinality of the node determines if the data are a collection
(table) or a flat structure. The model nodes should be defined semantically. That means the attributes that
belong together should be part of one model node. Usually those attributes are displayed together in a WD
view.
UI Adjustment Node
The UI_ADJUSTMENT node is provided by the UI framework. The attributes read_only and enabled must be
bound to the corresponding attributes of the UI elements. This has the advantage that these UI elements are
set to read-only or disabled if the user is not allowed to maintain the content. This is the case, when the
object is visualized in display mode.
The readOnly attribute of the recipient input field in the WD view is bound to the read_only attribute of the
UI_ADJUSTMENT node.
83
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
Now you may catch this exception in the WD component for example and react on it.
Reacting on Exceptions
You have to catch all possible exceptions properly. Depending on the exceptions, you can do one of the
following:
Try to react by providing a workaround
Example: If the user cannot edit an object because it is locked you can try to display it.
Within the WD component, do not catch exceptions if they are part of the signature in an interface
method.
Example: All maintenance UI WD components are implementing the interface FDT_IWD_OBJECT.
These methods have the exception cx_fdt_wd in its signature and are handled by the object
manager.
In the majority of cases, you probably cannot react and want to display the exception (error text) to
the user. This can be accomplished by calling the method
CL_FDT_WD_SERVICE=>REPORT_EXCEPTION.
It provides two parameters:
o IX_EXCEPTION for reporting backend exceptions
o IX_WD_EXCEPTION for UI exceptions
Method in a WD caller, calling a method in the model class and handling exception properly.
TRY.
wd_this->mo_model->refresh_model( ). “->may raise cx_fdt_wd
84
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
INIT
METHOD INIT .
wd_this->mo_model = io_model.
wd_this->mo_state = io_state.
wd_this->mv_id = iv_id.
wd_this->gc_usage_type_message = 'USAGE_MESSAGE_VAR'.
wd_this->gc_usage_type_rec = 'USAGE_REC_VAR'.
ls_rec-rec_1_req = abap_true.
ls_rec-rec_1_name = wd_this->mo_model-
>if_wd_component_assistance~get_text( key = '001' ).
ls_rec-rec_2_req = abap_true.
ls_rec-rec_2_name = wd_this->mo_model-
>if_wd_component_assistance~get_text( key = '001' ).
ls_rec-rec_3_req = abap_true.
ls_rec-rec_3_name = wd_this->mo_model-
>if_wd_component_assistance~get_text( key = '001' ).
ls_rec-rec_4_req = abap_true.
ls_rec-rec_4_name = wd_this->mo_model-
>if_wd_component_assistance~get_text( key = '001' ).
85
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
You should set those parameters into attributes of your component controller.
DISPLAY
The purpose of this method is to notify that the object should be displayed.
METHOD DISPLAY .
wd_this->mo_model->get_model( ).
wd_this->create_toolbar( ).
ENDMETHOD.
Usually, you call the GET_MODEL( ) of your model to get the model from the backend. This method
retrieves the data from the backend and provides it by supplying the corresponding model nodes.
Sometimes, you do not want to retrieve the complete data from the backend initially but only if the data
needs to be visualized. For example, if you have different tabs in your view. Therefore, instead of calling
GET_MODEL( ), you can call GET_MODEL_BY_NODE by providing the name of a model node. In this case,
only the provided node is filled with data from the backend.
This method can throw CX_FDT_WD.
EDIT
This method notifies that the object should be edited. Do not enqueue the object since this is done by the UI
framework.
METHOD edit .
wd_this->mo_model->get_model( ).
wd_this->create_toolbar( ).
ENDMETHOD.
SAVE
This method notifies that the object should be saved/synchronized in a consistent state to the backend. The
UI component/model must not call the save method in the backend. This is done by the framework, if
necessary.
86
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
METHOD save .
wd_this->mo_model->refresh_model( ).
ENDMETHOD.
Usually, you call the refresh_model( ) of your model, which synchronizes the UI with the backend.
This method can throw CX_FDT_WD.
SET_CONFIGURATION
After the creation of your WD component, this method is called by the framework and provides the
configuration handle (IO_CONFIGURATION). You must store this parameter into an attribute (convention:
mo_configuration) of your component controller. The configuration represents the user configuration and
technical settings (for example if a toolbar button should be displayed). The configuration handle
(IO_CONFIGURATION) is a mandatory parameter for every service method.
wd_this->MO_CONFIGURATION = io_configuration.
VIEW
The view (MAIN_VIEW) contains the layout of the action Email UI. The UI ADJUSTMENT and MODEL
nodes are bound from the component controller.
87
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
As usual in WD you define your UI elements here and bind the content properties of it to context nodes. The
content of the data is provided by the model nodes. For example, you bind the Recipients input field to the
context attribute Model.Recipients.Recipients (same applies to Subject, Message, and Parameters).
You also bind the attributes of the UIAdjustment node to the proper properties (enabled, read_only) of the
elements in your view.
Only views that are embedded in the window OBJECT_IVIEW are displayed.
REGISTER_TOOLBAR
This event registers a toolbar in the „DETAIL‟ tray.
The toolbar can consist of max 8 toolbar buttons.
Mandatory fields are the name of the action („action‟) and the text of the button („text‟).
Look at IF_FDT_WD_TYPES=>S_TOOLBAR for further fields.
When you press the button on the toolbar you are notified via the method, HDL_ACTION.
If you raise the event again, the toolbar is rebuilt from scratch.
The following method is an example how to populate buttons in the toolbar. You call this method in the
display and edit methods of the Componentcontroller.
METHOD create_toolbar_.
ls_toolbar-action = “My_Action”
ls_toolbar-text = “My Test Action”
"register toolbar
wd_this->fire_register_toolbar_evt( it_toolbar = lt_toolbar ).
88
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
If the user presses a button, the method HDL_ACTION is called by the framework. This gives you the
chance to handle the action.
METHOD hdl_action .
IF iv_action = My_Action”.
“Do something here
ENDIF.
ENDMETHOD.
Wizard UI
Optionally, you have the possibility to provide a simplified UI for your action or expression type, which is
used when the object is created.
An example is the random expression type, which provides the following screen during creation:
You can provide such a wizard UI for your expression or action type by implementing the followings steps:
1. Create a view for the wizard UI. The view should be simple, small and easy to use. You should reuse
the existing model nodes, which are already available for your main view. It must not have any links,
since it is not possible to navigate to other objects within this view.
2. Nest the view in the interface view WIZARD_IVIEW, which is available.
3. Implement the method IS_SUPPORTING_WIZARD_MODE in your component controller and set:
rv_supports_wizard_mode = abap_true
4. Implement the method MAINTAIN_IN_WIZARD of your component controller. This method is called
by the framework, before the create popup is displayed.
You can fill model nodes via your model class if you want to set default values.
89
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
When the user has acknowledged the creation of the object, you are notified via the SAVE method. As in the
standard view, synchronize your UI with the backend by calling the refresh_model( ).
The method CREATE of your WD component is called by the framework if the user creates a new instance
of the object (Create Popup). You use this method to preconfigure your component and to decide
dynamically if you provide a wizard UI or not (implementation of IS_SUPPORTING_WIZARD_MODE).
Note
It does not make sense to provide a wizard UI for every expression type or action type,
especially for more complex expression types such as the decision table.
Be aware that it is not possible to navigate from a wizard UI to other BRFplus objects.
Therefore, do not use links within this view.
Note
You should read data from the API in the GET_MODEL_BY_NODE method and fill the model
nodes accordingly. Change the content of model nodes in the WD component only if the user
changes data. Otherwise, the tracking of the state of your component will be erroneous.
90
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
IF_FDT_WD_MODEL~INIT
This method initializes the model and is called during the initialization of the component.
METHOD if_fdt_wd_model~init.
TRY.
me->mo_actn_email ?= me->mo_factory->get_expression( iv_id = mv_id ). (2)
CATCH cx_fdt INTO lx_fdt.
cl_fdt_wd_service=>convert_backend_exception( ix_fdt = lx_fdt ). (3)
ENDTRY.
ENDMETHOD.
PUBLISH_MODEL_NODES
The purpose of this method is to publish the model nodes which are defined in the WD component controller
under the model root node.
METHOD if_fdt_wd_model~publish_model_nodes.
* node recipients
ls_model_node-name = gc_model_node_recipients. (1)
ls_model_node-read_only = abap_false.
INSERT ls_model_node INTO TABLE rt_model_node. (2)
ENDMETHOD.
91
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
For every model node you create a constant (1) in the model class by using the name of the model name as
its value.
You publish those model nodes in this method. For each model node, you create an entry in table
rt_model_node (2). You specify if the model is only read-only; the user cannot change the data. Since this is
not true for this component, the read_only flag is set to abap_false.
Sometimes there is the need to add a non-data attribute to your model node. This is true if you use the
model for binding against a WD table since WD does not provide the possibility to bind two data sources for
content and metadata (for example, design of a row) of the table. To mark an attribute as meta-data and not
to consider it for checking if the object has changed, you can model the table ‘attributes’ accordingly, which
is part of the structure of the returning parameter rt_model_node.
For example, to exclude the CELL VARIANT attribute from a check to determine if the object was changed,
you would implement the following:
ls_attribute-name = 'CELL_VARIANT'.
ls_attribute-exclude_from_dirty_check = abap_true.
INSERT ls_attribute INTO TABLE lt_attributes.
ls_model_node-attributes = lt_attributes.
GET_MODEL_BY_NODE
This method retrieves the model from the backend and fills the proper model node. We discuss only the
recipient model node to simplify this tutorial.
METHOD get_model_by_node.
TRY.
lo_model_node = me->if_fdt_wd_model~get_model_node_by_name( iv_model_node_name ).
(1)
CASE iv_model_node_name.
WHEN gc_model_node_recipients. (2)
IF mv_timestamp IS NOT INITIAL.
lt_recipients = mo_actn_email->get_recipients( mv_timestamp ).
(3)
mo_actn_email->get_parameters(
EXPORTING iv_timestamp = mv_timestamp
IMPORTING ets_recipient_parameter = lts_rec_param ).
ELSE.
lt_recipients = mo_actn_email->get_recipients( ).
mo_actn_email->get_parameters(
IMPORTING ets_recipient_parameter = lts_rec_param ).
ENDIF.
lo_model_node->get_static_attributes(
IMPORTING static_attributes = ls_recipients_model ).
LOOP AT lts_rec_param INTO ls_rec_param.
92
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
93
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
WHEN 4.
ls_recipients_model-rec_4 = ls_rec_param-parameter_id.
ls_recipients_model-rec_4_name = lv_text.
ls_recipients_model-rec_4_req = abap_true.
IF ls_rec_param-parameter_id IS NOT INITIAL.
CLEAR ls_icon.
ls_icon = cl_fdt_wd_icons=>get_icon(
iv_id = ls_rec_param-parameter_id
io_configuration = mo_configuration
iv_timestamp = mv_timestamp
iv_bound_object_id = mv_id ).
ls_recipients_model-rec_4_icon = ls_icon-icon_source.
ls_recipients_model-rec_4_tooltip = ls_icon-tooltip.
ELSE.
ls_recipients_model-rec_4_tooltip = lv_text.
ENDIF.
ENDCASE.
ENDLOOP.
CONCATENATE LINES OF lt_recipients INTO ls_recipients_model-
recipients SEPARATED BY '; '. (4)
ENDMETHOD.
Initially, the instance of the model node is retrieved by calling get_model_node_by_name( ) (1).
For each model node (2) which is provided by the importing parameter iv_model_node_name, we fill the
data accordingly. If you have several model nodes in your component, it makes sense to spread the
implementation into several private methods of your model class, which are called by this method.
When you call the GET methods of the backend-API (mo_actn_email->get_recipients) you must
check if the UI should display an older version: if mv_timestamp is not initial, you have to supply this
timestamp for the backend call (3).
The recipient table (lt_recipients) provided by the backend is then prepared for displaying. Therefore,
the recipients are split into a string (lv_recipients_model) (4) and bound to the structure
ls_recipients_model of the structure node ls_recipients.
Then, the structure is bound to the model node (5). If you have a table (context node with cardinality > 1) you
must use the method bind_table instead. Be aware of the optional parameter iv_initialze_elements,
which you should assign to set_initial_elements when calling the BIND… methods of the WD context
node.
Finally, the exceptions of the backend are converted into the cx_fdt_wd_backend exception of the UI
layer.
Note
The protected method SET_MODEL_BY_NODE of CL_FDT_WD_MODEL has to be re-
implemented and not the interface IF_FDT_WD_MODEL method.
94
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
SET_MODEL_BY_NODE
The purpose of this method is to set the model node to the backend for the respective node. This means the
backend is updated.
METHOD set_model_by_node.
TRY.
lo_nd_model = me->if_fdt_wd_model~get_model_node_by_name( iv_model_node_name ).
(1)
WHEN gc_model_node_recipients.
(2)
" getting element of node
lo_nd_model-
>get_static_attributes( IMPORTING static_attributes = ls_recipients_model ). (3)
lv_recipients_model = ls_recipients_model-recipients.
SPLIT lv_recipients_model AT ';' INTO TABLE lt_recipients.
LOOP AT lt_recipients INTO ls_recipients.
CONDENSE ls_recipients.
INSERT ls_recipients INTO TABLE lt_recipients_final.
ENDLOOP.
mo_actn_email->set_recipients( lt_recipients_final ).
IF ls_recipients_model-rec_1_req EQ abap_true AND ls_recipients_model-
rec_1 IS NOT INITIAL.
ls_parameter-position = 1.
ls_parameter-parameter_id = ls_recipients_model-rec_1.
INSERT ls_parameter INTO TABLE lts_parameter.
ENDIF.
IF ls_recipients_model-rec_2_req EQ abap_true AND ls_recipients_model-
rec_2 IS NOT INITIAL..
ls_parameter-position = 2.
ls_parameter-parameter_id = ls_recipients_model-rec_2.
INSERT ls_parameter INTO TABLE lts_parameter.
ENDIF.
IF ls_recipients_model-rec_3_req EQ abap_true AND ls_recipients_model-
rec_3 IS NOT INITIAL..
95
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
ls_parameter-position = 3.
ls_parameter-parameter_id = ls_recipients_model-rec_3.
INSERT ls_parameter INTO TABLE lts_parameter.
ENDIF.
IF ls_recipients_model-rec_4_req EQ abap_true AND ls_recipients_model-
rec_4 IS NOT INITIAL..
ls_parameter-position = 4.
ls_parameter-parameter_id = ls_recipients_model-rec_4.
INSERT ls_parameter INTO TABLE lts_parameter.
ENDIF.
mo_actn_email->set_parameters( EXPORTING its_recipient_parameter = lts_parameter ).
(4)
ENDCASE.
CATCH cx_fdt INTO lx_fdt.
cl_fdt_wd_service=>convert_backend_exception( ix_fdt = lx_fdt ).
ENDTRY.
ENDMETHOD.
To set the model to the API you need a variable (ls_recipients_model) which refers to the same DDIC-
type as your model node in the Web Dynpro component.
Initially, the reference for the model node is retrieved (1).
Afterwards, you have to check which model node (iv_model_node_name) shall be updated (2).
Then, the data are retrieved from the (model) context node (3).
Finally, the backend is updated (4).
16.3.3 Reference
The following table provides an overview about the methods of the model class.
The interface IF_FDT_WD_MODEL consists of the following methods. You can call these methods in your
WD component:
96
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
Method Description
IF_WD_COMPONENT_ASSISTANCE If you have defined text symbols in your model class, you can
~GET_TEXT access them with the help of this method.
PUBLISH_MODEL_NODES Redefine this method.
Publish all the model nodes you have defined in your WD
component. Set the read_only flag = abap_true, if the
user cannot change the data of the node.
When you have a recursive context node please set the field
‘exclude_from_dirty_check’ = abap_true.
Detecting if the object has changed.
There is also a hash table available (attributes component in the
rt_model_node table) that enables you to exclude certain
attributes of your node(s) for the dirty state check. This means
that if the values of these attributes have changed, the object
(=>your WD component) is not considered as unchanged. Do
not misapply this option to mix the model with non-model
parameters.
INIT Redefine this method. Call this method during initialization of
your WD component. Do any necessary initialization here. Do
not forget to call the super method.
(super->if_fdt_wd_model~init(io_context_node =
io_context_node io_controller =
io_controller)
This method can throw CX_FDT_WD_BACKEND.
GET_MODEL This method gets the whole model for the WD component and
calls GET_MODEL_BY_NODE for each model node.
This method can throw CX_FDT_WD_BACKEND.
SET_MODEL This method updates the backend from the WD component and
calls SET_MODEL_BY_NODE for each changeable model
node.
Optional: you can provide an action which describes the
changes (insert, update) if you need such semantics in your
implementation.
This method can throw CX_FDT_WD_BACKEND.
GET_MODEL_BY_NODE This method retrieves your model from the backend and fills the
proper model node. You can provide a WD context node and/or
a WD context element if you need to query the data from the
backend. A use case for these query elements would be for
instance: you have a tree, the user adds a new node, and you
want to re-read the corresponding sub-tree to reflect the
changes on the UI.
Do not redefine this method but instead use the protected
method GET_MODEL_BY_NODE.
This method can throw CX_FDT_WD_BACKEND.
97
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
SET_MODEL_BY_NODE This method sets/updates your model to the backend for the
node. Do not redefine this method but instead use the protected
method SET_MODEL_BY_NODE. You can provide an action
which describes the changes (insert, update). The action is not
evaluated by the framework; you can use it in your
implementation.
This method can throw CX_FDT_WD_BACKEND.
IS_MODEL_CHANGED This method returns true, if the model has changed.
GET_MODEL_NODE_BY_NAME Retrieves the reference to a model node.
REFRESH_MODEL This method refreshes the model; the UI and backend are
synchronized. Technically, SET_MODEL (optional:
SET_MODEL_BY_NODE) is called first and then GET_MODEL
(optional GET_MODEL_BY_NODE).
This method is useful if the user has changed some data on the
UI and you want to call the API to update further fields (texts,
descriptions).
This method can throw CX_FDT_WD_BACKEND.
SET_MODEL_CHANGED This method sets the model as changed.
Method Description
SET_NOT_FOUND_TEXT_KEY Do not use this method.
It is inherited from the WD Assistance Class, which is the super
class of our model class.
GET_MODEL_BY_NODE Redefine this method:
Implement the functionality to retrieve the model from the API in
this method.
This method can throw CX_FDT_WD_BACKEND.
SET_MODEL_BY_NODE Redefine this method:
Implement the functionality to set the model to the API.
This method can throw CX_FDT_WD_BACKEND.
16.4 UI Class
The purpose of this OO class is to determine the characteristics of the expression / action type regarding its
UI. It determines the model class, the WD Component, and the implemented version of the UI
framework/infrastructure. The UI class is an attribute of the expression /action type and can be set via the UI.
98
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
16.4.1 HAS_WD_ABAP_UI
The purpose of this method is to determine if an expression type or an action type has a WD ABAP UI. The
method returns a Boolean variable stating the support for WD ABAP UI.
METHOD if_fdt_ui_definition~has_wd_abap_ui.
rv_has_wd_ui = abap_true.
ENDMETHOD.
There is an active WD ABAP UI for custom action email, thus the parameter is set to abap_true.
16.4.2 GET_WD_ABAP_MODEL_CLASS
In this method, the model class for an expression type or action type UI is determined.
METHOD if_fdt_ui_definition~get_wd_abap_model_class.
rv_model_class = 'CL_FDT_WD_ACTN_EMAIL_MODEL'.
ENDMETHOD.
The parameter returns the active model class for the custom action email.
16.4.3 GET_WD_ABAP_COMPONENT
99
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
METHOD if_fdt_ui_definition~get_wd_abap_component.
rv_wd_component = 'FDT_WD_ACTN_EMAIL'.
ENDMETHOD.
The parameter returns the active WD component for the custom action email.
16.4.4 GET_WD_ABAP_VERSION
This method determines the implemented version of the BRFplus UI framework.
METHOD if_fdt_ui_definition~get_wd_abap_version.
rv_version = ‘1.01’.
ENDMETHOD.
By versioning the UI components, it ensures that customer expression type or action types are protected
against future enhancements of this BRFplus UI framework. When your system is updated to a newer
release and you do not have the chance or do not want to immediately adapt your components, you should
return the version, which was available during development. The current version number is the value of the
constant IF_FDT_UI_DEFINITION=>GC_WD_ABAP_VERSION.
It is not recommended to return IF_FDT_UI_DEFINITION=>GC_WD_ABAP_VERSION because then you
would be forced to immediately react on every framework change. Instead, you should return the value of the
constant (1.01) to ensure your coding runs in subsequent SAP NetWeaver releases without adaptation of
your expression type.
Note
If you return IF_FDT_UI_DEFINITION=>GC_WD_ABAP_VERSION, you adapt your WD
component if the system is upgraded to a newer SAP NetWeaver release. Since the adaptation
is not always immediately possible, you are strongly encouraged to return the current version
as a value and not the constant. You can make use of new framework features by adapting
your coding and then return a higher version.
Note
The versioning is independent of an SAP NetWeaver release. An update of an SAP NetWeaver
release may not result in an update of the UI framework when there are no incompatible
changes.
100
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
The WD interface FDT_IWD_OBJECT, which is implemented by your WD component, provides two events
for creating new objects:
CREATE_OBJECT_SIMPLE
CREATE_OBJECT_EXPERT
CREATE_OBJECT_SIMPLE is easier to use and CREATE_OBJECT_EXPERT provides more
options with respect of controlling if the user can use reusable objects.
After the event is fired, the standard creation dialog is displayed. If the user actually creates an object, your
component is informed by calling the method ADD_USAGE, which is also part of the interface
FDT_IWD_OBJECT. You are provided with the ID of the newly created object and can update your model
accordingly.
Example
You have an attribute ‘MY_ATTRIBUTE’ in your expression type, which can be bound to another expression.
Therefore, you create a method ‘CREATE_MY_ATTRIBUTE’ in one of your WD controllers, which is called
by a UI action.
The possible object types that can be created by the user are narrowed by expressions (1) and then the
event is triggered (2).
When the expression is created, you are notified by the call of the ADD_USAGE method in the component
controller:
METHOD add_usage .
wd_this->mo_model->set_element_attribute( (1)
iv_model_node_name = CL_FDT_WD_MY_MODEL=>GC_MY_MODEL_NODE_NAME
iv_attribute_name = MyAttributeName
iv_value = iv_id ).
The incoming parameter IV_ID represents the ID of the created object. If the attribute is part of a flat model
structure you can easily update the model by calling (1), providing the name of the model node and the
name of the attribute. You use standard WD means to update the attribute in your WD context (model) node.
This is needed if your context node has cardinality > 1 (table).
After the attribute is set, the model is refreshed (2). This means, the API setter and getter are called via your
model class. This ensures that dependent attributes are also updated in the UI.
Note
When you have more than one parameter created by the user, you must memorize which
parameter is created before raising the event. In the ADD_USAGE method, you can use this
variable to differentiate between those parameters.
101
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
Example
You have an attribute MY_ATTRIBUTE in your expression type, which is bindable to another expression.
To access the query, you must add the component (interface) FDT_IWD_QUERY to your component.
To trigger the query by a user action, create a method, SELECT_MY_ATTRIBUTE, in one of your WD
controllers:
TRY.
lo_admin_data = cl_fdt_wd_service=>get_admin_data( wd_comp_controller->mv_id )(2)
lv_application_id = lo_admin_data->get_application( ).
wd_comp_controller->get_query( )->object_query(
io_calling_object = lo_admin_data
is_object_type = ls_object_type
iv_application_id = lv_application_id
iv_initial_search = abap_true
iv_type_fixed = abap_true
iv_multiple_selection = abap_false
).
102
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
(1) If the query is not already instantiated, this is done via the factory. Ensure that you supply the
configuration handle (if_fdt_wd_configuration).
(2) The admin data instance of the current object is retrieved and the query is called.
Note
IO_CALLING_PARAMETER is optional in the signatures of query methods. This will change in
the future. Therefore, make sure that you always provide IO_CALLING_PARAMETER.
The query interface FDT_IWD_QUERY provides the event OBJECTS_SELECTED, which you can
implement in an event handler HDL_OBJECTS_SELECTED.
DATA: lt_object TYPE fdtt_wd_object,
lx_fdt_wd TYPE REF TO cx_fdt_wd.
FIELD-SYMBOLS: <ls_object> TYPE fdts_wd_object.
**********************************************************************
READ TABLE mt_objects INDEX 1 ASSIGNING <ls_object>. (1)
wd_comp_controller->mo_model->set_element_attribute(
iv_model_node_name = wd_comp_controller->wdctx_properties (2)
iv_attribute_name = 'EXPRESSION_ID'
iv_value = <ls_object>-id
).
wd_comp_controller->mo_model->refresh_model( wd_comp_controller->wdctx_properties ). (3)
The selected objects are available in the importing table mt_objects (1) of the event.
The selected expression is set to the model node by the convenience method set_element_attribute.
The call of refresh_model (3) refreshes the view.
103
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
Note
When you have more than one parameter that can be selected by the user, memorize which
parameter is created before raising the event. In the event handler, you can then use this
variable to differentiate between those parameters.
The previous example presents the usage of the OBJECT_QUERY method from the class
CL_FDT_WD_QUERY_MODEL. This method controls the execution of the object query. In addition to this
method, the CL_FDT_WD_QUERY_MODEL class has other useful methods for querying objects.
Object Description
104
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
The interface IF_FDT_WD_OBJECT_MENU implements the service to render the menu for binding objects.
It includes the system objects (Standard). Further, it displays either the context data objects
(render_menu_default) or the last accessed objects (render_menu). The number of these ‘quick accessible’
objects is limited. For accessing elements of a structure, the user must use the ‘select’ functionality (standard
query).
Additionally, the standard menu items such as Select, Create and Remove are displayed. This interface
allows you to customize the menu. Due to WD restriction, this menu has to be created before the user clicks
on it.
Demo Component
The WD component FDT_WD_DEMO_OBJECT_MENU provides an example how to use the object menu
service.
To render the menu, implement the following steps (name of attributes/methods are proposals):
1. Create a menu for the link (UI element, but without any menu items!).
2. Create an attribute MO_OBJECT_MENU (public access) type ref to IF_FDT_WD_OBJECT_MENU
(preferable in the ‘Custom/Action’ controller, public access).
3. Create an attribute MV_REFRESH_OBJECT_MENU, type boole_d (public access) in the component
controller.
4. Implement a method ‘BUILD_OBJECT_MENU’ in a controller (it is preferable to do this in the
Component / Action controller). Call this method from the wdmodifyview method in your view, if this
method is called for the first time or if mv_refresh_object_menu = abap_true. You have to set
mv_refresh_object_menu to true if the menu has to be refreshed (the user has selected another
object, thus the menu must be updated).
5. Call the constructor by supplying the admin data of the maintained object and the UI configuration
(should be available as mo_configuration in your WD comp controller).
The service interface IF_FDT_WD_OBJECT_MENU provides the following methods to render the menu:
RENDER_DEFAULT_MENU
This method renders a default menu, which includes accessing the context and the
selection/creation of an expression.
Use this menu if you want to bind a context parameter or an expression to an attribute of your
expression type. In most cases you use this method.
RENDER_MENU
This method renders a menu according to the supplied object_type (is_object_type).
It provides a Select <Object Type>, Create <Object Type>, and a number of last accessed objects,
which fits to the object type.
105
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
DATA:
lo_configuration TYPE REF TO if_fdt_wd_configuration,
lo_factory TYPE REF TO if_fdt_wd_service_factory,
lo_node TYPE REF TO if_wd_context_node,
lo_node_mode TYPE REF TO if_wd_context_node,
lv_bound_object_id TYPE if_fdt_types=>id,
ls_object_type TYPE if_fdt_wd_types=>s_object_type_extended,
lt_element_type TYPE if_fdt_wd_object_menu=>t_element_type,
lo_caller TYPE REF TO if_fdt_admin_data,
lx_fdt_wd TYPE REF TO cx_fdt_wd.
*************************************************************************
TRY.
*create an instance of the object menu if this is the first call
IF wd_this->mo_object_menu IS NOT BOUND.
lo_factory ?= cl_fdt_wd_factory=>if_fdt_wd_factory~get_instance( ).
lo_caller = cl_fdt_wd_service=>get_admin_data( wd_this->mv_id ).
wd_this->mo_object_menu = lo_factory-
>get_object_menu( io_configuration = wd_this->mo_configuration
io_caller = lo_caller ).
ENDIF.
*you could call the set_filter... methods to filter out the available objects
*wd_this_mo_object_menu->set_filter...
*finally render the menu
wd_this->mo_object_menu->render_menu_default(
io_view = io_view
iv_action_handler = 'OBJECT_MENU_HANDLER'
* iv_bind_enabled_path = 'UI_ADJUSTMENT.ENABLED'
iv_menu_id = 'OBJECT_MENU' ).
CATCH cx_fdt_wd INTO lx_fdt_wd.
cl_fdt_wd_service=>report_exception( io_message_manager =
106
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
wd_this->wd_get_api( )->get_message_manager( )
ix_wd_exception = lx_fdt_wd ).
ENDTRY.
You can add additional menu items but you must implement the action handler yourself.
If you want to change the text of a rendered menu, you can get the instance of the menu item by calling the
method, GET_MENU_ITEM_BY_ID.
Filter for Data Object + Element Types
The methods SET_FILTER_DATA_OBJECT_TYPES, SET_FILTER_ELEMENT_TYPES, and
SET_FILTER_OBJECTS provide the possibility to limit the display of instances to certain element / data
object types. Use these filters if the result data object has to be a Boolean type.
Note
Be aware that the filter affects only the quick list (context data objects/history) and system
objects.
If you call the query component according to the user action, you have to apply the
corresponding filter for the query. The same is true if a new object is created.
Menu Actions
Create an action in the view to react on menu actions. This action must have the same name as the one you
assigned by calling the RENDER…. methods.
Call the method GET_ACTION_PARAMETER to retrieve the parameters for the action to detect if the user
wants to create/select/remove an object – or if the user has already selected an instance:
*create/remove/select etc. an object regarding the action, which was triggered by the use
r
CASE ls_action_parameter-action.
*user wants to create a new object (via event CREATE_OBJECT)
WHEN if_fdt_wd_object_menu=>gc_action_param_create.
*user wants to select a context object via the UI context query (via FDT_IWD_QUERY-
>CONTEXT_QUERY)
WHEN if_fdt_wd_object_menu=>gc_action_param_context_query.
*user wants to select an expression via the standard query via methods of FDT_IWD_QUERY
WHEN if_fdt_wd_object_menu=>gc_action_param_query.
*user wants to remove the current bounded object (delete the attribute of your model node
)
WHEN if_fdt_wd_object_menu=>gc_action_param_remove.
107
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
Note
If the user assigns another object, you must refresh the object menu.
If you follow the described pattern, set the member variable mv_refresh_object_menu =
abap_true.
IF_FDT_WD_STATE
An instance of this interface is available in the model class (mo_state) and in your WD component
(provided as a parameter in the INIT method).
It represents the state of the currently displayed object (e.g. is displayed, is unsaved, etc.) and is especially
helpful if you want to develop more complex UIs, within which the layout is created dynamically. Look at the
available methods.
CL_FDT_WD_SERVICE
This service class provides methods to assist you in developing your own UIs. See the following methods:
GET_DISPLAY_NAME
You should use this method to retrieve the display name for an object since the user can decide if he
wants to see the name or the text for an object via the configuration. By providing the ID of the object
and the configuration handle you retrieve the display name.
GET_ADMIN_DATA
Returns the admin data instance, by providing its ID and the configuration handle.
REPORT_EXCEPTION
Reports a BRFplus exception as user message(s) by providing the exception instance and the WD
message handler.
REPORT_MESSAGES
Reports BRFplus messages as user messages by providing the messages and the WD message
handler.
CONVERT_BACKEND_EXCEPTION
Every time you call a method in the backend, which can throw an exception, you must catch it and
convert it to the CX_FDT_WD_BACKEND exception by using this method.
16.6 Testing
If you implemented the UI components correctly, the expression type or action type should be available in
the create dialog. To speed up the testing process during development, you can display your UI without the
need to navigate to it. The prerequisite for the following shortcut is that there is an existing expression
(instance) for your expression type available.
To display any object in BRFplus, you can simply add the URL parameter ID to the URL.
Example:
http://myServer:50000/sap/bc/webdynpro/sap/fdt_wd_workbench?sap-language=EN&sap-
client=000&ID=00132120A5A802DB87A5A05EEFFC987B
108
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
Recommendation
We recommend setting a breakpoint in the constructor method of CX_FDT. This is a good idea
because all of the BRFplus exception classes inherit from CX_FDT, so whenever an error
occurs, chances are high that you can catch it there.
Also, when catching exceptions in your code, use the MT_MESSAGE variable that is known to
all exception class instances. In most of the cases, this variable contains information on the
current exception that you will find helpful in understanding and solving the issue.
109
CUSTOM EXPRESSION TYPES AND ACTION TYPES – A STEP-BY-STEP GUIDE WITH EXAMPLE
17 Related Content
Wikipedia, Business Rules:
http://en.wikipedia.org/wiki/Business_rules
Wikipedia, Business Rule Management System:
http://en.wikipedia.org/wiki/Business_Rule_Management_System
SCN, SAP NetWeaver Decision Service Management:
http://scn.sap.com/docs/DOC-29158
SCN, Business Rule Framework plus:
http://scn.sap.com/docs/DOC-8824
SCN, Business Rules Management
http://scn.sap.com/community/brm
110
www.sap.com
Crossgate, m@gic EDDY, B2B 360°, and B2B 360° Services are
registered trademarks of Crossgate AG in Germany and other
countries. Crossgate is an SAP company.
All other product and service names mentioned are the trademarks of
their respective companies. Data contained in this document serves
informational purposes only. National product specifications may vary.