This is a test message to test the length of the message box.
Login
BTP Application Job
Erstellt von Software-Heroes

BTP - Application Jobs (Anlage)

173

Wie legt man nun einen neuen Job im System an? In diesem Artikel schauen wir uns zwei Methoden an, um Jobs anzulegen.

Werbung


In der letzten Woche hatten wir dir eine Einführung in das Thema Application Job gegeben und wie Jobs in der Cloud und dem ABAP Environment aussehen und funktionieren. In diesem Artikel schauen wir uns an, wie so ein Job erstellt wird und wie wir dann darauf zugreifen können.

 

Einleitung

Bevor wir die Objekte anlegen, wollen wir noch einen kleinen Exkurs in die Vergangenheit machen. Als die ersten Jobs eingeführt wurden, gab es nur die Möglichkeit über die ABAP API die Objekte im System anzulegen. Mittlerweile gibt es auch die Möglichkeit in den ADTs alle Objekte anzulegen, diese Möglichkeit wollen wir auch genauer aufzeigen, da dies der Standardweg zur Neuanlage ist.

 

Vorbereitung

In unserer Demo werden wir eine Tabelle verwenden, um die Läufe zu protokollieren und Informationen sichtbar zu machen. Die Ausführung des Jobs kann nicht leicht debuggt werden, deshalb greifen wir vor allem auf diese Informationen zu, um vergangene Läufe und deren Inhalte zu tracken.

@EndUserText.label : 'Tracking for Jobs'
define table zbs_dmo_jtrack {
  key client     : abap.clnt not null;
  key identifier : sysuuid_x16 not null;
  content        : abap.char(200);
  test           : abap_boolean;
  rdate          : abap.dats;
  rtime          : abap.tims;
}

 

Im Feld "Content" können wir verschiedene Inhalte speichern, die restlichen Felder dienen für die automatische Befüllung aus den Werten und aus dem Kontext.

 

Anlage (ADT)

Die erste Anlage erfolgt über die ABAP Development Tools, kurz ADT, und nutzt dafür die Standard ADT Objekte. Dazu legen wir nun die folgenden Objekte an, um unseren ersten Job zu definieren.

 

Klasse anlegen

Zuerst einmal müssen wir die Ausführungsklasse anlegen, die später die Funktionalität implementiert, um unseren Job mit Parametern auszustatten und Einstiegspunkt für die Ausführung zu sein. Dazu implementieren wir bei der Anlage auch die beiden Interface:

  • IF_APJ_DT_EXEC_OBJECT - Bereitstellung der Methode GET_PARAMETERS, um die Parameter des Jobs zu definieren.
  • IF_APJ_RT_EXEC_OBJECT - Bereitstellung der Methode EXECUTE, die später bei der Jobausführung gestartet wird.

 

 

Nach der Ausführung und der Zuordnung des Transportes, steht die leere Klasse zur Verfügung, die wir nun mit Inhalt befüllen können.

CLASS zcl_bs_demo_job_adt_exe DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC.

  PUBLIC SECTION.
    INTERFACES if_apj_dt_exec_object.
    INTERFACES if_apj_rt_exec_object.
ENDCLASS.


CLASS zcl_bs_demo_job_adt_exe IMPLEMENTATION.
  METHOD if_apj_dt_exec_object~get_parameters.
  ENDMETHOD.


  METHOD if_apj_rt_exec_object~execute.
  ENDMETHOD.
ENDCLASS.

 

Parameter anlegen

Im nächsten Schritt wollen wir einige Parameter im Job anlegen, die wir später dann für Einstellungen verwenden wollen, aber auch um zu zeigen, wie man den Job gestalten kann. Dazu einmal die Signatur der Methode und welche Tabellen uns zur Verfügung stehen:

 

Zuerst einmal definieren wir einige Standard-Parameter, die wir dann im späteren Lauf des Jobs verwenden wollen. Dazu geben wir alle Informationen in der Tabelle mit, die die Felder besser beschreiben und wie sie später funktionieren sollen.

et_parameter_def = VALUE #( datatype       = 'C'
                            changeable_ind = abap_true
                            ( selname       = 'TEXT'
                              kind          = if_apj_dt_exec_object=>parameter
                              param_text    = 'Free text'
                              length        = 50
                              lowercase_ind = abap_true
                              mandatory_ind = abap_true )
                            ( selname    = 'COUNTRY'
                              kind       = if_apj_dt_exec_object=>select_option
                              param_text = 'Country'
                              length     = 3 )
                            ( selname         = 'R_TEXT'
                              kind            = if_apj_dt_exec_object=>parameter
                              param_text      = 'Text'
                              length          = 1
                              radio_group_ind = abap_true
                              radio_group_id  = 'R1' )
                            ( selname         = 'R_LAND'
                              kind            = if_apj_dt_exec_object=>parameter
                              param_text      = 'Country'
                              length          = 1
                              radio_group_ind = abap_true
                              radio_group_id  = 'R1' )
                            ( selname      = 'TEST'
                              kind         = if_apj_dt_exec_object=>parameter
                              param_text   = 'Test'
                              length       = 1
                              checkbox_ind = abap_true ) ).

 

