Mit BOPF arbeiten

Gliederung:

Modellierung – Design Time Tools

Wir unterscheiden 

  • Design Time: das Business Objekt (BO) wird modelliert. Festgelegt werden Datenstrukturen in Knoten (Nodes), Schlüssel und Aktionen die das BO Verhalten steuern. Die Dictionary-Objekte und die Konstantenschnittstelle werden generiert.
  • Run Time: ein Verbraucher (Anwendung) erzeugt BOs über einen Service Manager. Aktionen werden in der Interaction Phase ausgeführt. Mit dem Transaktionsmanager wird die Save/Cleanup Phase gestartet.

In der Design Time Tools sind

  • Transaktion BOB – Business Object Builder
  • Transaktion BOBX – Business Object Builder Expert
  • Transaktion BOBF 
  • BOPF Eclipse Plug-In 
  • Transaktion BOBT zum Testen von BOs.

Ich empfehle Transaktion BOBX zur Bearbeitung eines BOPF Modells. Aus dem Menüpunkt Springen kann die erweiterte Sicht aktiviert werden, womit die Knoten der im System vorhandene BOs angezeigt werden.

Referenzen:

Nachrichten

Validierungen, Ermittlungen und Aktionen erzeugen Nachrichten, die das Interface /BOBF/IF_FRW_MESSAGE implementieren. Eine BOPF-Nachricht ist immer nur für den Enduser gedacht. Sie spielt in der Verarbeitung keine Rolle. Die Nachrichten lassen sich in sehr unterschiedlichen Anwendungen (User Interfaces) einblenden. 

Für jedes Projekt wird empfohlen, eine eigene Hilfsklasse mit der Oberklasse /BOBF/CM_FRW anzulegen. Diese kann neue Nachrichtenobjekte anlegen und mit ADD_MESSAGE( ) hinzufügen. 

Knoten

Die Knoten haben eine baumartigen Knotenstruktur mit einem Wurzelknoten meistens ROOT und Unterknoten, z.B. eine Belegkopf und einen Knoten für die Positionen. In den Knoten wird das Verhalten modelliert.

Bemerkung: zur Laufzeit ist ein Knoten ist ein Container, vergleichbar mit einer ABAP internen Tabelle. Ein Objekt ist eine Zeile im Container und erhält eine global eindeutige Kennung (GUID). Der Verbraucher nutzt den Servicemanager um Aktionen über das aufzurufen. Diese Aufrufe haben für beliebigen BOs dieselbe Struktur, dank dem Command Pattern .

Knotenstruktur

Die Knoten können sowohl persistente Attribute enthalten, die auf der Datenbank abgelegt werden als auch transiente Attribute, die immer berechnet werden.

Technischer Schlüssel

