Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
the_tobias
Product and Topic Expert
Product and Topic Expert
4,322
Following the business process described in my previous post, this article explains an example implementation of a custom message provider for App Support. App Support uses BAdI Implementations to retrieve error messages and logs from a Front-End or Back-End server. This enables customers to create their own log projects outside of the delivered standard solution.

Class Implementation


When the BAdI implementation and the empty class have been created for enhancement definition /UI2/ADE_DATA_PROVIDER, we can continue in SE80 or the ABAP Development Tools. For ease of use, we can use a superclass to reuse some of the standard operations, which are typically used for this type of implementation. The superclass is /UI2/CL_ADE_BADI_DEFAULT:


Assignment of super class /UI2/CL_ADE_BADI_DEFAULT in transaction SE80


 

After adding the superclass, we need to delete the following interfaces, which have been added automatically during to the BAdI implementation, as they have already been implemented in the superclass:

  • IF_BADI_INTERFACE

  • /UI2/IF_ADE_BADI_DATA_PROVIDER


After removing the interfaces from our inheriting class in tab Interfaces, it should be possible to activate. Please note there won’t be any changes on the UI just yet.

Since we’ll be implementing a remote source (data is retrieved from the Back-End Server), we additionally have to implement interface /UI2/IF_ADE_BADI_CALLBACK_SRC.


Interfaces required for the BAdI implementation


Now we’re all set and are able to redefine the methods accordingly.


Inherited methods of the super class can be redefined


We best start with the constructor method, where we define the source as a remote source (data coming from Back-End Server):
  method CONSTRUCTOR.
"-! register as remote source here
super->constructor( iv_is_remote = abap_true ).
endmethod.

The next and very important method to redefine is VERIFY_SOURCE_AVAILABLE. Without this implementation, App Support won’t bother to follow up on the source. This implementation tells the framework, that the implementation is relevant for the current App context. Other restrictions, such as client-dependency can be added here as well.
  METHOD /ui2/if_ade_badi_data_provider~verify_source_available.
***---------------------------------------------------------------------------------------------------------
*** In this method App Support decides, if the BAdi implementation is relevant for the current application
*** to retrieve the correct appkey, simply debug the first time here, when in the application.
***---------------------------------------------------------------------------------------------------------
ev_available = /ui2/if_ade_badi_data_provider~sc_status_not_available.

"Check if App = Display Outbound delivery (Type: WebGUI, Tx: VL02n)
IF is_keys-appkey <> 'X-SAP-UI2-PAGE:X-SAP-UI2-CATALOGPAGE:SAP_LE_BC_OD_PROC:00O2TOBXDLX6WIZLS0DUK2RL0'.
RETURN.
ENDIF.

"now some more specific check, if the BAdI should be called here. In this scenario a log from a remote server
"is retrieved. Therefore we wait for a adeRemoteServer entry. If the log is from a local source, simply wait for
"adeLocalServer
IF is_keys-id_lvl1 <> 'adeLocalServer'.
"-! Important - this will make the entry available in the UI - after method GET_DISPLAY_NAME has been implemented
ev_available = /ui2/if_ade_badi_data_provider~sc_status_available.
"-! Important - set keys for remote proxy processing in CALLBACK_REMOTE_SOURCE and message handling
ms_keys = is_keys.
"-! register at App Support proxy hub, as this BAdI implements the remote interface, additionally set is remote in CONSTRUCTOR
me->register_at_proxy( ).
ENDIF.
ENDMETHOD.

In Method GET_DISPLAY_NAME we can now define how the new menu entry should look like. Additionally, we’ll provide a link to another representation of these messages, in our case SMQ2.
  METHOD /ui2/if_ade_badi_data_provider~get_display_name.
***---------------------------------------------------------------------------------------------------------
*** In this method App Support retrieves the name of the menu entry and a link to an original log
*** transaction, for example a general link to SLG1.
***---------------------------------------------------------------------------------------------------------

"This is the name displayed in the menu, ideally the text is translated into different languages
es_display_name-name = 'Deliveries Inbound Queue'.