Dazu einige der Elemente besser beschrieben:

  • SELNAME - Name des Feldes, darf maximal 8 Stellen haben.
  • KIND - Feld ist Parameter oder Select-Option. Im Interface IF_APJ_DT_EXEC_OBJECT gibt es die beiden Konstanten, die dazu verwendet werden können.
  • PARAM_TEXT - Text des Parameters der später in der App erscheinen soll, hier sollten übersetzbare Texte verwendet werden.
  • DATATYPE - Grundtyp mit dem das Feld definiert wird.
  • LENGTH - Länge des Feldes für spätere Eingaben in der Maske.
  • DECIMALS - Anzahl der Kommastellen, falls ein Dezimaler Datentype verwendet wird.
  • LOWERCASE_IND - Auf ABAP_TRUE setzen, wenn der Inhalt des Feldes Groß-/Kleinschreibung unterstützen soll.
  • CHECKBOX_IND - Auf ABAP_TRUE setzen, wenn das Feld als Checkbox angezeigt werden soll.
  • RADIO_GROUP_IND - Auf ABAP_TRUE setzen, wenn das Feld als Radiobutton angezeigt werden soll.
  • RADIO_GROUP_ID - Alle Felder in einer Gruppe (Radiobuttons) sollten die gleiche ID bekommen.
  • MANDATORY_IND - Auf ABAP_TRUE setzen, wenn das Feld ein Pflichtfeld sein soll. Dann ist eine Eingabe immer nötig.

 

Zum Abschluss definieren wir noch einige Vorschlagswerte, die später in das Template übernommen werden sollen.

et_parameter_val = VALUE #( sign   = 'I'
                            option = 'EQ'
                            ( selname = 'TEST' low = abap_true )
                            ( selname = 'R_TEXT' low = abap_false )
                            ( selname = 'R_LAND' low = abap_true ) ).

 

Nach dem Generieren aller Objekte, sieht das Parameter Bild dann wie folgt aus. Unsere Standard-Werte sind gesetzt (Checkbox und Radiobuttons) und der Text ist als Pflichtfeld definiert. Die Eingabe kann aber erst nach dem Schritt "Job-Template" getestet werden.

 

Job-Katalog

Wenn du ein entsprechendes Paket hast oder ein neues Paket angelegt hast, kannst du nun den Job-Katalog anlegen. Dieser definiert die Hülle für die ausführbare Klasse und die Einstellungen, die für den Start definiert werden können. Dazu auf das Paket Rechts-Klicken gehen und über "New -> Other ABAP Repository Object" nach dem "Job Catalog" suchen.

 

Die Ausführungsklasse ist Pflichtfeld und wird für die Anlage des Katalogs benötigt. Nach Befüllung der Informationen, kann der Wizard abgeschlossen werden.

 

Im Job-Katalog stehen dann noch verschiedene Exits zur Verfügung, die wir uns im nächsten Artikel einmal genauer anschauen werden. Von hier aus, kannst du aber auch in die ausführende Klasse abspringen.

 

Job-Template

Bevor wir allerdings den Job nun in der "Application Jobs" App finden, müssen wir erst noch ein Template anlegen. Wie beim Job-Katalog können wir dies über den Wizard als neues Objekt machen, es handelt sich dabei um ein Objekt vom Typ "Application Job Template".

 

Das Template wird angelegt und du findest alle definierten Elemente der Parameter in der Liste wieder. Dort werden die Vorschlagswerte für das Template gesichert und bei Ausführung geladen.

 

Es wird nun eine Meldung angezeigt, dass der Pflichtparameter nicht vorbelegt ist, wir können das Objekt allerdings trotzdem aktivieren. Die Prüfung wird vor allem bei der Einplanung des Jobs relevant.

 

Logik

Der wichtigste Bestandteil des Jobs ist allerdings die Ausführungslogik, diese haben wir bisher noch gar nicht berücksichtigt und müssen diese noch in unserer Klasse implementieren. Dazu gehen wir in die Klasse und erweitern die Logik um zwei Schritte.

 

Parameter parsen

