Real-time notifications and workflow using ABAP Push Channels (websockets) Part 1: Creating the APC and AMC
After hearing all about websocket technology at Tech-ed last year, I’ve been extremely eager to try it out. I found there were a few great blogs already written about ABAP Push Channels and how to create your own. I recommend reading the following useful blogs and documents to get a good understanding of ABAP Push Channels:
- Enabling real-time bidirectional client-server communication using ABAP Push Channel
- How to Enable Messaging to SAP UI5 Applications using ABAP Channels
- ABAP News for Release 7.40 – WebSocket Communication with ABAP Channels
and the following series of blogs by Masoud Aghadavoodi Jolfaei
- ABAP Channels Part 1: WebSocket Communication Using ABAP Push Channels
- ABAP Channels Part 2: Publish/Subscribe Messaging Using ABAP Messaging Channels
- ABAP Channels Part 3: Collaboration Scenario Using ABAP Messaging and ABAP Push Channels
So in this blog I’m not going to go into detail about what ABAP Push Channels are all about, I’d recommend reading the blogs and documents above for that.
I’m rather going to demonstrate a real-life possible use case for ABAP Push Channels (websockets). As entertaining as it is seeing it being used for ping pong games, thats unlikely to be very useful in an enterprise environment.
After writing this, I realised that it would be way too large to post as 1 blog. So I have divided it into several parts and each part will be posted in the appropriate space on SCN. See links below:
- Real-time notifications and workflow using ABAP Push Channels (websockets) Part 1: Creating the APC and AMC
- Real-time notifications and workflow using ABAP Push Channels (websockets) Part 2: Broadcasting the message via Workitem exits
- Real-time notifications and workflow using ABAP Push Channels (websockets) Part 3: Creating a UI5 Application for receiving notifications
- Real-time notifications and workflow using ABAP Push Channels (websockets) Part 4: Creating a Web Dynpro ABAP Application for receiving notifications
- Real-time notifications and workflow using ABAP Push Channels (websockets) Part 5: Using the UI5 or Web Dynpro applications in Side Panels
Please Note that this was all done on an ABAP 740 SP06 backend. Much of this is really new and may not be available or the same in prior versions.
The idea is to build a small UI5 or Web Dynpro ABAP Application to display the users Workflow Inbox. This application can either be run standalone or could even be used as a Side Panel Application in the NWBC client, which would possibly be the most appropriate use since it will always be open and be in the users sight while they are busy with other transactions.
Although I am using workflow as the use case to demo this, truthfully, this can be applied to any application in a very similar manner. These notifications are not only being used to display a message in the application, but also to inform the application that there has been a change and a refresh is necessary, therefore the application can reload the data. A push to pull type scenario. This prevents the need for periodic refreshes or for the user to constantly be pressing the refresh button to see if there have been changes.
Step 1 – Create the ABAP Push Channel
Got transaction SAPC (ABAP Push Channels). Right click on “ABAP Push Channels” and click Create.
Enter the name, in this case ZAPC_WF_NOTIFY. Then save to transport or as local object.
Enter a description then press the Generate Class and Service button.
Once generation is complete you will see the following message:
Navigate into the new generated class ZCL_APC_WS_EXT_ZAPC_WF_NOTIFY. Select IF_APC_WS_EXTENSION~ON_START and press the Redefine button . Then do the same for IF_APC_WS_EXTENSION~ON_MESSAGE.
For now leave the implementations of these methods blank, as we will return to enter the code in here after creating the AMC (ABAP Messaging Channel). Activate the class. Then Save and Activate the ABAP Push Channel.
Step 2 – Create the ABAP Messaging Channel
Goto transaction SAMC and right click on “ABAP Messaging Channels” and press Create.
Enter the name ZAMC_WF_NOTIFY. Then save to transport or as local object.
Enter a Description. Put /workflow_notify in Channels and set Message Type ID to TEXT and Activity Scope to System (User will not allow messages to be sent from one user to another). In order to make the messages user specific, we use the channel extension in bind_message_amc_consumer method call and the create_message_producer calls.
Then add the following entry to list of Authorised Programs:
Authorised Program: ZCL_APC_WS_EXT_ZAPC_WF_NOTIFY (class was created in the previous step)
Prog. Type: CLAS
Activity: Receive via APC WebSocket
In subsequent steps we will add in an additional entry in Authorised programs to allow the program broadcasting the message to use the ABAP Messaging Channel.
Save and Activate the AMC (ABAP Messaging Channel)
Step 3 – Implement the code for the Messaging Channel in the APC
Go back to the APC class we created in step 1 and now implement the following code in the IF_APC_WS_EXTENSION~ON_START method. We are going to leave the IF_APC_WS_EXTENSION~ON_MESSAGE method blank as in this use case the client won’t be sending any messages back to the ABAP backend. However, if it were to do so, we would need to add code into this method to handle it.
METHOD if_apc_ws_extension~on_start .
DATA: lv_channel_ext TYPE amc_channel_extension_id.
TRY.
* Set the Channel extension to the user who is connecting,
* this is to ensure the user in a specific client only receives their own messages
lv_channel_ext = sy-mandt && sy–uname.
* Bind the APC (Websocket) we created in step 1 to the AMC ABAP Messagin Channel we created in step 2
DATA(lo_binding)= i_context->get_binding_manager( ).
lo_binding->bind_amc_message_consumer( i_application_id = ‘ZAMC_WF_NOTIFY’
i_channel_id = ‘/workflow_notify’
i_channel_extension_id = lv_channel_ext ).
CATCH cx_apc_error INTO DATA(lx_apc_error).
DATA(lv_message) = lx_apc_error->get_text( ).
MESSAGE lx_apc_error->get_text( ) TYPE ‘E’.
ENDTRY.
ENDMETHOD.
In the next part we will create the work item exits which will broadcast the message via the ABAP Messaging Channel.
Great blog series Brad - Thanks!!!
Thanks Jason!
Hi Brad,
I saw that if you use Activity Scope as User, it will send the message to the same user who is sending it.
Can we send message to a specific user using AMC?
Hi Ekansh,
Yes you can, you would use the activity scope as system and use the channel extension to specify the user as shown above in this blog or as shown below:
* Set the Channel extension to the user who is connecting,
* this is to ensure the user in a specific client only receives their own messages
lv_channel_ext = sy-mandt && sy-uname.
* Bind the APC (Websocket) we created in step 1 to the AMC ABAP Messagin Channel we createdin step 2
DATA(lo_binding)= i_context->get_binding_manager( ).
lo_binding->bind_amc_message_consumer( i_application_id ='ZAMC_WF_NOTIFY'
i_channel_id ='/workflow_notify'
i_channel_extension_id =lv_channel_ext ).
If you choose Activity scope user then you will not be able to communicate between different users.
Cheers,
Brad
Hello Brad,
I am using an AMC with scope as System, the receiver program has activity as Receive via session. I included channel extension in sender as well as receiver program such that the channel extension is like "100USER2" (100 is the client and USER2 is the user to whom I want to send the message). I logged in with two different users(USER1 & USER2) and run the receiver report. The problem is that message is getting received by both the users.
Can you help please?
Hi Ekansh,
Can you post the code for me to see please.
Cheers,
Brad
Hi Brad,
The code for sending is:
REPORT zdemo_send_amc.
CLASS demo DEFINITION.
PUBLIC SECTION.
CLASS-METHODS main.
ENDCLASS.
CLASS demo IMPLEMENTATION.
METHOD main.
DATA: lv_channel_ext TYPE amc_channel_extension_id,
lv_uname type sy-uname.
lv_uname = 'USER2'.
lv_channel_ext = sy-mandt && lv_uname.
TRY.
CAST if_amc_message_producer_text(
cl_amc_channel_manager=>create_message_producer(
i_application_id = 'ZAMC_XXXX_TEST'
i_channel_id = '/XXXX_test'
i_channel_extension_id = lv_channel_ext )
)->send( i_message = |Message from Ekansh by { sy-repid }| ).
CATCH cx_amc_error INTO DATA(text_exc).
cl_demo_output=>display( text_exc->get_text( ) ).
ENDTRY.
ENDMETHOD.
ENDCLASS.
START-OF-SELECTION.
demo=>main( ).
The code for receiving is:
REPORT zdemo_receive_amc_new.
CLASS message_receiver DEFINITION.
PUBLIC SECTION.
INTERFACES: if_amc_message_receiver_text.
DATA: text_message TYPE string.
ENDCLASS.
CLASS message_receiver IMPLEMENTATION.
METHOD if_amc_message_receiver_text~receive.
text_message = i_message.
ENDMETHOD.
ENDCLASS.
CLASS amc_demo DEFINITION.
PUBLIC SECTION.
CLASS-METHODS main.
ENDCLASS.
CLASS amc_demo IMPLEMENTATION.
METHOD main.
DATA: lv_channel_ext TYPE amc_channel_extension_id,
lv_uname type sy-uname.
lv_uname = 'USER2'.
lv_channel_ext = sy-mandt && lv_uname.
DATA(receiver) = NEW message_receiver( ).
TRY.
cl_amc_channel_manager=>create_message_consumer(
i_application_id = 'ZAMC_XXXX_TEST'
i_channel_id = '/XXXX_test'
i_channel_extension_id = lv_channel_ext
)->start_message_delivery( i_receiver = receiver ).
CATCH cx_amc_error INTO DATA(text_exc).
cl_demo_output=>display( text_exc->get_text( ) ).
ENDTRY.
WAIT FOR MESSAGING CHANNELS
UNTIL receiver->text_message IS NOT INITIAL
UP TO 5 SECONDS.
cl_demo_output=>begin_section( receiver->text_message ).
ENDMETHOD.
ENDCLASS.
START-OF-SELECTION.
amc_demo=>main( ).
Hi Ekansh,
It appears to be correct to me and similar to what I did. The only difference is I setup a class to receive via an APC websocket and have the receiver code in the following method:METHOD if_apc_ws_extension~on_start. Which is triggered via an external UI5 app or web dynpro.
Maybe try putting the receiver into an APC websocket class and in the on~start method. Then use the webdynpro component/application WDR_TEST_APC to test it. Try logon with both users and connect to it with both users and see if it still gives you that issue.
Cheers,
Brad
Hi Ekansh,
I see you are using just a single extension id in the above code. Until you use two different extension id's all the messages which are sent to that specific channel/extension ID combination would be received by all the users who are running this receiver report.
Regards,
Manish
Hi Manish,
Can you explain how can I use two different extension ids while sending the message.
Hi Brad!
Will this only work if the fiori client is open or this work like a gmail push notification?
Hi Brad,
How can we communicate to Non SAP system through ABAP channel.
We want to send the Notification data thru Websocket to NON SAP system. Able to test the ABAP Channel from Browser but the NON SAP system is unable to receive the data sent from SAP even though they add our WSS URL in their application.
Before calling ABAP push channel do we need to establish communication between SAP and NON SAP system? If possible kindly share how to do that.
Thanks & Regards
Deepthi
Hi Brad,
We are trying to connect to NON SAP system thru ABAP Channel . Able to test the ABAP channel from web .Non SAP system added ABAP channel wss URL in their application but they are unable to receive any message from SAP.
Before calling Abap push channel do we need to establish connectivity with Non SAP system? If so how should that be done.
Thanks & Regards
Deepthi