Das technische Include /BOBF/S_FRW_KEY_INCL für Schlüssel ist für alle BO gleich (GUID für den Primärschlüssel KEY, GUID für den übergeordneter BO PARENT_KEY und GUID für die Wurzel der Knotenstruktur ROOT_KEY:

Alternative Schlüssel

Das BO Datenmodell wird in den Attribute mit dem Gruppenname NODE_DATA gepflegt.. Ein klassischer lesbarer Primärschlüssel wird oft noch definiert. In diesem Fall sollte ein Datenbank-Index definiert werden.

Die Datenstruktur mit dem Gruppenname TRANSIENT_NODE_DATA enthält die transiente Daten, die nur zur Laufzeit über Ermittlungen bestimmt werden.

Die Methode CONVERT_ALTERN_KEY( ) wird benutzt, um alternative Schlüssel in GUID umzusetzen.

Knotenelemente

Jeder Knoten hat Knotenelemente und optionale Konsistenzgruppen. Die Gruppe darf ein Fehlerstatus definieren, wo kein Speichern möglich ist.

Die generierte Konstantenschnittstelle definiert lesbare Namen für die GUID. Berechtigungen können auf Knotenebene geprüft werden.

An den Knoten werden Funktionen für Aktionen, Ermittlungen, Abfragen, … angehängt. Dazu legt man ABAP Klassen an, die nach dem Command Pattern das Interface implementieren.

Ansicht eines Business Object in Transaktion BOBX:

Assoziationen

Eine Assoziation definert eine Beziehung zwischen BO-Knoten und prägt damit das Datenmodell. Am häufigsten wird im Read API Methode RETRIEVE_BY_ASSOCIATION( ) verwendet, um auf einfach auf abhängige Objekte zuzugreifen.

Abfragen

Eine BOPF Abfrage liefert ähnlich einer SQL-Abfrage nur persistente Daten. Abfragen werden machen Sinn, wenn sie vom Verbraucher zu Beginn einer Anwendung ausgeführt werden, um die BOPF GUIDs zu holen. Innerhalb benutzt man die READ API-Methoden retrieve() oder retrieve_by_association()  des Service-Managers. RETRIEVE( ) kann auch die Datenbank lesen, falls es vom Service Manager mit dem Parameter IV_BEFORE_IMAGE = ‘X’ aufgerufen wird.

Die Abfragen

  • SELECT_ALL und
  • SELECT_BY_ELEMENTS

werden vom BOPF bei Bedarf generiert. Andere Abfrage wie SELECT_BY_ATTRIBUTES müssen das Interface /BOBF/IF_FRW_QUERY implementieren.

Aktionen

Aktionen sind vergleichbar mit öffentlichen Klassenmethoden, die Attribute verändern. Eine Aktion bearbeiten immer eine Liste von BO Schlüsselfelder. Technisch wird sie als Methode EXECUTE( ) des Interfaces /BOBF/IF_FRW_ACTION implementiert.

Innerhalb der Aktion werden über das READ API retrieve( ) aus den Schlüsseln die kompletten Datensätze gelesen und verändert. Die Änderungen werden ins Puffer über das MODIFY API update( ) geschrieben. Im Beispiel wird dann eine Nachricht erzeugt.

Das BOPF API ist untypisiert und arbeitet mit Datenreferenzen. Daher werden oft Referenzen auf lokale Daten angelegt, verändert und zum Speichern weitergegeben.

METHOD /bobf/if_frw_action~execute.

DATA ls_textid LIKE if_t100_message=>t100key.

DATA lv_severity TYPE zcm_proddevord=>ty_message_severity.

io_read->retrieve( EXPORTING iv_node = zif_proddevord_c=>sc_node-root

                                   it_key = it_key

                     IMPORTING   eo_message = eo_message

                               et_data = lt_root

                               et_failed_key = et_failed_key ).

LOOP AT lt_root REFERENCE INTO DATA(lr_head).

         lr_head->notify_loop = zcl_pu_global=>c_loop_initial.

         lr_head->qstatus = zcl_pu_global=>c_qstatus_first_step.

         CLEAR lr_head->wait_until.

         CLEAR lr_head->wait_for_action.

         io_modify->update( iv_node   = is_ctx-node_key 

                            iv_key    = lr_head->key

                        iv_root_key   = lr_head->root_key

                          is_data   = lr_head

                             it_changed_fields = VALUE #( 

( zif_proddevord_c=>sc_node_attribute-root-qstatus )

( zif_proddevord_c=>sc_node_attribute-root-notify_loop )

( zif_proddevord_c=>sc_node_attribute-root-wait_until )

( zif_proddevord_c=>sc_node_attribute-root-wait_for_action ) ) ).

   io_modify->end_modify( EXPORTING iv_process_immediately = abap_true

                          IMPORTING eo_message = DATA(lo_message) ).

   IF lo_message IS BOUND AND lo_message->check( ).

        ls_textid = zcm_proddevord=>reset_counter_error.

        lv_severity = /bobf/cm_frw=>co_severity_error.

   ELSE.

        ls_textid = zcm_proddevord=>reset_counter_success.

       lv_severity = /bobf/cm_frw=>co_severity_info.

   ENDIF.

   zcm_proddevord=>add( EXPORTING textid   = ls_textid

                                     severity = lv_severity

                                     node_key = is_ctx-node_key

                                     ir_pu = lr_head

                        CHANGING co_message = eo_message ).

