[ABAP] Transaktionsdienst (Objektorientiert)

* https://help.sap.com/saphelp_nw70/helpdata/de/fa/f23c18330411d5992100508b6b8b11/content.htm?no_cache=true
* https://rvanmil.wordpress.com/2011/04/14/using-the-transaction-service/
* https://archive.sap.com/discussions/thread/3338833
* https://help.sap.com/saphelp_erp60_sp/helpdata/de/f5/a3682ebc6911d4b2e80050dadfb92b/frameset.htm

* Typgruppe: OSCON
* Update modes
*   OSCON_DMODE_DIRECT           local updates (like the procedural SET UPDATE TASK LOCAL)
*   OSCON_DMODE_UPDATE_TASK      asynchronous updates
*   OSCON_DMODE_LOCAL            local updates (like the procedural SET UPDATE TASK LOCAL)
*   OSCON_DMODE_UPDATE_TASK_SYNC synchronous updates (like the procedural COMMIT WORK AND WAIT)
*   OSCON_DMODE_DEFAULT          (OSCON_DMODE_UPDATE_TASK)
* Programme:
*   DEMO_TRANSACTION_SERVICE
*   DEMO_CREATE_PERSISTENT

CLASS lcl_ta_handler DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS on_finished FOR EVENT finished OF if_os_transaction
      IMPORTING
          status.
ENDCLASS.

CLASS lcl_ta_handler IMPLEMENTATION.
  METHOD on_finished.
    IF status = oscon_tstatus_fin_success.
      WRITE: / 'Update erfolgreich.'.
    ENDIF.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.

  TRY.
      cl_os_system=>init_and_set_modes( i_external_commit = oscon_true
                                        i_update_mode     = oscon_dmode_default ).

      DATA(o_tam) = cl_os_system=>get_transaction_manager( ).
      DATA(o_ta) = o_tam->create_transaction( ).

      SET HANDLER lcl_ta_handler=>on_finished FOR o_ta.

      o_ta->start( ).
      
      ...

* ruft implizit COMMIT WORK
      o_ta->end( ).
    CATCH cx_root INTO DATA(e_txt).
      WRITE: / e_txt->get_text( ).
  ENDTRY.

[ABAP] Timerobjekt cl_gui_timer verwenden

* Hinweis zum Aufruf von cl_gui_timer:
* - selbst mit interval = 1 (1s) triggert der Timer nach run( ) nur alle 2s
* - parallele Listausgaben mehrerer Worker können scheinbar Deadlocks verursachen

* Workerobjekt, welches vom Timer aufgerufen wird
CLASS lcl_worker DEFINITION.
  PUBLIC SECTION.
    METHODS: constructor
      IMPORTING
        i_id TYPE i.
    METHODS: do
      IMPORTING
        i_cnt TYPE i.
    METHODS: finished.

  PRIVATE SECTION.
    DATA: gv_id TYPE i.
ENDCLASS.

CLASS lcl_worker IMPLEMENTATION.
  METHOD constructor.
    gv_id = i_id.
  ENDMETHOD.
  METHOD do.
    WRITE: / 'Do( ) - Timer ID:', gv_id, 'Counter:', i_cnt.
  ENDMETHOD.

  METHOD finished.
    WRITE: / 'Finished( ) - Timer ID:', gv_id.
  ENDMETHOD.
ENDCLASS.

* Timerobjekt, welches zyklisch Worker aufruft
CLASS lcl_timer DEFINITION.
  PUBLIC SECTION.
    METHODS: start
      IMPORTING
        i_worker    TYPE REF TO lcl_worker
        i_interval  TYPE i
        i_count_max TYPE i.

  PRIVATE SECTION.

    DATA: o_worker TYPE REF TO lcl_worker.
    DATA: gv_count_current TYPE i.
    DATA: gv_count_max TYPE i.

    METHODS: on_timer_finished FOR EVENT finished OF cl_gui_timer
      IMPORTING
          sender.
ENDCLASS.

CLASS lcl_timer IMPLEMENTATION.
  METHOD start.
* Übergabewerte ok?
    IF i_count_max >= 0 AND i_interval > 0.
      o_worker = i_worker.

* erster Aufruf -> Funktion sofort ausführen
      o_worker->do( i_cnt = 1 ).

* Zählervariablen setzen
      gv_count_current = 1.
      gv_count_max = i_count_max.

* Timer erzeugen
      DATA(o_timer) = NEW cl_gui_timer( ).
      SET HANDLER on_timer_finished FOR o_timer.
      o_timer->interval = i_interval.
      o_timer->run( ).
    ENDIF.
  ENDMETHOD.

  METHOD on_timer_finished.
* Funktion ausführen
    o_worker->do( i_cnt = gv_count_current + 1 ).

* unendlich
    IF gv_count_max = 0.
* Timer wieder ausführen
      sender->run( ).
    ELSE.
* Anzahl Durchgänge
      gv_count_current = gv_count_current + 1.

      IF gv_count_current < gv_count_max.
* Timer wieder ausführen
        sender->run( ).
      ELSE.
        o_worker->finished( ).
      ENDIF.
    ENDIF.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.

* 1. Timerobjekt mit Worker ID 1
  NEW lcl_timer( )->start( i_worker    = NEW lcl_worker( i_id = 1 )
                           i_interval  = 1
                           i_count_max = 10 ).

* 2. Timerobjekt mit Worker ID 2
  NEW lcl_timer( )->start( i_worker    = NEW lcl_worker( i_id = 2 )
                           i_interval  = 3
                           i_count_max = 5 ).

* 3. Timerobjekt mit Worker ID 3
  NEW lcl_timer( )->start( i_worker    = NEW lcl_worker( i_id = 3 )
                           i_interval  = 2
                           i_count_max = 3 ).

  MESSAGE 'Ok.' TYPE 'S'.