Im ersten Schritt erhalten wir alle Eingaben als Tabelle und sollten diese für unseren Prozess aufbereiten. Dieser Schritt ist optional, kann allerdings für die Folgeschritte für mehr Übersichtlichkeit sorgen. Zuerst einmal definieren wir Felder, die die Inhalte unserer Parameter aufnehmen.

DATA ld_text TYPE c LENGTH 50.
DATA lt_r_country TYPE RANGE OF I_Country-Country.
DATA ld_radio_text TYPE abap_boolean.
DATA ld_radio_country TYPE abap_boolean.
DATA ld_test TYPE abap_boolean.

 

Nun können wir die Inhalte der Tabelle parsen und auf die verschiedenen Felder verteilen. Bei Parametern reicht eine einfache Zuweisung der Inhalte, bei den SELECT-OPTIONS müssen wir jede Zeile anhängen, da es hier mehr Einträge geben kann, die zu einer Select-Option gehören.

LOOP AT it_parameters INTO DATA(ls_parameter).
  CASE ls_parameter-selname.
    WHEN 'TEXT'.
      ld_text = ls_parameter-low.
    WHEN 'COUNTRY'.
      INSERT CORRESPONDING #( ls_parameter ) INTO TABLE lt_r_country.
    WHEN 'R_TEXT'.
      ld_radio_text = ls_parameter-low.
    WHEN 'R_LAND'.
      ld_radio_country = ls_parameter-low.
    WHEN 'TEST'.
      ld_test = ls_parameter-low.
  ENDCASE.
ENDLOOP.

 

Hinweis: Die Namen der Parameter können maximal 8-stellig sein, hier gibt es offensichtlich noch Abhängigkeiten zu echten Selektionsbildern. Es empfiehlt sich die Nutzung eines Konstanten-Interface für die Definition der Parameter und das Auflösen in Variablen.

 

Logik ausführen

Nachdem nun alle Inhalte auf Variablen verteilt wurden, können wir nun mit der Implementierung der eigentlichen Logik beginnen. Hierbei handelt es sich um eine Demo Logik, es kann genauso gut eine andere Klasse oder Methode aufgerufen werden, der Einfachheit halber machen wir dies in der gleichen Methode. Im ersten Schritt befüllen wir die Standardfelder für jeden Datensatz.

DATA(ls_database) = VALUE zbs_dmo_jtrack( identifier = cl_system_uuid=>create_uuid_x16_static( )
                                          rdate      = cl_abap_context_info=>get_system_date( )
                                          rtime      = cl_abap_context_info=>get_system_time( )
                                          test       = ld_test ).

 

Dann wählen wir, welche Logik ausgeführt werden soll. Ist der Radiobutton für Text gesetzt, dann übernehmen wir den Text, ansonsten werden die Länder über die Selektion gelesen und die Namen als Komma getrennte Liste übernommen.

CASE abap_true.
  WHEN ld_radio_text.
    ls_database-content = ld_text.

  WHEN ld_radio_country.
    SELECT FROM I_CountryText
      FIELDS CountryName
      WHERE Country IN @lt_r_country
        and Language = @sy-langu
      INTO TABLE @DATA(lt_names).

    ls_database-content = concat_lines_of( table = lt_names sep = `, ` ).

ENDCASE.

 

Zum Abschluss schreiben wir den neuen Datensatz auf die Datenbank, um später den Lauf prüfen zu können und ob die Logik, sowie die Übergabe, sauber funktioniert hat.

INSERT zbs_dmo_jtrack FROM @ls_database.
COMMIT WORK.

 

Application Jobs

Nachdem wir nun die Klasse, den Katalog und das Template angelegt haben, können wir in die App "Application Jobs" gehen, um das Ergebnis der Generierung zu prüfen und unseren ersten Job zu starten. Über die Suchhilfe können wir nun das Job-Template wählen.

 

Die Ausführung setzen wir auf "Sofort", um das Ergebnis direkt zu bekommen. Nun können wir auch unsere Parameter zum ersten Mal sehen und entsprechende Eingaben für den Job durchführen.

 

Über "Schedule" startet der Job entsprechend. Nun führen wir noch einen zweiten Lauf aus, setzen allerdings das Testkennzeichen und auf Text, um Änderungen im Ergebnis zu sehen. Nach dem Lauf der beiden Jobs, können wir in unsere Logging-Tabelle schauen.

 

Komplettes Beispiel

Hier noch einmal die komplette Implementierung der Job-Klasse, damit kannst du diesen Job in deinem System nachbauen.

CLASS zcl_bs_demo_job_adt_exe DEFINITION PUBLIC FINAL CREATE PUBLIC.
  PUBLIC SECTION.
    INTERFACES if_apj_dt_exec_object.
    INTERFACES if_apj_rt_exec_object.