"this method creates a WebGUI link for the entered transaction
ev_link_to_log = /ui2/cl_ade_configuration=>get_instance( )->create_webgui_link(
EXPORTING
iv_transaction = 'SMQ2'
iv_rfc_destination = iv_dest ).


ENDMETHOD.

With this implementation we should already see the new menu entry in the application "Display Outbound Delivery":


The menu entry is already visible, but no error messages yet


 

Currently no hanging queues are displayed, but we’ll do this in the next step. The link we added is available when clicking this icon:


Please note: In case the menu entry is not displayed, please check your authorizations for object S_FLP_AS. Our new filter value should now be available as data source for field SUI_ADEDS in the selection criteria. If it is not yet set in your profile, add it to your authorizations to display the new menu entry.


Available values in authorization setup in PFCG on the Front-End Server


For further details, on the authorization setup please check the help.sap.com documentation.

Now we only have to take care of retrieving the actual queue entries. For this example implementation, I’ll use function module TRFC_GET_QIN_INFO_DETAILS, which is RFC enabled, but not released for customers.

The function module retrieves all inbound queues of the called system, depending on the queue name (pretty much same as SMQ2). Therefore, it is a good fit for our example here - the only catch is that we should use it in an asynchronous manner, since we don’t want to cause any negative impact on App Support’s performance. So, let’s look at the implementation of method GET_SOURCE_INFORMATION:
  METHOD /ui2/if_ade_badi_data_provider~get_source_information.
***--------------------------------------------------------------------------------------------
*** The usage of this method depends on the type of Source, which is being used. In case the
*** messages are retrieved from a local source, the source (db table, local fm, etc.) can be
*** collected here directly and passed to ET_MESSAGES.
*** For a remote source it is recommended to use the asynchronuous processing, via usage of
*** STARTING NEW TASK. This way the application remains stable, even if the remote source
*** triggers a timeout. In case of a remote source the messages are retrieved in method
*** CALLBACK_REMOTE_SOURCE and do not have to be provided here.
***---------------------------------------------------------------------------------------------
DATA:
lv_task(32) TYPE c,
lv_qname TYPE trfcqnam,
lv_message TYPE c LENGTH 250.


IF mv_mandt IS INITIAL.
" set client and system id to add them in CALLBACK_REMOTE_SOURCE
/ui2/cl_ade_configuration=>get_instance( )->get_system_client_by_rfc_dest(
EXPORTING
iv_rfc_dest = iv_rfc_dest " Logical RFC Destination - Points to SAP system
IMPORTING
ev_sysid = mv_sysid " Target system
ev_client = mv_mandt "target client
).

"later in the callback function we can't call this method, as we run in background -> therefore create template link for log queues
mv_template_link = /ui2/cl_ade_configuration=>get_instance( )->create_webgui_link(
EXPORTING
iv_transaction = 'SMQ2'
it_query_parms = VALUE #( ( name = 'QNAME' value = 'MYPLACEHOLDER' ) ) "this is the parameter in SMQ2 -> MYPLACEHOLDER will be removed later
iv_rfc_destination = iv_rfc_dest ).
ENDIF.

"This entry depends on how the RFC queues are setup in the remote system. Here we're reading inbound queues from the same system
"and client, as EWM is on the same system.
lv_qname = 'DLWS' && mv_sysid && 'CLNT' && mv_mandt && '*'.

"To call the function module in a separate task, we need to provide a task id. Ideally related to our BAdI
lv_task = is_keys-id.