ENDLOOP.

  ENDMETHOD.

Validierungen

im Objektmodell würde man Validierung als Methoden abbilden. Im BOPF sind diese so weil die eine UI unabhängige Validierung von Attributen erst ermöglichen. Im BOPF gibt es 

  • Aktionsvalidierungen: diese werden vor der verbundenen Aktion automatisch durchlaufen. Eine Validierung liefert Failed Keys zurück, d.h. BO für die Validierung fehlgeschlagen ist. Für diese BO findet keine Ausführung der verbundenen Aktion. 
  • Konsistenzvalidierungen: diese werden nach einer Attributänderung durchlaufen und können den Status einer Konsistenzgruppe ändern. Damit kann u.U. vermieden werden, dass die Daten gesichert werden. Es wird auf jeden Fall die Aktion ausgeführt.

Das Attribut Failed Keys macht nur bei Validierung Sinn. Eine Aktion die Failed Key liefert wurde bereits ausgeführt. Daher sollte wirklich inhaltlich Aktionen von Validierungen getrennt werden. Ermittlungen die Failed Key zurückliefern werden vom BOPF später wieder mit demselben Schlüssel (für dasselbe BO) wiederholt, bis kein Failed Key zurückgeliefert wird. Dann erst ist Speichern möglich. BOPF nimmt an, Eingabewerte würden fehlen.

METHOD /bobf/if_frw_validation~execute.

DATA lt_root TYPE zpu_t_root.     

io_read->retrieve( EXPORTING iv_node = zif_proddevord_c=>sc_node-root

                              it_key = it_key

                    IMPORTING eo_message = eo_message

                              et_data = lt_root

                                 et_failed_key = et_failed_key ).

et_failed_key = VALUE #( FOR ls_root IN lt_root 

  WHERE ( NOT ( zprstk EQ zcl_pu_global=>c_pu_status_waiting_for_order

            AND qstatus EQ zcl_pu_global=>c_qstatus_idle ) ) 

                     ( key = ls_root-key ) ).

  ENDMETHOD.

Ermittlungen

Transiente Attribute werden vom BOPF automatisch aktualisiert, mit einer eigene Kategorie von Routinen, die sog. Determinations Ermittlungen. In BOPF werden Ermittlungen automatisch bei Änderungen aufgerufen und implementieren so das Konzept der reaktiven Programmierung, wie bei Datenbank-Trigger. 

Beispiel: a = 1. b = 2. Eine Ermittlung berechnet das transiente Attribut s = a + b und s hat zunächst den Wert 3. Setzt man a = 2, dann wird die Ermittlung im Hintergrund aufgerufen und s auf 4 gesetzt. 

Ermittlungen können z.B. transiente Attribute nachladen. Der Wizard in der Transaktion BOB führt durch die verschiedene Anwendunsfälle und setzt die Auswertungszeitpunkte, die bei Transaktion BOBX selbst eingestellt werden müssen.

Transaktionsmodel

Der Transaktionsmanager verwaltet Lese- und Schreibzugriffe auf BO Attribute mit einem Puffer.

In sog. Interaction Phase werden die Operationen

  • Anlegen
  • Lesen
  • Ändern
  • Löschen
  • Aktion ausführen
  • Finalize
  • Check before Save
  • Adjust numbers
  • Save
  • After Save

schreibt den Puffer dann in konsistenten Datenbank-Objekte  oder nimmt dies Änderungen zurück (Cleanup Phase).

Um BOPF mit existieren Verbuchungsfunktionsbausteinen zu kombinieren kann es notwendig werden, spezielle Klasse für den Datenzugriff zu benutzen. Zwei solche Data Access Classes (DAC) sind verfügbar:  /BOBF/CL_DAC_TABLE und /BOBF/CL_DAC_LEGACY_TABLE).

Zusätzlich kann es notwendig sein, die Kontrolle in der Save Phase abzugeben, indem ein Slave Transaktionsmanager benutzt wird. Bei komplexen Transaktion kann mit Sync Points einen Teil-Rollback realisiert werden.