In this blog you will see how a DDIC Search help can serve as a simple to use data source for a Fiori list report.
Search helps are well known and heavily used to find and select SAP objects. They are part of the DDIC development objects and select data either directly DDIC-table based or code based via an ABAP interface.
Search helps serve as UI elements and are part of SAP GUI or Webdynpro applications. But they can be exposed via SAP Gateway to oDATA/ UI5 interfaces too.
The latter does not only allow to use them as a value help in an UI5 application. The technology can easily be adapted to generate a Fiori List report application in the same way CDS Views are exposed. The result list of a Search help is basically the same as a result list of a CDS select.
The advantage of this approach is that some restrictions of CDS / DDL developments can be overcome and this without deep knowledge of SAP Gateway or UI5 or Javascript. The main additional effort concerns the annotations which are manually defined for the list and the detail screen. This can be done easily via the annotation modeler in SAP WebIDE.
Restrictions of CDS based Fiori list reports
The restrictions that can be solved by this approach compared to a pure CDS based UI are:
◈ Add difficult calculations which cannot be done in CDS or only on the DB layer but are available as function modules (example: purchase order history),
◈ Add data from other sources than the data base (example: SM50, SM04, SM12 lists or file contents or RFC results),
◈ Avoid performance issues in CDS especially before HANA which can be solved by sequential selects in ABAP.
The approach can roughly be described as follows:
◈ Create (or reuse an existing) DDIC Search help.
This Search help can contain a Search help exit which means the selection can be done by your own ABAP coding!
◈ Create a gateway object and import the Search help
◈ Don’t forget some flags to make the resulting oDATA entity searchable
◈ Generate the gateway runtime objects
◈ Add some coding for the defaultSearchElement
◈ Add the service definition
◈ Create a new Fiori element report in SAP WebIDE based on the service
◈ Add a local annotation file for Select fields, List fields, Detail fields, Header fields
Here is an example tutorial which displays the list of the current users (like transaction SM04) in a Fiori elements list.
Please follow the step-by-step guide in detail:
1. Define an elementary Search help and develop a Search help exit
SE11 -> Search help:
Why use a DDIC search help for a Fiori list report?
Search helps are well known and heavily used to find and select SAP objects. They are part of the DDIC development objects and select data either directly DDIC-table based or code based via an ABAP interface.
Search helps serve as UI elements and are part of SAP GUI or Webdynpro applications. But they can be exposed via SAP Gateway to oDATA/ UI5 interfaces too.
The latter does not only allow to use them as a value help in an UI5 application. The technology can easily be adapted to generate a Fiori List report application in the same way CDS Views are exposed. The result list of a Search help is basically the same as a result list of a CDS select.
The advantage of this approach is that some restrictions of CDS / DDL developments can be overcome and this without deep knowledge of SAP Gateway or UI5 or Javascript. The main additional effort concerns the annotations which are manually defined for the list and the detail screen. This can be done easily via the annotation modeler in SAP WebIDE.
Restrictions of CDS based Fiori list reports
The restrictions that can be solved by this approach compared to a pure CDS based UI are:
◈ Add difficult calculations which cannot be done in CDS or only on the DB layer but are available as function modules (example: purchase order history),
◈ Add data from other sources than the data base (example: SM50, SM04, SM12 lists or file contents or RFC results),
◈ Avoid performance issues in CDS especially before HANA which can be solved by sequential selects in ABAP.
What is the technical approach ?
The approach can roughly be described as follows:
◈ Create (or reuse an existing) DDIC Search help.
This Search help can contain a Search help exit which means the selection can be done by your own ABAP coding!
◈ Create a gateway object and import the Search help
◈ Don’t forget some flags to make the resulting oDATA entity searchable
◈ Generate the gateway runtime objects
◈ Add some coding for the defaultSearchElement
◈ Add the service definition
◈ Create a new Fiori element report in SAP WebIDE based on the service
◈ Add a local annotation file for Select fields, List fields, Detail fields, Header fields
Here is an example tutorial which displays the list of the current users (like transaction SM04) in a Fiori elements list.
Please follow the step-by-step guide in detail:
1. Define an elementary Search help and develop a Search help exit
SE11 -> Search help:
Add a new function module ZZ_SHLP_EXIT_SM04 with the following coding and parameters:
FUNCTION zz_shlp_exit_sm04.
*"----------------------------------------------------------------------
*"*"Local Interface:
*" TABLES
*" SHLP_TAB TYPE SHLP_DESCR_TAB_T
*" RECORD_TAB STRUCTURE SEAHLPRES
*" CHANGING
*" VALUE(SHLP) TYPE SHLP_DESCR_T
*" VALUE(CALLCONTROL) LIKE DDSHF4CTRL STRUCTURE DDSHF4CTRL
*"----------------------------------------------------------------------
TYPES: BEGIN OF ty_struc,
timestamp TYPE swftrctxt1,
server_name TYPE ssi_servername,
logon_hdl TYPE ssi_logon_hdl,
logon_id TYPE ssi_logon_id,
session_hdl TYPE ssi_session_hdl,
user_name TYPE ssi_user_name,
logon_type TYPE ssi_logon_type,
logon_sub_type TYPE ssi_logon_sub_type,
tenant TYPE ssi_tenant_id,
request_time TYPE ssi_timestamp,
memory TYPE ssi_memsize,
location_info TYPE ssi_logon_location_info,
application TYPE ssi_application,
application_info TYPE ssi_application_info,
rfc_hdl TYPE ssi_rfc_hdl,
rfc_type TYPE ssi_rfc_type,
trace TYPE ssi_trace_level,
priority TYPE ssi_priority,
memory_brutto TYPE ssi_memsize_brutto,
memory_abap TYPE ssi_memsize_abap,
memory_hyper TYPE ssi_memsize_hyper,
memory_heap TYPE ssi_memsize_heap,
open_tasks TYPE ssi_open_tasks,
act_program TYPE ssi_main_program,
websocket_handle TYPE ssi_websocket_handle,
sap_gui_version TYPE ssi_sap_gui_version,
paging_blocks TYPE ssi_sap_paging_blocks,
state TYPE ssi_logon_state,
client_ip_addr TYPE ssi_logon_client_ip,
END OF ty_struc.
DATA: rc TYPE sy-subrc,
session_list TYPE ssi_session_list,
server_info TYPE REF TO cl_server_info,
lv_record TYPE ty_struc,
lt_record TYPE TABLE OF ty_struc,
time_t_bias TYPE p VALUE '19700101000000'.
CALL FUNCTION 'F4UT_OPTIMIZE_COLWIDTH'
TABLES
shlp_tab = shlp_tab
record_tab = record_tab
CHANGING
shlp = shlp
callcontrol = callcontrol.
IF callcontrol-step = 'SELECT'.
TRY.
CREATE OBJECT server_info.
session_list = server_info->get_session_list( with_application_info = 1 ).
CATCH cx_ssi_no_auth.
ENDTRY.
SORT session_list BY tenant user_name.
LOOP AT session_list ASSIGNING FIELD-SYMBOL(<f>).
MOVE-CORRESPONDING <f> TO lv_record.
DATA(r_tstmp) = cl_abap_tstmp=>add(
tstmp = time_t_bias " UTC Time Stamp
secs = <f>-request_time " Time Interval in Seconds
).
CONVERT TIME STAMP r_tstmp TIME ZONE sy-zonlo INTO DATE DATA(dat) TIME DATA(tim).
lv_record-timestamp =
|{ dat(4) }-{ dat+4(2) }-{ dat+6(2) } { tim(2) }:{ tim+2(2) }:{ tim+4(2) }|.
APPEND lv_record TO lt_record.
ENDLOOP.
CALL FUNCTION 'F4UT_RESULTS_MAP'
EXPORTING
* SOURCE_STRUCTURE =
apply_restrictions = 'X'
TABLES
shlp_tab = shlp_tab
record_tab = record_tab
source_tab = lt_record
CHANGING
shlp = shlp
callcontrol = callcontrol
EXCEPTIONS
illegal_structure = 1
OTHERS = 2.
callcontrol-step = 'DISP'.
ENDIF.
ENDFUNCTION.
2. Go to the SAP Gateway Service Builder (SEGW)
◈ Add a new project ZSM04
◈ Go to ZSM04->Data Model->Import->Search Help
◈ Define the entity type name ZZSM04 in the following wizard:
◈ Select the upper check box to import the entire structure of the Search help:
◈ Select the key fields:
◈ Open the generated Entity Set ZzSm04Set and select the boxes Addressable and Searchable:
◈ Double click the Properties of the Entity Type to mark Sortable and Filterable:
You can change the labels for the fields later as well via the T Button.
◈ Generate the runtime objects, result should be:
3. Add the service definition in /IWFND/MAINT_SERVICE, result should be:
4. Go to SAP WEB IDE (hana.ondemand.com)
Choose New Project from Template -> List Report Application. In the service catalog choose your ZSM04_SRV. There is no annotation file yet (ok) . In Data Binding choose your oDATACollection=ZzSm04Set as defined in the gateway and click Finish.
You have now created the UI5 list report in your workspace. In theory, it can already be executed but without selections and no active columns (could be added by settings in the UI) and no details screen.
5. Add annotations.
To enable search fields, detail screen fields and a list a local annotation file needs to be added. This is the main difference to the CDS driven approach where the annotations come from the CDS DDL Source or the meta data extensions developed in Eclipse and ADT.
For the example, see the annotation file which needs to be added first to the project: Place the cursor to the webapp folder in the generated project and do right mouse -> new -> annotation file. Just accept the proposed name and click next -> finish. The result is a annotation0.xml in the webapp folder. Open the file, choose Code Editor and copy the following content:
<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0">
<edmx:Reference Uri="https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Aggregation.V1.xml">
<edmx:Include Alias="Aggregation" Namespace="Org.OData.Aggregation.V1"/>
</edmx:Reference>
<edmx:Reference Uri="https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Authorization.V1.xml">
<edmx:Include Alias="Auth" Namespace="Org.OData.Authorization.V1"/>
</edmx:Reference>
<edmx:Reference Uri="https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Capabilities.V1.xml">
<edmx:Include Alias="Capabilities" Namespace="Org.OData.Capabilities.V1"/>
</edmx:Reference>
<edmx:Reference Uri="https://wiki.scn.sap.com/wiki/download/attachments/448470974/Common.xml?api=v2">
<edmx:Include Alias="Common" Namespace="com.sap.vocabularies.Common.v1"/>
</edmx:Reference>
<edmx:Reference Uri="https://wiki.scn.sap.com/wiki/download/attachments/448470971/Communication.xml?api=v2">
<edmx:Include Alias="Communication" Namespace="com.sap.vocabularies.Communication.v1"/>
</edmx:Reference>
<edmx:Reference Uri="https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Core.V1.xml">
<edmx:Include Alias="Core" Namespace="Org.OData.Core.V1"/>
</edmx:Reference>
<edmx:Reference Uri="https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Measures.V1.xml">
<edmx:Include Alias="Measures" Namespace="Org.OData.Measures.V1"/>
</edmx:Reference>
<edmx:Reference Uri="https://wiki.scn.sap.com/wiki/download/attachments/448470968/UI.xml?api=v2">
<edmx:Include Alias="UI" Namespace="com.sap.vocabularies.UI.v1"/>
</edmx:Reference>
<edmx:Reference Uri="https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Validation.V1.xml">
<edmx:Include Alias="Validation" Namespace="Org.OData.Validation.V1"/>
</edmx:Reference>
<edmx:DataServices>
<Schema xmlns="http://docs.oasis-open.org/odata/ns/edm">
<Annotations Target="ZSM04_SRV.ZzSm04">
<Annotation Term="UI.SelectionFields">
<Collection>
<PropertyPath>Application</PropertyPath>
<PropertyPath>Timestamp</PropertyPath>
</Collection>
</Annotation>
<Annotation Term="UI.HeaderInfo">
<Record Type="UI.HeaderInfoType">
<PropertyValue Property="TypeName" String="sm04 list"/>
<PropertyValue Property="TypeNamePlural" String="sm04 list"/>
<PropertyValue Property="Title">
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="UserName"/>
</Record>
</PropertyValue>
</Record>
</Annotation>
<Annotation Term="UI.Identification">
<Collection>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="ServerName"/>
</Record>" "
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="UserName"/>
</Record>" "
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="Tenant"/>
</Record>" "
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="LocationInfo"/>
</Record>" "
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="Application"/>
</Record>" "
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="ApplicationInfo"/>
</Record>" "
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="ActProgram"/>
</Record>" "
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="ClientIpAddr"/>
</Record>" "
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="Memory"/>
</Record>" "
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="Timestamp"/>
</Record>
</Collection>
</Annotation>
<Annotation Term="UI.LineItem">
<Collection>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="ServerName"/>
</Record>" "
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="UserName"/>
</Record>" "
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="Tenant"/>
</Record>" "
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="LocationInfo"/>
</Record>" "
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="Application"/>
</Record>" "
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="ApplicationInfo"/>
</Record>" "
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="ActProgram"/>
</Record>" "
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="ClientIpAddr"/>
</Record>" "
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="Memory"/>
</Record>" "
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="Timestamp"/>
</Record>
</Collection>
</Annotation>
<Annotation Term="UI.Facets">
<Collection>
<Record Type="UI.ReferenceFacet">
<PropertyValue Property="Target" AnnotationPath="@UI.Identification"/>
</Record>
</Collection>
</Annotation>
</Annotations>
</Schema>
</edmx:DataServices>
</edmx:Edmx>
Save everything, place the cursor on your project root and click run. In case a popup appears select flpSandbox.html. The test launchpad of the Webide opens up and you can start your application. You should get a result like this:
Even the selections should already work except the first defaultSearch Field.
6. Add the implementation for defaultSearch.
The field will be used for the selection on User. To achieve this, coding needs to be added to the DPC_EXT class of the gateway project. Basically, the parameter search_string from the oDATA call which is passed from the first default search field in the Fiori UI needs to be passed to the search help selections. Here is the coding:
class ZCL_ZSM04_DPC_EXT definition
public
inheriting from ZCL_ZSM04_DPC
create public .
public section.
methods /IWBEP/IF_MGW_APPL_SRV_RUNTIME~GET_ENTITYSET
redefinition .
methods /IWBEP/IF_SB_GENDPC_SHLP_DATA~GET_SEARCH_HELP_VALUES
redefinition .
protected section.
data MV_SEARCH_STRING type STRING .
private section.
ENDCLASS.
CLASS ZCL_ZSM04_DPC_EXT IMPLEMENTATION.
METHOD /iwbep/if_mgw_appl_srv_runtime~get_entityset.
mv_search_string = iv_search_string . "save the default search for later use
TRY.
CALL METHOD super->/iwbep/if_mgw_appl_srv_runtime~get_entityset
EXPORTING
iv_entity_name = iv_entity_name
iv_entity_set_name = iv_entity_set_name
iv_source_name = iv_source_name
it_filter_select_options = it_filter_select_options
it_order = it_order
is_paging = is_paging
it_navigation_path = it_navigation_path
it_key_tab = it_key_tab
iv_filter_string = iv_filter_string
iv_search_string = iv_search_string
io_tech_request_context = io_tech_request_context
IMPORTING
er_entityset = er_entityset
es_response_context = es_response_context.
CATCH /iwbep/cx_mgw_busi_exception .
CATCH /iwbep/cx_mgw_tech_exception .
ENDTRY.
ENDMETHOD.
METHOD /iwbep/if_sb_gendpc_shlp_data~get_search_help_values.
DATA: lt_selopt TYPE ddshselops .
lt_selopt[] = it_selopt[] .
* map the default search field to UserName
IF NOT mv_search_string IS INITIAL.
APPEND INITIAL LINE TO lt_selopt ASSIGNING FIELD-SYMBOL(<f_sel>).
<f_sel>-shlpfield = 'USER_NAME' .
<f_sel>-shlpname = iv_shlp_name .
<f_sel>-sign = 'I'.
<f_sel>-low = mv_search_string.
IF mv_search_string CA '*'.
<f_sel>-option = 'CP'.
ELSE.
<f_sel>-option = 'EQ'.
ENDIF.
ENDIF.
CALL METHOD super->/iwbep/if_sb_gendpc_shlp_data~get_search_help_values
EXPORTING
iv_shlp_name = iv_shlp_name
iv_maxrows = 9999
iv_sort = space
iv_call_shlt_exit = 'X'
it_selopt = lt_selopt
IMPORTING
et_return_list = et_return_list
es_message = es_message.
ENDMETHOD.
ENDCLASS.
The result
Now the Fiori list report is fully functional. It is easy and convienient to use a DDIC search help which exists since R/3 4.0 as a Fiori list report. It is easier as to write the oDATA service completely by hand. In some cases you might reuse an already existing object which can include ABAP code for the data selection as well. Because of the ABAP coding you can select any source of data and any calculation you might need.
No comments:
Post a Comment