Custom Expression Types and Action Types
Custom Expression Types and Action Types
CUSTOMER
Document Version: 1.0 - 15 October 2013
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.
Hanno Holzheuser is a knowledge architect, currently supporting the SAP Netweaver
Business Rule Framework plus team.
Hanno joined SAP in 1990 and has worked for many units in SAP NetWeaver, SAP Business
Suite, and SAP Cloud managing KM teams and projects.
Marco Wuest is a senior developer in the BRFplus team. Having mainly worked on UI topics,
he created the architecture of the UI layer and implemented the UI infrastructure.
Marco joined SAP in 2003. He previously worked in the Records and Case Management
project.
Carsten Ziegler is the chief product owner of SAP NetWeaver Decision Service Management
and SAP NetWeaver Business Rule Framework plus.
He joined SAP in 2000. Since then he has been working in various projects as a developer,
development architect, project lead and product owner.
2013-07-29
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
Specification/Design .......................................................................................................................... 10
7.1
LOAD_BUFFER_DB ............................................................................................................................. 30
7.2
LOAD_BUFFER .................................................................................................................................... 32
7.3
SET_BUFFER....................................................................................................................................... 33
7.4
SAVE_BUFFER_DB ............................................................................................................................. 33
7.5
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.1
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
8.2.1
GET_USED_EXPRESSIONS.......................................................................................................... 44
8.2.2
GET_DSM_AVAILABILITY .............................................................................................................. 45
8.2.3
GET_CONTEXT_DATA_OBJECTS ................................................................................................ 45
8.3
8.3.1
8.4
CUSTOM EXPRESSION TYPES AND ACTION TYPES A STEP-BY-STEP GUIDE WITH EXAMPLE
10
11
11.1
IS_GENERATING ............................................................................................................................ 54
11.2
GENERATE_PROCESS ................................................................................................................. 54
11.2.1
IF_FDT_DATA_OBJECT->GENERATE_CREATE_DATA_REF .................................................... 55
11.2.2
IF_FDT_DATA_OBJECT=>GENERATE_CONVERT_TO .............................................................. 55
11.2.3
11.2.4
11.2.5
11.2.6
11.2.7
11.2.8
11.2.9
CL_FDT_EXPR_SERVICES=>GENERATE_RANGE_PROCESS ................................................ 60
11.2.10
11.2.11
CL_FDT_EXPRESSION=>GENERATE_GET_VALUE .................................................................. 61
11.2.12
11.3
11.4
12
12.1
CHANGE_TRACE_NODE ............................................................................................................... 64
12.2
CREATE_TRACE_CHILD_NODES ................................................................................................ 65
13
13.1
EXPORT_XML ................................................................................................................................. 67
13.2
IMPORT_XML ................................................................................................................................. 68
13.3
13.3.1
GET_DTD ........................................................................................................................................ 70
13.3.2
GET_ELEMENT_DOMAIN_LIST .................................................................................................... 75
13.3.3
GET_VERSION_CHANGE_LIST .................................................................................................... 76
13.3.4
MODIFY_XML_VERSION_CHANGES ........................................................................................... 76
14
15
16
16.1
16.2
16.2.1
16.2.2
16.2.3
16.2.4
16.3
16.3.1
16.3.2
CUSTOM EXPRESSION TYPES AND ACTION TYPES A STEP-BY-STEP GUIDE WITH EXAMPLE
16.3.3
Reference ........................................................................................................................................ 96
16.4
UI Class ........................................................................................................................................... 98
16.4.1
HAS_WD_ABAP_UI ........................................................................................................................ 99
16.4.2
GET_WD_ABAP_MODEL_CLASS ................................................................................................. 99
16.4.3
GET_WD_ABAP_COMPONENT .................................................................................................... 99
16.4.4
GET_WD_ABAP_VERSION.......................................................................................................... 100
16.5
16.5.1
16.5.2
16.5.3
16.5.4
16.5.5
16.6
17
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 customers use of the information contained in
this document.
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.
CUSTOM EXPRESSION TYPES AND ACTION TYPES A STEP-BY-STEP GUIDE WITH EXAMPLE
CUSTOM EXPRESSION TYPES AND ACTION TYPES A STEP-BY-STEP GUIDE WITH EXAMPLE
Specification/Design
Database Layout
Transport Objects
Interface Creation
Class Creation
New Methods
Redefined Methods
Check Methods
Process Methods
Data Exchange
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.
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.
Object
Category
Customizing
C Customizing
System
S System
Master Data
A Application
BCF
S System
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
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:
Object Category
Transport Object
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.
18
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.
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
BEFORE_EXP
ZDMPRELOCK
FDT_AFTER_IMPORT_C
FDT_BEFORE_EXPORT_C
FDT_PRELOCK
Cross Object = X
Cross Object = X
Cross Object =
FDT_AFTER_IMPORT
FDT_BEFORE_EXPORT
FDT_PRELOCK
Cross Object = X
Cross Object = X
Cross Object = X
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.
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.
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
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.
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
Interface Component
Alias
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.
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
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.
5. Define the following attributes:
Attribute
Level
Visibility
Associated
Type
MS_BUFFER
Instance
Attribute
Private
Type
S_BUFFER
MV_MS_BUFFER_LOADED
Instance
Attribute
Private
Type
ABAP_BOOL
MS_BUFFER_DB
Instance
Attribute
Private
Type
S_BUFFER
MV_MS_BUFFER_DB_LOADED
Instance
Attribute
Private
Type
ABAP_BOOL
GC_ACTN_6000
Constant
Private
Type
TABNAME
Initial Value
FDT_ACTN_6000
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.
6. Create a public alias for the object ID:
Interface Component
Alias
Visible
IF_FDT_ADMIN_DATA~MV_ID
MV_ID
Public
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
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.
For the email action type, create the following code:
DATA: lo_persistence
lv_version
ls_actn_6000
ls_parameter
TYPE if_fdt_actn_email=>s_parameter,
lv_last_db_version TYPE if_fdt_types=>version.
DEFINE db_to_buffer_format.
if &1 is not initial.
ls_parameter-position
= &2.
ls_parameter-parameter_id = &1.
insert ls_parameter into table &3.
clear ls_parameter.
endif.
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
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 ).
SPLIT ls_actn_6000-recipients AT space INTO TABLE rs_buffer-t_recipient.
rs_buffer-subject = ls_actn_6000-subject.
rs_buffer-body
= ls_actn_6000-body.
"Add position and format it and add to buffer.
db_to_buffer_format ls_actn_6000-rec_param_1
db_to_buffer_format ls_actn_6000-rec_param_2
db_to_buffer_format ls_actn_6000-rec_param_3
db_to_buffer_format ls_actn_6000-rec_param_4
db_to_buffer_format
db_to_buffer_format
db_to_buffer_format
db_to_buffer_format
db_to_buffer_format
db_to_buffer_format
db_to_buffer_format
db_to_buffer_format
ls_actn_6000-msg_param_1
ls_actn_6000-msg_param_2
ls_actn_6000-msg_param_3
ls_actn_6000-msg_param_4
ls_actn_6000-msg_param_5
ls_actn_6000-msg_param_6
ls_actn_6000-msg_param_7
ls_actn_6000-msg_param_8
1
2
3
4
rs_buffer-ts_rec_parameter.
rs_buffer-ts_rec_parameter.
rs_buffer-ts_rec_parameter.
rs_buffer-ts_rec_parameter.
1
2
3
4
5
6
7
8
rs_buffer-ts_message_parameter.
rs_buffer-ts_message_parameter.
rs_buffer-ts_message_parameter.
rs_buffer-ts_message_parameter.
rs_buffer-ts_message_parameter.
rs_buffer-ts_message_parameter.
rs_buffer-ts_message_parameter.
rs_buffer-ts_message_parameter.
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.
* fill the buffer if appropriate
IF mv_ms_buffer_db_loaded EQ abap_false AND
( iv_version IS NOT SUPPLIED OR iv_version EQ lv_last_db_version ).
ms_buffer_db
= rs_buffer.
mv_ms_buffer_db_loaded = abap_true.
ENDIF.
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 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:
DATA: lts_version TYPE if_fdt_admin_data=>ts_version,
ls_message TYPE if_fdt_types=>s_message,
lt_message TYPE if_fdt_types=>t_message,
lv_version
TYPE if_fdt_types=>version,
lv_no_version TYPE abap_bool,
lv_ctext TYPE c LENGTH 20,
lv_i TYPE i.
FIELD-SYMBOLS <ls_version> TYPE if_fdt_admin_data=>s_version.
ASSERT NOT ( iv_timestamp IS SUPPLIED AND iv_version IS SUPPLIED ). ">>>
IF iv_timestamp IS NOT SUPPLIED AND iv_version IS NOT SUPPLIED.
when we have the last version we can read from the buffer
IF mv_ms_buffer_loaded EQ abap_false.
*
load the buffer with the last version
ms_buffer
= load_buffer_db( ).
mv_ms_buffer_loaded = abap_true.
ENDIF.
rs_buffer = ms_buffer.
RETURN. ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ELSEIF iv_timestamp IS SUPPLIED. "get the right version for the tmstmp
if_fdt_admin_data~get_active_version(
EXPORTING iv_timestamp = iv_timestamp
IMPORTING ev_version
= lv_version
ev_no_version = lv_no_version ).
IF lv_no_version EQ abap_true.
WRITE iv_timestamp TO lv_ctext. "Convert to external format
DATA: lv_name TYPE if_fdt_types=>name.
DATA: lv_str_name TYPE string.
cl_fdt_services=>get_texts_for_id( EXPORTING iv_id
= mv_id
IMPORTING ev_name
= lv_name ).
lv_str_name = lv_name.
MESSAGE x006(fdt_core) WITH lv_str_name lv_ctext INTO ls_message-text.
message_exception ls_message lt_message cx_fdt_input.
*
ENDIF.
ELSEIF iv_version IS SUPPLIED. "use this version
lv_version = iv_version.
ENDIF.
* do we have a valid version now?
if_fdt_admin_data~get_versions( IMPORTING ets_version = lts_version ).
READ TABLE lts_version ASSIGNING <ls_version>
WITH TABLE KEY version = lv_version.
IF sy-subrc NE 0.
MESSAGE x002(fdt_core) WITH iv_version INTO ls_message-text.
message_exception ls_message lt_message cx_fdt_input.
32
CUSTOM EXPRESSION TYPES AND ACTION TYPES A STEP-BY-STEP GUIDE WITH EXAMPLE
ENDIF.
lv_i = lines( lts_version ).
READ TABLE lts_version INDEX lv_i ASSIGNING <ls_version>.
IF <ls_version>-version EQ lv_version.
*
when we have the last version we can read from the buffer
IF mv_ms_buffer_loaded EQ abap_false.
*
load the buffer with the last version
ms_buffer
= load_buffer_db( ).
mv_ms_buffer_loaded = abap_true.
ENDIF.
rs_buffer = ms_buffer.
ELSE.
*
requested version has to be loaded from DB
rs_buffer = load_buffer_db( lv_version ).
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
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:
DATA: lo_persistence TYPE REF TO if_fdt_persistence,
ls_actn_6000
TYPE fdt_actn_6000s,
ls_parameter
TYPE if_fdt_actn_email=>s_parameter.
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( ).
= 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.
CONCATENATE LINES OF ms_buffer-t_recipient INTO ls_actn_6000-recipients
SEPARATED BY space.
lo_persistence->write_single( iv_tabname = gc_actn_6000
is_value
= ls_actn_6000 ).
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
7.5.2 IF_FDT_ACTN_EMAIL=>GET_RECIPIENTS
DATA ls_buffer TYPE s_buffer.
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
DATA ls_buffer TYPE s_buffer.
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
DATA ls_buffer TYPE s_buffer.
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
7.5.6 IF_FDT_ACTN_EMAIL=>SET_RECIPIENTS
DATA: ls_buffer
TYPE s_buffer,
lt_recipient LIKE it_recipient.
ls_buffer = load_buffer( ).
CHECK ls_buffer-t_recipient NE it_recipient. ">>>
* remove empty lines
lt_recipient = it_recipient.
DELETE lt_recipient WHERE table_line IS INITIAL.
ls_buffer-t_recipient = lt_recipient.
set_buffer( ls_buffer ).
notify_change( ).
7.5.7 IF_FDT_ACTN_EMAIL=>SET_PARAMETERS
DATA: ls_buffer
ls_parameter
lts_parameter
ls_msg
lt_msg
lv_unknown
TYPE s_buffer,
TYPE if_fdt_actn_email=>s_parameter,
TYPE if_fdt_actn_email=>ts_parameter,
TYPE if_fdt_types=>s_message,
TYPE if_fdt_types=>t_message,
TYPE abap_bool.
ls_buffer = load_buffer( ).
CHECK ( its_message_parameter
its_message_parameter
( its_recipient_parameter
its_recipient_parameter
IS
NE
IS
NE
SUPPLIED AND
ls_buffer-ts_message_parameter ) OR
SUPPLIED AND
ls_buffer-ts_rec_parameter ).
36
CUSTOM EXPRESSION TYPES AND ACTION TYPES A STEP-BY-STEP GUIDE WITH EXAMPLE
7.5.8 IF_FDT_ACTN_EMAIL=>SET_SUBJECT
DATA: ls_buffer TYPE s_buffer.
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
38
Note
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.
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.
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.
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:
DATA: lo_email TYPE REF TO cl_fdt_actn_email,
ls_buffer TYPE s_buffer.
FIELD-SYMBOLS: <ls_parameter> TYPE if_fdt_actn_email=>s_parameter.
Adapt the class name to create a copy with the correct type:
lo_email ?= super->copy( iv_deep = iv_deep
iv_application_id = iv_application_id ).
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 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
When another application is provided (IV_APPLICATION_ID), the copied objects are created in this
application (with reference to this application).
* copy the attributes of this class
ls_buffer = load_buffer( ).
LOOP AT ls_buffer-ts_message_parameter ASSIGNING <ls_parameter>.
<ls_parameter>-parameter_id = copy_on_request(
iv_id
iv_deep
iv_application_id
= <ls_parameter>-parameter_id
= iv_deep
= iv_application_id ).
ENDLOOP.
LOOP AT ls_buffer-ts_rec_parameter ASSIGNING <ls_parameter>.
<ls_parameter>-parameter_id = copy_on_request(
iv_id
iv_deep
iv_application_id
= <ls_parameter>-parameter_id
= iv_deep
= iv_application_id ).
ENDLOOP.
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:
DATA lo_persistence TYPE REF TO if_fdt_persistence.
super->transport( iv_transport_request = iv_transport_request ).
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 selfimplemented expression types.
o
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
IV_1ST_VRS_TMSTMP
Importing
IV_2ND_VRS_TMSTMP
Importing
IV_SUB_OBJ_1ST_VRS_TMSTMP
Importing
The first timestamp for the comparison of the subobject changes. If initial, it implies the second
timestamp, which has been supplied, is the first
version of the sub-object.
IV_SUB_OBJ_2ND_VRS_TMSTMP
Importing
The second timestamp for the comparison of the subobject changes. Together the first and second
timestamps define the range between which the
changes in the sub-objects has to be analyzed. The
changes are retrieved for the second timestamp of the
parent object.
IV_COMPARE_ONLY_SUB_OBJECT
Importing
IV_SUPERIOR_ID
Importing
IV_DETAILED
Importing
ETS_PROCESSING_CHANGE
Exporting
ETS_NON_PROCESSING_CHANGE
Exporting
CTS_CHANGE_TIMESLICE
Changing
CTS_CHANGE_SUMMARY
Changing
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.
PROCESS
GENERATE_PROCESS
IS_GENERATING
A successful check is required to activate an object. The result of the method is a list of information,
warnings, or error messages.
This method is implemented to reuse the specific check methods that are 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 is as follows:
DATA: ls_msg
TYPE if_fdt_types=>s_message,
lt_msg
TYPE if_fdt_types=>t_message,
lt_recipient TYPE if_fdt_actn_email=>t_recipient,
lv_body
TYPE if_fdt_actn_email=>body,
lv_subject
TYPE if_fdt_actn_email=>subject,
lts_rec_param TYPE if_fdt_actn_email=>ts_parameter,
ls_rec_param TYPE if_fdt_actn_email=>s_parameter,
lts_msg_param TYPE if_fdt_actn_email=>ts_parameter,
ls_msg_param TYPE if_fdt_actn_email=>s_parameter.
rt_message = super->check( iv_activation_check ).
*
*
*
*
IV_ACTIVATION_CHECK set to
objects has to be included
IV_ACTIVATION_CHECK set to
objects has to be included
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 ).
* No initial parameter ids in the param tables
LOOP AT lts_msg_param INTO ls_msg_param WHERE parameter_id IS INITIAL.
MESSAGE e321(fdt_expressions) WITH 'message body'(005) ls_msg_paramposition INTO ls_msg-text.
append_message ls_msg rt_message.
ENDLOOP.
LOOP AT lts_rec_param INTO ls_rec_param WHERE parameter_id IS INITIAL.
MESSAGE e321(fdt_expressions) WITH 'recipients'(006) ls_rec_paramposition INTO ls_msg-text.
append_message ls_msg rt_message.
ENDLOOP.
43
CUSTOM EXPRESSION TYPES AND ACTION TYPES A STEP-BY-STEP GUIDE WITH EXAMPLE
CHECK_RECIPIENTS
CHECK_PARAMETERS
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.
DATA: lv_obj_type
TYPE if_fdt_types=>object_type,
lts_msg_parameter TYPE if_fdt_actn_email=>ts_parameter,
lts_rec_parameter TYPE if_fdt_actn_email=>ts_parameter,
ls_parameter
TYPE if_fdt_actn_email=>s_parameter.
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
IMPORTING
iv_timestamp = iv_timestamp
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.
LOOP AT lts_rec_parameter INTO ls_parameter WHERE parameter_id IS NOT INITIAL.
CLEAR lv_obj_type.
cl_fdt_factory=>get_id_information(
EXPORTING iv_id
= ls_parameter-parameter_id
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
DATA: lv_obj_type
TYPE if_fdt_types=>object_type,
lts_msg_parameter TYPE if_fdt_actn_email=>ts_parameter,
lts_rec_parameter TYPE if_fdt_actn_email=>ts_parameter,
ls_parameter
TYPE if_fdt_actn_email=>s_parameter.
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
IMPORTING
iv_timestamp = iv_timestamp
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.
LOOP AT lts_rec_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.
The result of TO_STRING for a constant expression with a value returns the value of the constant.
The result of TO_STRING for a case expression gives you a basic idea about the results for different
test parameter values.
There are two modes for the TO_STRING (see constants IF_FDT_CONSTANTS => GC_TO_STRING*).
46
CUSTOM EXPRESSION TYPES AND ACTION TYPES A STEP-BY-STEP GUIDE WITH EXAMPLE
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:
DATA:
ls_msg
TYPE if_fdt_types=>s_message,
lt_msg
TYPE if_fdt_types=>t_message,
lt_recipient TYPE if_fdt_actn_email=>t_recipient,
lv_body
TYPE if_fdt_actn_email=>body,
lv_subject
TYPE if_fdt_actn_email=>subject,
lts_rec_param TYPE if_fdt_actn_email=>ts_parameter,
ls_rec_param TYPE if_fdt_actn_email=>s_parameter,
lts_msg_param TYPE if_fdt_actn_email=>ts_parameter,
ls_msg_param TYPE if_fdt_actn_email=>s_parameter.
IV_ACTIVATION_CHECK set to
objects has to be included
IV_ACTIVATION_CHECK set to
objects has to be included
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 ).
* No initial parameter ids in the param tables
LOOP AT lts_msg_param INTO ls_msg_param WHERE parameter_id IS INITIAL.
MESSAGE e321(fdt_expressions) WITH 'message body'(005) ls_msg_paramposition INTO ls_msg-text.
append_message ls_msg rt_message.
ENDLOOP.
LOOP AT lts_rec_param INTO ls_rec_param WHERE parameter_id IS INITIAL.
MESSAGE e321(fdt_expressions) WITH 'recipients'(006) ls_rec_paramposition INTO ls_msg-text.
append_message ls_msg rt_message.
ENDLOOP.
* body and subject both must not be initial.
IF lv_body IS INITIAL AND lv_subject IS INITIAL.
MESSAGE e311(fdt_expressions) INTO ls_msg-text.
append_message ls_msg rt_message.
ENDIF.
48
CUSTOM EXPRESSION TYPES AND ACTION TYPES A STEP-BY-STEP GUIDE WITH EXAMPLE
CHECK_RECIPIENTS
CHECK_PARAMETERS
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
IO_CONTEXT
Context object
IV_TIMESTAMP
IO_PROCESSOR
IO_TRACE
RO_RESULT
Result object
CX_FDT
Exception handling
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.
DATA: lo_message
lx_bcs
lr_data
lv_id
ls_buffer
lv_value
lv_main_doc
lv_param
lt_message
ls_message
ls_parameter
lv_rec_trace
lo_do_type
lo_typedescr
DATA: lv_msg_1
lv_msg_2
50
TYPE
TYPE
TYPE
TYPE
TYPE
TYPE
TYPE
TYPE
TYPE
TYPE
TYPE
TYPE
TYPE
TYPE
TYPE
TYPE
REF TO cl_bcs_message,
REF TO cx_bcs,
REF TO data,
if_fdt_types=>id,
s_buffer,
string,
string,
string,
if_fdt_types=>t_message,
if_fdt_types=>s_message,
if_fdt_actn_email=>s_parameter,
string,
if_fdt_types=>data_object_type,
REF TO cl_abap_typedescr.
string,
string,
CUSTOM EXPRESSION TYPES AND ACTION TYPES A STEP-BY-STEP GUIDE WITH EXAMPLE
lv_msg_3
lv_msg_4
TYPE string,
TYPE string.
FIELD-SYMBOLS: <lv_string>
<lv_value>
<la_data>
<lt_data>
<ls_recipient>
TYPE
TYPE
TYPE
TYPE
TYPE
string,
any,
any,
ANY TABLE,
LINE OF s_buffer-t_recipient.
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.
LOOP AT ls_buffer-ts_message_parameter INTO ls_parameter.
CONCATENATE '&' ls_parameter-position INTO lv_param.
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 ).
ASSIGN lr_data->* TO <la_data>.
lv_value = get_string_from_data( <la_data> ).
REPLACE ALL OCCURRENCES OF lv_param IN ls_buffer-subject WITH lv_value.
REPLACE ALL OCCURRENCES OF lv_param IN ls_buffer-body WITH lv_value.
ENDLOOP.
REPLACE ALL OCCURRENCES OF '\&&' IN ls_buffer-subject WITH '&&'.
REPLACE ALL OCCURRENCES OF '\&&' IN ls_buffer-body WITH '&&'.
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 ).
write_trace_info_4 '221' lv_msg_1 space lv_msg_2 space lv_msg_3 space
lv_msg_4 space.
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.
ro_result = create_and_set_result( iv_timestamp = iv_timestamp ).
process_followup_actions( io_context
iv_timestamp
io_processor
io_result
=
=
=
=
io_context
iv_timestamp
io_processor
ro_result ).
53
CUSTOM EXPRESSION TYPES AND ACTION TYPES A STEP-BY-STEP GUIDE WITH EXAMPLE
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.
54
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.
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.
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.
We discourage using the code composer (CL_CMP_COMPOSER) based on performance.
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
IV_VARIABLE_NAME
IV_TIMESTAMP
Generation timestamp
IO_GENERATION_MNGR
ET_SOURCE_CODE
Generated coding
Code Example
Data definition for mail body
lo_mail_body_do->generate_create_data_ref(
EXPORTING iv_variable_name
=
iv_timestamp
=
io_generation_mngr =
IMPORTING et_source_code
=
lv_mail_body_name
lv_timestamp
io_generation_mngr
lt_data_def_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
IV_VARIABLE_NAME_SOURCE
IO_TARGET_DATA_OBJECT
IV_VARIABLE_NAME_TARGET
IV_TIMESTAMP
Generation timestamp
IO_GENERATION_MNGR
ET_SOURCE_CODE
Generated coding
Code Example
Conversion from temporary result to result:
lo_tmp_result_do->generate_convert_to(
EXPORTING iv_variable_name_source
io_target_data_object
iv_variable_name_target
iv_timestamp
io_generation_mngr
IMPORTING et_source_code
=
=
=
=
=
=
lv_tmp_result_name
lo_result_do
lv_result_do_name
lv_timestamp
io_generation_mngr
lt_conv_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:
56
Parameter
Description
IV_DOBJ_ID
IV_SOURCE_NAME
IV_TARGET_NAME
IV_TIMESTAMP
Generation timestamp
IV_USE_DOBJ_NAME_S
IV_USE_DOBJ_NAME_T
IV_SOURCE_DDIC_NAME
ITS_ID_NAME
ET_SOURCE_CODE
Generated coding
CUSTOM EXPRESSION TYPES AND ACTION TYPES A STEP-BY-STEP GUIDE WITH EXAMPLE
Code Example
Move from data of an exporting parameter after a static method call:
Cl_fdt_expr_services=>generate_move_from_external(
EXPORTING iv_dobj_id
iv_source_name
iv_target_name
iv_timestamp
IMPORTING et_source_code
=
=
=
=
=
lv_dobj_id
iv_source_do_name
iv_target_do_name
lv_timestamp
lt_move_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
IV_DOBJ_ID
IV_SOURCE_NAME
IV_TARGET_NAME
IV_TIMESTAMP
Generation timestamp
IV_TARGET_DDIC_NAME
IV_USE_DOBJ_NAME
IV_USE_DNAME_IN_TGT
ITS_ID_NAME
ET_SOURCE_CODE
Generated coding
Code Example
Move from data of an importing parameter after a static method call:
Cl_fdt_expr_services=>generate_move_to_external(
EXPORTING iv_dobj_id
iv_source_name
iv_target_name
iv_timestamp
IMPORTING et_source_code
=
=
=
=
=
lv_dobj_id
iv_source_do_name
iv_target_do_name
lv_timestamp
lt_move_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
Parameter
Description
IV_ID
EV_NAME
EV_UNKNOWN
Code Example
Get the context name for a recipient:
Cl_fdt_expr_services=>generate_get_context_name(
EXPORTING iv_id
IMPORTING ev_name
ev_unknown
11.2.6
= lv_recipient_id
= lv_recipient_name
= lv_unknown
).
CL_FDT_EXPR_SERVICES=>
GEN_GET_NEXT_VARIABLE_NAME
Parameter
Description
IV_DESIRED_NAME
RV_EFFECTIVE_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 &&
append lv_line to et_source_code.
58
` TYPE string.`.
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
IV_SYMBOLIC_NAME
RV_GENERATION _NAME
Code Example
Get the trace object name to clear its work area:
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.
11.2.8
CL_FDT_EXPR_SERVICES=> GEN_GENERATE_TRACE
This method returns if the generation takes place with lean trace or without.
Explanation of the parameter:
Parameter
Description
EV_GENERATE_TRACE
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
Parameter
Description
IV_FUNCTION_ID
Function ID
IV_EXPRESSION_ID
Calling expression ID
IV_VARIABLE_NAME
IV_CREATE_VARIABLE
IV_TIMESTAMP
Generation timestamp
IV_TEST_PARAMETER
Test parameter ID
ITS_RANGE
Range table
IV_CASE_SENSITIVITY
IV_IS_SV_RANGE
ET_SOURCE_CODE
EV_DEEP_TRACED
CTS_USED_CONTEXT_ID
Code Example
Implicit range for a condition inside an expression:
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
Parameter
Description
IV_VARIABLE_NAME
IV_CREATE_VARIABLE
IS_VALUE
Value
IV_TIMESTAMP
Generation timestamp
ET_SOURCE_CODE
EV_DIRECT_RESULT_NAME
Code Example
Direct value for a default result inside an expression:
cl_fdt_expr_services=>generate_simple_value_process(
EXPORTING iv_variable_name
=
iv_create_variable =
is_value
=
iv_timestamp
=
IMPORTING et_source_code
=
APPEND LINES OF lt_def_res_code TO et_source_code.
lv_def_res_name
abap_false
s_default_result_value
lv_timestamp
lt_def_res_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
IV_VARIABLE_NAME
IV_CREATE_VARIABLE
IV_TIMESTAMP
Generation timestamp
IO_GENERATION_MNGR
IV_CALLING_EXPR_ID
IV_TARGET_DO_ID
IV_TARGET_ELEMENT_TYPE
ET_SOURCE_CODE
EV_DIRECT_RESULT_NAME
EV_DEEP_TRACED
EV_CONTEXT_OR_CONST
CUSTOM EXPRESSION TYPES AND ACTION TYPES A STEP-BY-STEP GUIDE WITH EXAMPLE
CTS_USED_CONTEXT_ID
Code Example
Generate parameter code for an email parameter:
generate_get_value( EXPORTING iv_function_id
iv_id
iv_variable_name
iv_create_variable
iv_timestamp
io_generation_mngr
iv_calling_expr_id
IMPORTING et_source_code
ev_direct_result_name
CHANGING cts_used_context_id
APPEND LINES OF lt_parm_code TO et_source_code.
=
=
=
=
=
=
=
=
=
=
lv_function_id
<ls_para>-parameter_id
lv_parm_var_name
abap_true
lv_timestamp
io_generation_mngr
mv_id
lt_parm_code
lv_direct_parm_name
cts_used_context_id ).
11.2.12 CL_FDT_EXPRESSION=>
GENERATE_TRACE_SUB_EXPRESSION
This method generates the coding for tracing any subexpressions.
Explanation of the parameters:
Parameter
Description
IV_POSITION
Trace position
IV_POSITION_NAME
IV_RESULT_NAME
IV_ID
Subexpression ID
IV_PARENT_ID
Expression ID
IV_WITH_VALUE
IV_SKIP_TRUE
IV_SKIP_FALSE
IV_IS_SV_RANGE
ET_SOURCE_CODE
Code Example
Generate trace coding for an embedded procedure call:
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.
For more examples, check out the usages of
CL_FDT_EXPRESSION=>GENERATE_TRACE_SUB_EXPRESSION in your system.
Recommendation
The names of variables you define need to be unique in the coding. Use method
CL_FDT_EXPR_SERVICES=>GEN_GET_NEXT_VARIABLE_NAME to get the final
variable name.
Your expression might be called in a loop. Therefore the variables you declared might
have a value in the second loop passing. Clear variable if they are not set to a value.
If your expression allows calling other expressions or data objects, ensure the types of
the data objects fit the data types you expect or convert the data object to the type you
require.
(Use method IF_FDT_DATA_OBJECT->GENERATE_CONVERT_TO.)
63
CUSTOM EXPRESSION TYPES AND ACTION TYPES A STEP-BY-STEP GUIDE WITH EXAMPLE
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:
Parameter
Type
Typing
Method
Associated Type
Description
IO_LEAN_TRACE_
HELPER
Importing
TYPE REF TO
CL_FDT_WD_LEAN_
TRACE_HELPER
IV_TIMESTAMP
Importing
TYPE
IF_FDT_TYPES=>
TIMESTAMP
IS_RECORD
Importing
TYPE
IF_FDT_LEAN_TRACE
=>S_RECORD
CS_NODE
Changing
TYPE
FDTS_WD_TRACE_
MODEL
Code Example
METHOD CHANGE_TRACE_NODE.
DATA: lv_name TYPE string.
FIELD-SYMBOLS: <lv_bool> TYPE abap_bool.
64
CUSTOM EXPRESSION TYPES AND ACTION TYPES A STEP-BY-STEP GUIDE WITH EXAMPLE
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 interface of the method must contain the following parameters:
Parameter
Type
Typing
Method
Associated Type
Description
IO_LEAN_TRACE_
HELPER
Importing
TYPE REF
TO
CL_FDT_WD_LEAN_
TRACE_HELPER
IS_PARENT_NODE
Importing
TYPE
FDTS_WD_TRACE_
MODEL
ET_NODE
Exporting
TYPE
CL_FDT_WD_LEAN_
TRACE_MODEL=>
TS_TRACE_VALUE
Child nodes
CTS_RECORD
Changing
TYPE
IF_FDT_LEAN_TRACE
=>TS_RECORD
The following example illustrates how to sort nodes and extend their default names.
Note
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
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.
DATA: lv_body
TYPE if_fdt_actn_email=>body,
lt_recpt
TYPE if_fdt_actn_email=>t_recipient,
lv_subject
TYPE if_fdt_actn_email=>subject,
lts_msg_parameter TYPE if_fdt_actn_email=>ts_parameter,
lts_rec_parameter TYPE if_fdt_actn_email=>ts_parameter.
super->if_fdt_data_exchange_internal~export_xml( iv_timestamp = iv_timestamp
io_parent
= io_parent ).
* Add the Email Recipient Information to xml document.
lt_recpt = if_fdt_actn_email~get_recipients( iv_timestamp ).
convert_abap_to_xml(
io_parent
= io_parent
iv_name
= 'RECIPIENTS'
iv_namespace_prefix = if_fdt_data_exchange=>gc_xml_namespace_prefix
ia_abap
= lt_recpt ).
* Add the Email Body Information to xml document.
lv_body = if_fdt_actn_email~get_body( iv_timestamp ).
convert_abap_to_xml(
io_parent
= io_parent
iv_name
= 'BODY'
iv_namespace_prefix = if_fdt_data_exchange=>gc_xml_namespace_prefix
ia_abap
= lv_body ).
* and so on for the rest
ENDMETHOD.
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
iv_name
iv_namespace_prefix
ia_abap
END-OF-DEFINITION.
=
=
=
=
io_parent
&1
gc_my_namespace_prefix
&2 ).
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:
export_xml: 'RECIPIENTS' ls_buffer-t_recipient,
'BODY'
ls_buffer-body,
'SUBJECT'
ls_buffer-subject,
...
You should use your own namespace for the XML elements, as this will prevent possible errors due to
double definition. It is useful to define a global constant (see gc_my_namespace in the previous coding) that
contains your namespace prefix. You can choose whatever you want for a namespace prefix, (for example,
CUST_EXTY1). You have to pass this namespace with exporting parameter es_namespace:
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 dont have to do this, when importing objects without an ID (for example, a simple
value of type cl_fdt_expr_sv=>s_value).
DATA: lv_no_element
ls_msg_parameter
ls_rec_parameter
ls_buffer
TYPE
TYPE
TYPE
TYPE
abap_bool,
if_fdt_actn_email=>s_parameter,
if_fdt_actn_email=>s_parameter,
s_buffer.
super->if_fdt_data_exchange_internal~import_xml( io_parent ).
* Import the Email Body from XML
convert_xml_to_abap( EXPORTING io_parent
= io_parent
iv_name
= 'BODY'
iv_namespace_prefix = gc_my_namespace_prefix
IMPORTING ea_abap
= ls_buffer-body
ev_no_element
= lv_no_element ).
IF lv_no_element EQ abap_true.
ls_msg-msgv1 = cx_fdt=>get_object_description( mv_id ).
* Message: No &1 supplied for &2
MESSAGE x302(fdt_core) WITH 'BODY' ls_msg-msgv1 INTO ls_msg-text.
message_exception ls_msg lt_msg cx_fdt_input.
ENDIF.
* Import the Email Recipients from XML
convert_xml_to_abap( EXPORTING io_parent
= io_parent
iv_name
= 'RECIPIENTS'
iv_namespace_prefix = gc_my_namespace_prefix
IMPORTING ea_abap
= ls_buffer-t_recipient
ev_no_element
= lv_no_element ).
IF lv_no_element EQ abap_true.
ls_msg-msgv1 = cx_fdt=>get_object_description( mv_id ).
* Message: No &1 supplied for &2
MESSAGE x302(fdt_core) WITH 'RECIPIENTS' ls_msg-msgv1 INTO ls_msg-text.
message_exception ls_msg lt_msg cx_fdt_input.
68
CUSTOM EXPRESSION TYPES AND ACTION TYPES A STEP-BY-STEP GUIDE WITH EXAMPLE
ENDIF.
* Import the Email Subject from XML
convert_xml_to_abap( EXPORTING io_parent
= io_parent
iv_name
= 'SUBJECT'
iv_namespace_prefix = gc_my_namespace_prefix
IMPORTING ea_abap
= ls_buffer-subject
ev_no_element
= lv_no_element ).
IF lv_no_element EQ abap_true.
ls_msg-msgv1 = cx_fdt=>get_object_description( mv_id ).
* Message: No &1 supplied for &2
MESSAGE x302(fdt_core) WITH 'SUBJECT' ls_msg-msgv1 INTO ls_msg-text.
message_exception ls_msg lt_msg cx_fdt_input.
ENDIF.
* Set the paramters
convert_xml_to_abap( EXPORTING io_parent
= io_parent
iv_name
= 'MESSAGE_PARAMETERS'
iv_namespace_prefix = gc_my_namespace_prefix
IMPORTING ea_abap
= ls_buffer-ts_message_parameter
ev_no_element
= lv_no_element ).
IF lv_no_element EQ abap_true.
ls_msg-msgv1 = cx_fdt=>get_object_description( mv_id ).
* Message: No &1 supplied for &2
MESSAGE x302(fdt_core) WITH 'MESSAGE_PARAMETERS' ls_msg-msgv1 INTO ls_msg-text.
message_exception ls_msg lt_msg cx_fdt_input.
ENDIF.
convert_xml_to_abap( EXPORTING io_parent
= io_parent
iv_name
= 'RECIPIENT_PARAMETERS'
iv_namespace_prefix = gc_my_namespace_prefix
IMPORTING ea_abap
= ls_buffer-ts_rec_parameter
ev_no_element
= lv_no_element ).
IF lv_no_element EQ abap_true.
ls_msg-msgv1 = cx_fdt=>get_object_description( mv_id ).
* Message: No &1 supplied for &2
MESSAGE x302(fdt_core) WITH 'RECIPIENT_PARAMETERS' ls_msg-msgv1 INTO ls_msg-text.
message_exception ls_msg lt_msg cx_fdt_input.
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:
<!ELEMENT CUST_EXTY1:PARAMETER1
(#PCDATA)>
<!ELEMENT CUST_EXTY1:PARAMETER2
<!ELEMENT CUST_EXTY1:SIMPLE_VALUE
(#PCDATA)>
(CUST_EXTY1:ELEMENT_TYPE?, CUST_EXTY1:VALUE?,
CUST_EXTY1:SUPPLEMENT?,
CUST_EXTY1:NONE_AP?)>
<!ELEMENT CUST_EXTY1:DEMO_TABLE
(CUST_EXTY1:ITEM| CUST_EXTY1:item)*>
In the XML, there will be one XML element called PARAMETER1, which has its ID embedded. It has
no deeper structure. Therefore the embedded data inside this XML element is defined as #PCDATA.
The simple value is different because the SIMPLE_VALUE XML element consists of several other
XML elements since its type is CL_FDT_EXPR_SV=>S_VALUE.
These are as follows:
70
ELEMENT_TYPE
VALUE
SUPPLEMENT
NONE_AP
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:
<!ELEMENT CUST_EXTY1:ITEM
(CUST_EXTY1:ELEMENT_TYPE?, CUST_EXTY1:VALUE?,
CUST_EXTY1:SUPPLEMENT?, CUST_EXTY1:NONE_AP?)>
<!ELEMENT CUST_EXTY1:item
(CUST_EXTY1:ELEMENT_TYPE?, CUST_EXTY1:VALUE?,
CUST_EXTY1:SUPPLEMENT?, CUST_EXTY1:NONE_AP?)>
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.
<!ELEMENT CUST_EXTY1:ELEMENT_TYPE
(#PCDATA)>
<!ELEMENT CUST_EXTY1:VALUE
(#PCDATA)>
<!ELEMENT CUST_EXTY1:SUPPLEMENT
(#PCDATA)>
<!ELEMENT CUST_EXTY1:NONE_AP
(#PCDATA)>
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-XMLelement 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
DATA: lo_outer_cp
= 'PARAMETER1'
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:
io_content_particle->add_content_particle( content_particle = lo_outer_cp ).
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:
DATA: lo_element_descr
).
grouping
= if_ixml_content_particle=>co_sequence ).
lo_element_descr->set_occurrence(
occurs
= if_ixml_content_particle=>co_one
).
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.
<!ELEMENT CUST_EXTY1:PARAMETER1
(#PCDATA)>
To achieve this, you have to create an empty particle and add it as content to the element description object.
DATA: lo_cp_brackets
72
CUSTOM EXPRESSION TYPES AND ACTION TYPES A STEP-BY-STEP GUIDE WITH EXAMPLE
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.
DATA: lo_cp_element
lo_cp_element = io_doc_type->create_content_particle(
name
= '#PCDATA'
grouping
= if_ixml_content_particle=>co_sequence
occurrence = if_ixml_content_particle=>co_one ).
Note
If you do not pass a prefix parameter the particle is created with its name (in this example,
#PCDATA).
Now add LO_CP_ELEMENT as content to LO_CP_BRACKETS, which will be added as content to
LO_ELEMENT_DESCR.
lo_cp_brackets->add_content_particle( content_particle = lo_cp_element ).
lo_element_descr->add_content_particle( content_particle = lo_cp_brackets ).
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.
io_doc_type->append_child( new_child = lo_element_descr ).
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
prefix
= 'SIMPLE_VALUE
= cl_fdt_actn_email=>gc_my_namespace_prefix
grouping
= if_ixml_content_particle=>co_sequence
occurrence = if_ixml_content_particle=>co_one ).
io_content_particle->add_content_particle( content_particle = lo_outer_cp ).
lo_element_descr = io_doc_type->create_element_decl(
name
= 'SIMPLE_VALUE'
prefix = cl_fdt_actn_email=>gc_my_namespace_prefix ).
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
).
* -> create anonymous content (brackets-)particle: (...)
lo_cp_brackets = io_doc_type->create_content_particle(
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
prefix
grouping
occurrence
=
=
=
=
'ELEMENT_TYPE'
cl_fdt_actn_email=>gc_my_namespace_prefix
if_ixml_content_particle=>co_sequence
if_ixml_content_particle=>co_zero_or_one ).
=
=
=
=
'VALUE'
cl_fdt_actn_email=>gc_my_namespace_prefix
if_ixml_content_particle=>co_sequence
if_ixml_content_particle=>co_zero_or_one ).
=
=
=
=
'SUPPLEMENT'
cl_fdt_actn_email=>gc_my_namespace_prefix
if_ixml_content_particle=>co_sequence
if_ixml_content_particle=>co_zero_or_one ).
=
=
=
=
'NONE_AP'
cl_fdt_actn_email=>gc_my_namespace_prefix
if_ixml_content_particle=>co_sequence
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
if_ixml_content_particle=>co_choice
Occurrence
13.3.2
Constant
Result
if_ixml_content_particle=>co_one
if_ixml_content_particle=>co_one_or_more
if_ixml_content_particle=>co_zero_or_more
if_ixml_content_particle=>co_zero_or_one
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.
DATA: ls_element_domain TYPE if_fdt_data_exchange_external=>s_element_domain,
lt_element_domain TYPE if_fdt_data_exchange_external=>t_element_domain.
Define the DDIC element to which the element ACTIVITY is bounded
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.
DATA: ls_version_change
ls_message
TYPE if_fdt_data_exchange_external=>s_xml_version_change,
TYPE if_fdt_types=>s_message.
ls_version_change-xml_version
ls_message-msgty
ls_message-text
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.
DATA: lo_ixml
lo_document
lo_node
lo_ref_element
lo_new_element
lo_element
lv_value
ls_value
lt_value
TYPE
TYPE
TYPE
TYPE
TYPE
TYPE
TYPE
TYPE
TYPE
REF TO if_ixml,
REF TO if_ixml_document,
REF TO if_ixml_node,
REF TO if_ixml_element,
REF TO if_ixml_element,
REF TO if_ixml_element,
string,
if_fdt_actn_email=>recipient,
if_fdt_actn_email=>t_recipient.
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
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
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
1. Create your own transportable application (like FDT_SYSTEM).
2. Create your own action types and expression types.
3. Change the Access Level to Global so the action type or expression type can be used by objects
from other applications.
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
fdt_demo_report_actn_email.
DATA: lo_factory
lo_email
lo_function
lt_message
lo_result
lr_data
lv_body
lv_recipient
lt_recipient
lv_subject
lo_trace
lo_lean_trace
TYPE
TYPE
TYPE
TYPE
TYPE
TYPE
TYPE
TYPE
TYPE
TYPE
TYPE
TYPE
REF TO if_fdt_factory,
REF TO if_fdt_actn_email,
REF TO if_fdt_function,
if_fdt_types=>t_message,
REF TO if_fdt_result,
REF TO data,
if_fdt_actn_email=>body,
if_fdt_actn_email=>recipient,
if_fdt_actn_email=>t_recipient,
if_fdt_actn_email=>subject,
REF TO if_fdt_trace,
REF TO if_fdt_lean_trace.
lo_factory = cl_fdt_factory=>if_fdt_factory~get_instance(
if_fdt_constants=>gc_application_tmp ).
* create the email action
lo_email ?= lo_factory->get_expression(
iv_expression_type_id = if_fdt_actn_email=>gc_exty_email ).
lo_email->if_fdt_transaction~enqueue( ).
lo_email->if_fdt_admin_data~set_name( 'DEMO_ACTN_MESSAGE_LOG' ).
* the email action specific attributes
lv_recipient = '[email protected]'.
APPEND lv_recipient TO lt_recipient.
lo_email->set_recipients( lt_recipient ).
lv_subject = 'This is a test of an email action'.
lo_email->set_subject( lv_subject ).
lv_body = 'This is the first test report. When you can see you email it works.'.
lo_email->set_body( lv_body ).
* 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 ).
* activate and save function + email action
lo_function->if_fdt_transaction~activate( EXPORTING iv_deep
= abap_true
IMPORTING et_message = lt_message ).
IF lt_message IS NOT INITIAL.
BREAK-POINT.
RETURN. ">>>
ENDIF.
lo_function->if_fdt_transaction~save( iv_deep
= abap_true ).
lo_function->if_fdt_transaction~dequeue( iv_deep = abap_true ).
lo_function->process( EXPORTING iv_trace_mode = if_fdt_constants=>gc_trace_mode_lean
IMPORTING eo_result
= lo_result
eo_trace
= lo_trace ).
lo_lean_trace ?= lo_trace.
lo_lean_trace->save( ).
80
CUSTOM EXPRESSION TYPES AND ACTION TYPES A STEP-BY-STEP GUIDE WITH EXAMPLE
Component
Description
Web Dynpro
Component
The WD component visualizes and controls (react on user actions) the UI. It is
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 OOclass 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
16.2.1
The WD component has to reimplement the following WD interfaces in the component definition:
FDT_IWD_COMPONENT
FDT_IWD_OBJECT
FDT_IWD_OBJECT_EXTENDED
FDT_IWD_QUERY
16.2.2
The context of the WD component consists of the model context nodes (root node MODEL) and the node
UI_ADJUSTMENT, which is provided by the interface FDT_IWD_OBJECT.
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.
16.2.3
In the WD environment, we cannot use CX_FDT (and its subclasses) because the UI layer in BRF has an
exception hierarchy, which cannot be used in method signatures (unchecked exceptions) due to history
reasons. There is an exception class hierarchy for the WD UI. Its root class is CX_FDT_WD. If you have to
propagate a backend exception (CX_FDT and subclasses), you have to convert the backend exception to
CX_FDT_WD_BACKEND.
Method CL_FDT_WD_SERVICE=>CONVERT_BACKEND_EXCEPTION does the conversion.
If you call a method that can raise CX_FDT (and its subclasses) ensure you either report the exception to the
user or propagate it correctly.
83
CUSTOM EXPRESSION TYPES AND ACTION TYPES A STEP-BY-STEP GUIDE WITH EXAMPLE
= io_controller ).
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:
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
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
CATCH cx_fdt_wd_backend INTO lx_fdt_backend.
lo_msg_manager = wd_this->wd_get_api( )->get_message_manager( ).
cl_fdt_wd_service=>report_exception( io_message_manager = lo_msg_manager
ix_wd_exception
ENDTRY.
84
= lx_fdt_backend ).
CUSTOM EXPRESSION TYPES AND ACTION TYPES A STEP-BY-STEP GUIDE WITH EXAMPLE
16.2.4
Implementation of Interface
FDT_IWD_OBJECT/FDT_IWD_COMPONENT
The following methods make use of additional attributes and methods seen in the Attributes tab from the
COMPONENTCONTROLLER for the WD component FDT_WD_ACTN_EMAIL.
INIT
This method is called by the framework, after the WD component is created.
METHOD INIT .
wd_this->mo_model = io_model.
wd_this->mo_state = io_state.
wd_this->mv_id
= iv_id.
wd_this->mo_model->init( io_context_node = wd_context
io_controller
= wd_this->wd_get_api( ) ).
wd_this->mo_model_cl ?= io_model.
wd_this->gc_usage_type_message = 'USAGE_MESSAGE_VAR'.
wd_this->gc_usage_type_rec
= 'USAGE_REC_VAR'.
DATA: lo_context_node TYPE REF TO if_wd_context_node,
ls_rec
TYPE
wd_this->element_recipients,
lv_string
TYPE
string.
lo_context_node = wd_context->path_get_node( path = `MODEL.RECIPIENTS` ).
lo_context_node->get_static_attributes( IMPORTING static_attributes = ls_rec ).
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' ).
lo_context_node->bind_structure( EXPORTING new_item = ls_rec ).
ENDMETHOD.
85
CUSTOM EXPRESSION TYPES AND ACTION TYPES A STEP-BY-STEP GUIDE WITH EXAMPLE
Parameter
Type
Purpose
IV_ID
Importing
ID of the object
IO_MODEL
Importing
IO_STATE
Importing
CX_FDT_WD
Exception
Initialization failed
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_.
DATA: ls_toolbar
lt_toolbar
TYPE if_fdt_wd_types=>s_toolbar,
TYPE if_fdt_wd_types=>t_toolbar.
ls_toolbar-action = My_Action
ls_toolbar-text = My Test Action
APPEND ls_toolbar TO lt_toolbar.
"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.
The GET_MODEL methods read data from the backend and provide it as (model) context nodes
for the WD component.
The SET_MODEL methods read data from the (model) context nodes and update the backend
accordingly. Each model class must inherit from CL_FDT_WD_MAINTENANCE_MODEL.
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.
16.3.1
The model class for custom action email is CL_FDT_WD_ACTN_EMAIL_MODEL and is inherited from
CL_FDT_WD_MAINTENANCE_MODEL.
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.
DATA lx_fdt
(1)
TRY.
me->mo_actn_email ?= me->mo_factory->get_expression( iv_id = mv_id ).
CATCH cx_fdt INTO lx_fdt.
cl_fdt_wd_service=>convert_backend_exception( ix_fdt = lx_fdt ).
(2)
(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.
DATA: ls_model_node TYPE if_fdt_wd_types=>s_model_node.
* node recipients
ls_model_node-name = gc_model_node_recipients.
ls_model_node-read_only = abap_false.
INSERT ls_model_node INTO TABLE rt_model_node.
(1)
(2)
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.
DATA: lo_model_node
lx_fdt
lt_recipients
lts_rec_param
ls_rec_param
ls_recipients_model
ls_icon
lv_body
lv_subject
lv_text
ls_message_model
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_modelrecipients SEPARATED BY '; '. (4)
lo_model_node->bind_structure( new_item
= ls_recipients_model
(5)
set_initial_elements = iv_initialize_elements ).
...
ENDCASE.
CATCH cx_fdt INTO lx_fdt.
cl_fdt_wd_service=>convert_backend_exception( ix_fdt = lx_fdt ).
ENDTRY.
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 reimplemented 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.
DATA:
lo_nd_model
TYPE
ls_message_model
TYPE
ls_parameter
TYPE
lts_parameter
TYPE
lt_recipients
TYPE
lt_recipients_final TYPE
ls_recipients
LIKE
lt_recipients_model TYPE
ls_recipients_model TYPE
ls_bs_model
TYPE
lx_fdt
TYPE
lv_recipients_model TYPE
lt_plc_hldr
TYPE
lo_query
TYPE
lt_ids
TYPE
lt_token
TYPE
ls_token
TYPE
lv_body
TYPE
lv_message
TYPE
REF TO
if_wd_context_node,
fdts_wd_actn_email_msg_model,
if_fdt_actn_email=>s_parameter,
if_fdt_actn_email=>ts_parameter,
if_fdt_actn_email=>t_recipient,
if_fdt_actn_email=>t_recipient,
LINE OF lt_recipients,
STANDARD TABLE OF fdts_wd_actn_email_recp_model,
fdts_wd_actn_email_recp_model,
fdts_wd_actn_email_bs_model,
REF TO cx_fdt,
string,
match_result_tab,
REF TO if_fdt_query,
REF TO if_fdt_types=>t_object_id,
cl_fdt_actn_email=>ts_token,
cl_fdt_actn_email=>s_token,
string,
string.
DATA: result_tab
TYPE match_result_tab,
ls_result_tab TYPE match_result.
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 ).
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_modelrec_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_modelrec_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_modelrec_3 IS NOT INITIAL..
(3)
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_modelrec_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 DDICtype 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.2
In the majority of cases, you do not have to take care about the dirty state of the maintained object, if the
current maintained object is changed.
The BRFplus UI framework provides this check as an automatic service by tracking the state of your model
nodes. However, this service is not available when there is the need to use a recursive node (displaying
hierarchical data in a tree).
In this case, you are responsible to detect if the user has changed the tree (and its content). To do this with
the minor effort, apply the following pattern:
Use a separate model node for the content (attributes) of the node tree. It has the advantage that
you do not have to check, if the user has changed these node attributes. Of course, when the user
chooses SAVE or switches to another node in the tree you must update the model
(set_model_by_node).
When the user creates or deletes a node, this action calls proper methods in you model class. These
methods (CREATE_NODE) change the tree and have to inform the framework by calling the method
if_fdt_wd_model~set_model_changed( ) to indicate that the model has changed.
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
~GET_TEXT
If you have defined text symbols in your model class, you can
access them with the help of this method.
PUBLISH_MODEL_NODES
INIT
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
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
IS_MODEL_CHANGED
GET_MODEL_NODE_BY_NAME
REFRESH_MODEL
SET_MODEL_CHANGED
Method
Description
SET_NOT_FOUND_TEXT_KEY
GET_MODEL_BY_NODE
SET_MODEL_BY_NODE
UUID (mv_id)
Timestamp (mv_timestamp)
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
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.
The change history is documented in the interface documentation of IF_FDT_UI_DEFINITION.
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.
If you want to create a new BRFplus object within your expression UI, you can do this by implementing the
following steps:
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.
DATA: ls_object_type
TYPE if_fdt_wd_types=>s_object_type_extended.
ls_object_type-type = if_fdt_constants=>gc_object_type_expression.
(1)
wd_comp_controller->fire_create_object_simple_evt(
is_object_type = ls_object_type
(2)
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 ).
wd_this->mo_model->refresh_model( wd_this->wdctx_properties ).
(2)
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
16.5.2
If you want to bind a parameter against an existing BRFplus object within your action / expression UI, you
can use the UI query.
The WD interface FDT_IWD_QUERY provides various methods to query for a specific BRFplus object. After
calling one of those methods, a query dialog is displayed from which the user can choose an object. If the
user has actually chosen an object, your component is notified and the ID of the object is provided.
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:
DATA: lo_comp_factory
(1)
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
).
CATCH cx_fdt_input INTO lx_fdt_input.
cl_fdt_wd_service=>report_exception(
io_message_manager = wd_this->wd_get_api( )->get_message_manager( )
ix_exception
= lx_fdt_input ).
ENDTRY.
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.
The standard object query consists of the following parameters:
Parameter
Type
Description
IO_CALLING_PARAMETER
Importing
Mandatory:
Admin Data Reference of current displayed object
(expression).
IS_OBJECT_TYPE
Importing
IV_APPLICATION_ID
Importing
IV_INITIAL_SEARCH
Importing
IV_TYPE_FIXED
Importing
IV_MULTIPLE_SELECTION
Importing
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.
To receive the selected object(s), implement an event handler.
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.
16.5.3
Object
Description
ELEMENT_QUERY
CONTEXT_QUERY
ADVANCED_QUERY
You can navigate to other objects within your UI. For example, you can create a link to another expression
that is bound to an attribute of your expression type.
To navigate to another object, simply raise the event NAVIGATE_TO_OBJECT and provide the ID of the
object. The event is available in the component controller of your component (implemented in interface
FDT_IWD_OBJECT).
16.5.4
Object Menu
To enable the user to bind a BRFplus object to a parameter, use a link menu by which the user is able to
choose an existing object or to create a new object. The scope of this service is for use within an expression
type UI.
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.
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
Parameter
Type
Description
IO_VIEW
Importing
IV_MENU_ID
Importing
IV_ACTION_HANDLER
Importing
Action (in the view) which handles the object menu actions. You
only need to define one action for all menu items.
IS_OBJECT_TYPE
Importing
IV_ACTION_MODE
Importing
IS_CONFIGURATION
Importing
IV_BOUND_OBJECT_ID
Importing
IV_BIND_ENABLED_PATH
Importing
106
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 =
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:
DATA: ls_action_parameter TYPE if_fdt_wd_object_menu=>s_action_parameter.
***************************************************************************
*retrieve the action parameter to do followup actions.
ls_action_parameter = wd_comp_controller->mo_object_menu>get_action_parameter( wdevent ).
*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.
*user has selected an instance...
*...the instance is provided in ls_action_parameter-object_id
*...the selected object type is provided in ls_action_parameter-object_type
WHEN if_fdt_wd_object_menu=>gc_action_param_obj_selected.
ENDCASE.
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.
16.5.5
Other Services
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&sapclient=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
110
www.sap.com