Monday, 12 September 2016

ABAP News for Release 7.50 - ABAP Channels Reloaded

ABAP Channels (ABAP Messaging Channels AMC and ABAP Push Channels APC) were introduced with ABAP 7.40, SP02, SP05. They enable an event based bidirectional communication between ABAP application servers and with the internet. For that, a dedicated Push Channel Protocol (PCP) can be used since 7.40, SP08. Before ABAP 7.50, the communication between ABAP servers and the internet was restricted to the Web Socket Protocol (WS) and the AS ABAP acting as a stateless APC server. The following features are new with ABAP 7.50:

Stateful APC Servers


Before ABAP 7.50, each ABAP Push Channel that you created as a repository object in SE80 or SAPC was automatically stateless. An APC handler class always inherited from CL_APC_WSP_EXT_STATELESS_BASE or CL_APC_WSP_EXT_STATELESS_PCP_B. Now you can select Stateful too.

ABAP News for Release 7.50 - ABAP Channels Reloaded

The respective APC handler classes will inherit from CL_APC_WSP_EXT_STATEFUL_BASE or CL_APC_WSP_EXT_STATEFUL_PCP_B. For a stateful APC server its context and especially the attributes of the APC handler class are not deleted between different client accesses.

Stateful APC applications are running in a so called Non Blocking Model, where all blocking statements are forbidden.Those are the usual suspects that call programs or screens, leave programs or screens, or interrupt.

AS ABAP as APC Client


From ABAP 7.50 on, you can define handler classes in ABAP, that implement either IF_APC_WSP_EVENT_HANDLER or IF_APC_WSP_EVENT_HANDLER_PCP (the latter for using the Push Channel Protocol). Methods of such classes can handle messages from an APC server. The actual client is then created with factory methods of the classes CL_APC_WSP_CLIENT_MANAGER or CL_APC_TCP_CLIENT_MANAGER. Using a client object, you can open and close connections to an APC server and you can create and send messages.

In order to receive messages in an ABAP APC client, the AS ABAP has to wait for those. Such a wait state can be programmed explicitly with the new ABAP statement WAIT FOR PUSH CHANNELS, that completes the already existing WAIT FOR MESSAGING CHANNELS and WAIT FOR ASYNCHRONOUS TASKS.

See the example in the next section.

TCP Protocol


Besides the WebSocket protocol (WSP), the ABAP Push Channels framework now also supports native TCP (Transmission Control Protocol) sockets. This allows communication with Clients and Servers that  do not support WSP. Those can be embedded systems or Progammable Logic Controllers (PLC). And this ultimately connects our good old ABAP directly to - attention, buzz word alarm - the internet of things (IOT)!

For an AS ABAP to work as a TCP server, you simply select the respective connection type:

ABAP News for Release 7.50 - ABAP Channels Reloaded

PCP cannot be used as subprotocol here, but stateful TCP servers are possible. The respective APC handler classes will inherit from CL_APC_TCP_EXT_STATELESS_BASE or CL_APC_TCP_EXT_STATEFUL_BASE.

For an AS ABAP to work as a TCP client, you basically do the same as for WSP clients (see above) but use CL_APC_TCP_CLIENT_MANAGER in order to create the client object.

The following is a complete example for an ABAP program that creates an ABAP TCP client:

CLASS apc_handler DEFINITION FINAL .
  PUBLIC SECTION.
    INTERFACES if_apc_wsp_event_handler.
    DATA       message TYPE string.
ENDCLASS.

CLASS apc_handler IMPLEMENTATION.
  METHOD if_apc_wsp_event_handler~on_open.
  ENDMETHOD.

  METHOD if_apc_wsp_event_handler~on_message.
    TRY.
        message = i_message->get_text( ).
      CATCH cx_apc_error INTO DATA(apc_error).
        message = apc_error->get_text( ).
    ENDTRY.
  ENDMETHOD.

  METHOD if_apc_wsp_event_handler~on_close.
    message = 'Connection closed!'.
  ENDMETHOD.

  METHOD if_apc_wsp_event_handler~on_error.
  ENDMETHOD.
ENDCLASS.

CLASS apc_demo DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS main.
ENDCLASS.