ENDCLASS.


CLASS zcl_bs_demo_job_adt_exe IMPLEMENTATION.
  METHOD if_apj_dt_exec_object~get_parameters.
    et_parameter_def = VALUE #( datatype       = 'C'
                                changeable_ind = abap_true
                                ( selname       = 'TEXT'
                                  kind          = if_apj_dt_exec_object=>parameter
                                  param_text    = 'Free text'
                                  length        = 50
                                  lowercase_ind = abap_true
                                  mandatory_ind = abap_true )
                                ( selname    = 'COUNTRY'
                                  kind       = if_apj_dt_exec_object=>select_option
                                  param_text = 'Country'
                                  length     = 3 )
                                ( selname         = 'R_TEXT'
                                  kind            = if_apj_dt_exec_object=>parameter
                                  param_text      = 'Text'
                                  length          = 1
                                  radio_group_ind = abap_true
                                  radio_group_id  = 'R1' )
                                ( selname         = 'R_LAND'
                                  kind            = if_apj_dt_exec_object=>parameter
                                  param_text      = 'Country'
                                  length          = 1
                                  radio_group_ind = abap_true
                                  radio_group_id  = 'R1' )
                                ( selname      = 'TEST'
                                  kind         = if_apj_dt_exec_object=>parameter
                                  param_text   = 'Test'
                                  length       = 1
                                  checkbox_ind = abap_true ) ).

    et_parameter_val = VALUE #( sign   = 'I'
                                option = 'EQ'
                                ( selname = 'TEST' low = abap_true )
                                ( selname = 'R_TEXT' low = abap_false )
                                ( selname = 'R_LAND' low = abap_true ) ).
  ENDMETHOD.


  METHOD if_apj_rt_exec_object~execute.
    DATA ld_text          TYPE c LENGTH 50.
    DATA lt_r_country     TYPE RANGE OF I_CountryText-Country.
    DATA ld_radio_text    TYPE abap_boolean.
    DATA ld_radio_country TYPE abap_boolean.
    DATA ld_test          TYPE abap_boolean.

    LOOP AT it_parameters INTO DATA(ls_parameter).
      CASE ls_parameter-selname.
        WHEN 'TEXT'.
          ld_text = ls_parameter-low.
        WHEN 'COUNTRY'.
          INSERT CORRESPONDING #( ls_parameter ) INTO TABLE lt_r_country.
        WHEN 'R_TEXT'.
          ld_radio_text = ls_parameter-low.
        WHEN 'R_LAND'.
          ld_radio_country = ls_parameter-low.
        WHEN 'TEST'.
          ld_test = ls_parameter-low.
      ENDCASE.
    ENDLOOP.

    DATA(ls_database) = VALUE zbs_dmo_jtrack( identifier = cl_system_uuid=>create_uuid_x16_static( )
                                              rdate      = cl_abap_context_info=>get_system_date( )
                                              rtime      = cl_abap_context_info=>get_system_time( )
                                              test       = ld_test ).

    CASE abap_true.
      WHEN ld_radio_text.
        ls_database-content = ld_text.

      WHEN ld_radio_country.
        SELECT FROM I_CountryText
          FIELDS CountryName
          WHERE Country IN @lt_r_country
            and Language = @sy-langu
          INTO TABLE @DATA(lt_names).

        ls_database-content = concat_lines_of( table = lt_names sep = `, ` ).

    ENDCASE.

    INSERT zbs_dmo_jtrack FROM @ls_database.
    COMMIT WORK.
  ENDMETHOD.
ENDCLASS.

 

Anlage (API)

Für die Anlage der Objekte gibt es im System auch eine ABAP API, die vor allem zu Zeiten genutzt wurde, als die ABAP Development Tools die Objekte für die Jobs noch nicht unterstützt haben. Dazu benötigst du allerdings ebenfalls schon die Ausführungsklasse für den Job, bevor du dir mit der API den Katalog und das Template generieren lassen kannst. Dazu einmal ein Stück Beispiel-Code:

CLASS zcl_bs_demo_poc_job_cre DEFINITION PUBLIC FINAL CREATE PUBLIC.
  PUBLIC SECTION.
    INTERFACES if_oo_adt_classrun.
ENDCLASS.