"Here the remote RFC function module is called in a new task. As a callback the interface method callback_remote_source
"is used, which has to be implemented by this class (Implement interface /UI2/IF_ADE_BADI_CALLBACK_SRC)
CALL FUNCTION 'TRFC_GET_QIN_INFO_DETAILS'
STARTING NEW TASK lv_task "maximum length 32
DESTINATION iv_rfc_dest
CALLING /ui2/if_ade_badi_callback_src~callback_remote_source ON END OF TASK
EXPORTING
qname = lv_qname
client = mv_mandt
EXCEPTIONS
communication_failure = 1 MESSAGE lv_message
system_failure = 2 MESSAGE lv_message
OTHERS = 3.
IF sy-subrc <> 0.
/ui2/cx_ade=>raise_error_in_fm(
EXPORTING
iv_fm_name = 'TRFC_GET_QIN_INFO_DETAILS'
iv_error = CONV #( lv_message )
).
ENDIF.
ENDMETHOD.

The method can be split into two parts. The first part only stores some information in the object instance, based on the current context. The second part calls the function module and sets method CALLBACK_REMOTE_SOURCE as callback interface, when the data is retrieved. For an embedded system implementation, the function module could be used without the STARTING NEW TASK statement. In this case we could also pass the messages to ET_MESSAGES directly, but as we are in a distributed landscape, we’ll implement it with an remote enabled function call.

The target RFC connection of the currently displayed app is provided as input parameter, so we know the destination for our function call right away. The actual results of the remote function call are processed in method CALLBACK_REMOTE_SOURCE, when the data has been retrieved from the Backend Server:
  METHOD /ui2/if_ade_badi_callback_src~callback_remote_source.
***---------------------------------------------------------------------------------------------------------
*** This method is called, when the RFC retrieves a result. With the statement RECEIVE RESULTS FROM FUNCTION
*** the actual exporting parameters are obtained from the FM. The messages should then be mapped to the
*** standard message format of /ui2/ade_s_diagnostics_log. In the last step the messages are passed to the
*** proxy instance. The proxy instance will take care of delivering them to App Support.
***---------------------------------------------------------------------------------------------------------
DATA: lt_rfcqueue TYPE STANDARD TABLE OF trfcqin,
lv_message(250) TYPE c.

"Get messages from callback
RECEIVE RESULTS FROM FUNCTION 'TRFC_GET_QIN_INFO_DETAILS'
TABLES
qtable = lt_rfcqueue
EXCEPTIONS
system_failure = 1 MESSAGE lv_message
communication_failure = 2 MESSAGE lv_message
OTHERS = 3.


"map messages to target format
LOOP AT lt_rfcqueue ASSIGNING FIELD-SYMBOL(<ls_entry>).
"we are only interested in queues in status failed
IF <ls_entry>-qstate <> 'SYSFAIL'.
CONTINUE.
ENDIF.

"build a message line for each sysfail SMQ2 entry
APPEND VALUE #(
s_keys = ms_keys
username = ms_keys-username
source = /ui2/if_ade_badi_data_provider=>sc_source_remote
type = 'E'
msg_date = <ls_entry>-qrfcdatum
msg_time = <ls_entry>-qrfcuzeit
error_text = <ls_entry>-errmess
context = substring( val = <ls_entry>-qname off = 14 ) "add delivery number as context information (last part of queue name)
sysid = mv_sysid "determined in GET_SOURCE_INFORMATION
client = mv_mandt "determined in GET_SOURCE_INFORMATION

"The template link has been set GET_SOURCE_INFORMATION for easier use here. Read more will now lead to the SMQ2 log entry.
more_info_link = replace( val = mv_template_link sub = 'MYPLACEHOLDER' with = <ls_entry>-qname )
) TO mt_messages.

ENDLOOP.

"set in result list in the proxy instance, which will dispatch it to the UI
me->mo_proxy_instance->callback_remote_data_source( iv_id = ms_keys-id
it_messages = mt_messages ).


ENDMETHOD.


Conclusion


With relatively little implementation effort, it is possible to collect logs and error messages in a central location in the SAP Fiori Launchpad. App Support allows flexible enhancements for customer specific projects using the widely accepted BAdI concept.

For Questions and Answers on SAP Fiori – please see the SAP Community Q&A area and feel free to post your own questions.

I hope you found this blog post helpful – feel free to leave comments and feedback, you can follow the SAP Fiori Launchpad tag to receive updates on blog posts here.
1 Comment