CLASS apc_demo IMPLEMENTATION.
  METHOD main.
    DATA(tcp_server) = `C:\ncat\ncat.exe`.
    DATA(ip_adress)  = cl_gui_frontend_services=>get_ip_address( ).
    DATA(port)       = `12345`.
    DATA(terminator) = `0A`.
    DATA(msg)        = `Hello TCP, answer me!`.

    "Server
    IF cl_gui_frontend_services=>file_exist(
         file = tcp_server ) IS INITIAL.
      cl_demo_output=>display( 'TCP Server not found!' ).
      LEAVE PROGRAM.
    ENDIF.
    cl_gui_frontend_services=>execute(
    EXPORTING
      application = `cmd.exe`
      parameter  =  `/c ` && tcp_server &&
                   ` -l ` && ip_adress && ` -p ` && port ).
    WAIT UP TO 1 SECONDS.

    TRY.
        DATA(event_handler) = NEW apc_handler( ).

        "Client
        DATA(client) = cl_apc_tcp_client_manager=>create(
          i_host   = ip_adress
          i_port  = port
          i_frame = VALUE apc_tcp_frame(
            frame_type =
              if_apc_tcp_frame_types=>co_frame_type_terminator
            terminator =
              terminator )
          i_event_handler = event_handler ).

        client->connect( ).

        "Send mesasage from client
        DATA(message_manager) = CAST if_apc_wsp_message_manager(
          client->get_message_manager( ) ).
        DATA(message) = CAST if_apc_wsp_message(
          message_manager->create_message( ) ).
        DATA(binary_terminator) = CONV xstring( terminator ).
        DATA(binary_msg) = cl_abap_codepage=>convert_to( msg ).
        CONCATENATE binary_msg binary_terminator
               INTO binary_msg IN BYTE MODE.
        message->set_binary( binary_msg ).
        message_manager->send( message ).

        "Wait for a message from server
        CLEAR event_handler->message.
        WAIT FOR PUSH CHANNELS
             UNTIL event_handler->message IS NOT INITIAL
             UP TO 10 SECONDS.
        IF sy-subrc = 4.
          cl_demo_output=>display(
            'No handler for APC messages registered!' ).
        ELSEIF sy-subrc = 8.
          cl_demo_output=>display(
            'Timeout occured!' ).
        ELSE.
          cl_demo_output=>display(
            |TCP client received:\n\n{ event_handler->message }| ).
        ENDIF.

        client->close(
          i_reason = 'Application closed connection!' ).

      CATCH cx_apc_error INTO DATA(apc_error).
        cl_demo_output=>display( apc_error->get_text( ) ).
    ENDTRY.

  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
  apc_demo=>main( ).

To simulate an external TCP server, the program uses the current frontend computer, to which the freely available Ncat can be downloaded. The ABAP program starts Ncat.exe, which waits for a message. The ABAP APC client sends a message and waits itself by using WAIT FOR PUSH CHANNELS. You can enter a message in the Ncat console and will receive it in ABAP. Note, that the terminator character of the TCP frame structure must be defined explicitly.

Detached APC Client


This one is a little bit tricky. The use case is a scenario, where an AS ABAP wants to work as an APC server, but wants to open the connection itself. In order to do so, the AS ABAP first acts like an APC client (see above) and opens a connection. But instead of sending a message, it is immediately detached but the connection remains open. Now the same or any other ABAP application server can be attached to the connection as a so called attached client, and the AS ABAP of the detached client then plays the role of a stateless or stateful server.

A deatched client similar to a real client needs handler classes implementing IF_APC_WSP_EVENT_HANDLER or IF_APC_WSP_EVENT_HANDLER_PCP. But only the ON_OPEN event is needed in order to receive a connection handle. The detached clients itself are created with CL_APC_WSP_CLIENT_CONN_MANAGER or CL_APC_TCP_CLIENT_CONN_MANAGER. Such a detached client is used to open the connection and to be detached immediately by its method CONNECT_AND_DETACH.

Now, the connection handle can be used to create an attached client with method ATTACH of CL_APC_WSP_CLIENT_CONN_MANAGER or CL_APC_TCP_CLIENT_CONN_MANAGER. The attached client object can send messages to the AS ABAP of the detached client. Oh boy.

APC Access Object


With a similar mechanism as for attaching an attached client to a detached client, you can create an access object for any APC connection. If an APC handler class decides to publish a connection handle that it can get itself with method GET_CONNECTION_ATTACH_HANDLE from its context object, you can use the same method ATTACH as above to create an access object, that can send messages to the connection. In this case some restrictions for the connection handle apply. Only the same session, client and user or the same program and client are allowed to use such a connection handle.

AMC Point-to-Point-Communication


ABAP Messaging Channels as you know them up to now are based on a publlish and subscribe mechanism, where the sender does not know the receivers. With ABAP 7.50, also a point-to-point communication is possible, where a sender can send messages to a specific receiver. For that, the sender needs the id of the receiver. A receiver can get its id with method GET_CONSUMER_SESSION_ID of its channel manager and publish it appropriately. A sender can use that id to create a respective sender object with method CREATE_MESSAGE_PRODUCER_BY_ID of its channel manager.The message can be send asynchronously or synchronously. In the latter case, the sender waits for a feedback.

No comments:

Post a Comment