CLASS zcl_bs_demo_poc_job_cre IMPLEMENTATION.
  METHOD if_oo_adt_classrun~main.
    CONSTANTS lc_transport TYPE cl_apj_dt_create_content=>ty_transport_request VALUE '<TRANSPORT_NUMBER>'.
    CONSTANTS lc_package   TYPE cl_apj_dt_create_content=>ty_package           VALUE '<PACKAGE_NAME>'.

    TRY.
        DATA(lo_dt) = cl_apj_dt_create_content=>get_instance( ).

        lo_dt->create_job_cat_entry( iv_catalog_name       = 'ZBS_DEMO_POC_JOB_CATAPI'
                                     iv_class_name         = 'ZCL_BS_DEMO_POC_JOB_EXE'
                                     iv_text               = 'DEMO: Job API'
                                     iv_catalog_entry_type = cl_apj_dt_create_content=>class_based
                                     iv_transport_request  = lc_transport
                                     iv_package            = lc_package ).
        out->write( |Job catalog entry created successfully| ).

      CATCH cx_apj_dt_content INTO DATA(lo_apj_dt_content).
        out->write( |Creation of job catalog entry failed: { lo_apj_dt_content->get_text( ) }| ).
    ENDTRY.

    TRY.
        NEW zcl_bs_demo_job_adt_exe( )->if_apj_dt_exec_object~get_parameters(
          IMPORTING et_parameter_val = DATA(lt_parameters) ).

        IF 1 = 1.
          lo_dt->create_job_template_entry( iv_template_name     = 'ZBS_DEMO_POC_JOB_TEMPAPI'
                                            iv_catalog_name      = 'ZBS_DEMO_POC_JOB_CATAPI'
                                            iv_text              = 'DEMO: Job API'
                                            it_parameters        = lt_parameters
                                            iv_transport_request = lc_transport
                                            iv_package           = lc_package ).
          out->write( |Job template created successfully| ).

        ELSE.
          lo_dt->delete_job_template_entry( iv_template_name     = 'ZBS_DEMO_JOB_TEMPLATE_DEFAULT'
                                            iv_transport_request = lc_transport ).
          out->write( |Job template deleted successfully| ).

        ENDIF.

      CATCH cx_apj_dt_content INTO lo_apj_dt_content.
        out->write( |Creation of job template failed: { lo_apj_dt_content->get_text( ) }| ).
        RETURN.
    ENDTRY.
  ENDMETHOD.
ENDCLASS.

 

Der Code ruft die API auf und legt zuerst den Job-Katalog an, im zweiten Schritt werden aus der Ausführungsklasse die Parameter gelesen und damit das Template generiert, die API setzt aber keine Default-Werte im Template.

 

Hinweis: Die Anlage von Job-Katalog und Template über die API wird nur noch bedingt empfohlen, es sollte auf die Standardwerkzeuge im ADT zurückgegriffen werden, da hier immer die neuesten Features implementiert sind.

 

Fazit

Für die Erstellung eines Jobs sind einige Schritte und Objekte nötig, am Ende ist aber alles viel einfacher als man denkt und man hat eine sehr übersichtliche Möglichkeit, Jobs für Aufgaben zu erstellen. Mit den Parametern hat man die maximale Flexibilität für Eingaben von außen, dies ähneln sehr stark den Selektionsbildern von Reports.


Enthaltene Themen:
BTPApplication JobABAP Environment
Kommentare (0)



Und weiter ...

Bist du zufrieden mit dem Inhalt des Artikels? Wir posten jeden Freitag neuen Content im Bereich ABAP und unregelmäßig in allen anderen Bereichen. Schaue bei unseren Tools und Apps vorbei, diese stellen wir kostenlos zur Verfügung.


RAP - Popup Defaultwerte

Kategorie - ABAP

Wie kannst du im Popup einer Aktion in RAP dem User Defaultwerte zur Verfügung stellen? In diesem Artikel erweitern wir unsere Anwendung.

21.01.2025

RAP - Popup Pflichtfelder

Kategorie - ABAP

Wie kannst du eigentlich Pflichtfelder für ein Popup in RAP definieren? In diesem Artikel werden wir etwas genauer auf die Details eingehen.

14.01.2025

RAP - Deep Table Action

Kategorie - ABAP

Ist die Übergabe von Tabellen an Aktionen in RAP aktuell möglich? Dieser Artikel soll einen besseren Einblick in das Thema gewähren.

07.01.2025

RAP - Side Effects

Kategorie - ABAP

Wie kannst du Teile der Fiori UI aktualisieren, ohne einen kompletten Refresh zu machen? Mit Side Effects ist das in ABAP und RAP ganz leicht möglich.

27.12.2024

RAP - Events

Kategorie - ABAP

Wie kannst du eigentlich Events in RAP erzeugen und mit ABAP verarbeiten? Hier erfährst du mehr zur eventgetriebenen Verarbeitung.

23.12.2024