[ABAP] Archivierte Objekte lesen

*  Beispiele:
*
*  https://www.abapforum.com/forum/viewtopic.php?t=1196
*  https://copycodesap.wordpress.com/2014/10/27/custom-table-archival-read-program/
*
*  Transaktion:
*    ALO1 (Ermitteln Verknüpfungen ASH/DOREX)
*
*  Reports:
*    SBOOKR
*    SBOOKR_2
*    SBOOKR_3
*    RDRBFI00
*
*  Paket: SARC
*  Funktionsgruppe: ARCH
*
*  Funktionsbausteine:
*
*    ARCHIVE_CLOSE_FILE (Offene Archivdateien werden geschlossen)
*    ARCHIVE_GET_CUSTOMIZING_DATA (Customizing-Daten eines Archivierungsobjektes lesen)
*    ARCHIVE_GET_INFORMATION (Archivobjekt-Informationen werden aufgrund eines Handles übergeben)
*    ARCHIVE_GET_NEXT_OBJECT (Datenobjekt aus der Archivdatei lesen)
*    ARCHIVE_GET_NEXT_RECORD (Sequentielles Lesen der Sätze aus einem Datenobjekt)
*    ARCHIVE_GET_STATISTICS (Übernahme der vom ADK gesammelten Statistikdaten)
*    ARCHIVE_GET_TABLE (Sätze strukturgerecht aus aktuellem Datenobjekt lesen)
*    ARCHIVE_GIVE_STATISTICS (Übergabe von Statistikdaten in Programmen der Datenarchivierung)
*    ARCHIVE_NEW_OBJECT (Datenobjekt zum Schreiben anfordern)
*    ARCHIVE_OPEN_FOR_DELETE (Archivdatei öffnen zum Löschen der Sätze in der Datenbank)
*    ARCHIVE_OPEN_FOR_MOVE (Datenobjekte in eine neue Archivdatei schreiben und/oder zurückladen)
*    ARCHIVE_OPEN_FOR_READ (Öffnen einer vorhandenen Archivdatei zum Lesen)
*    ARCHIVE_OPEN_FOR_WRITE (Archivdatei zum Schreiben öffnen)
*    ARCHIVE_PUT_RECORD (Datensatz in Datenobjekt schreiben)
*    ARCHIVE_PUT_TABLE (Sätze strukturgerecht in aktuelles Datenobjekt stellen)
*    ARCHIVE_READ_OBJECT (Lesen eines Datenobjektes aus einer Archivdatei)
*    ARCHIVE_SAVE_OBJECT (Datenobjekt in die Archivdatei schreiben)
*    ARCHIVE_WRITE_STATISTICS (Ausgabe der vom ADK gesammelten Statistikdaten (Standardprotokoll))
*
*  Paket: SWW
*  Funktionsgruppe: SWWX
*
*  Funktionsbausteine:
*
*    WORKITEM_ARCHIVE_GET_TABLE (Lesen von archivierten Workitems)
*    WORKITEM_ARCHIVE_OBJECT (Archivierungsklasse WORKITEM: Schreiben eines Workitems in ein Archiv)
*    WORKITEM_ARCHIVE_PUT_TABLE (Übergabe konvertierter Daten an das ADK)
*    WORKITEM_READ_ARCHIVE_OBJ (Archivierungsklasse WORKITEM: Lesen von Workitems aus dem Archiv)
*
*  Tabellen:
*
*    ARCH_OBJ (Objekte für die Archivierung und Reorganisation)
*    ARCH_TXT (Bezeichnung der Archivierungsobjekte)
*    ARCH_DEF (Definition eines Archivierungsobjekts)
*    ADMI_RUN (Archivierungsläufe Kopfdaten)
*    ADMI_FILES (Archivdateien der Archivierungsläufe)
*    PATH (Definition der physischen Dateipfade je Syntax)
*    FILENAME (Umsetztabelle von internen Dateinamen in externe Dateinamen)
*    FILESYS (Definition der Gruppen der Dateibeschreibungssyntax)
*    FSYSTXT (Bezeichnung der Dateibeschreibungssyntax)
*    FILENAMECI (Plattformunabhängige Dateinamen, mandantenübergreifend)
*    FILEPATH (Definition der logischen Dateipfade)
*    PATHTEXT (Bezeichnung der logischen Dateipfade)
*
*  Customizing Dateipfade:
*
*  Transaktion FILE
*  oder
*  SPRO -> SAP NetWeaver -> Application Server -> Systemadministration -> Plattformunabhängige Dateinamen -> Dateinamen und Dateipfade mandantenunabhängig pflegen

* Archivierungsobjekt
PARAMETERS: p_obj TYPE arch_def-object DEFAULT 'CHANGEDOCU'.

DATA(lv_handle) = VALUE sy-tabix( ).
DATA: it_archive_files TYPE STANDARD TABLE OF rng_archiv WITH DEFAULT KEY.
DATA: it_selected_files TYPE STANDARD TABLE OF admi_files WITH DEFAULT KEY.

* Öffnen einer vorhandenen Archivdatei zum Lesen
* wenn nur ein Wert für "object" angegeben wurde, dann erscheint ein Auswahl-Popup
CALL FUNCTION 'ARCHIVE_OPEN_FOR_READ'
  EXPORTING
*   archive_document             = '000000'
*   ARCHIVE_NAME                 = ' '
    object                       = p_obj
*   MAINTAIN_INDEX               = ' '
  IMPORTING
    archive_handle               = lv_handle
  TABLES
    archive_files                = it_archive_files
    selected_files               = it_selected_files
  EXCEPTIONS
    file_already_open            = 1
    file_io_error                = 2
    internal_error               = 3
    no_files_available           = 4
    object_not_found             = 5
    open_error                   = 6
    not_authorized               = 7
    archiving_standard_violation = 8
    OTHERS                       = 9.

IF sy-subrc = 0.
* Testweise den externen Speicherpfad im UNIX-Dateisystem ermitteln
  LOOP AT it_selected_files ASSIGNING FIELD-SYMBOL(<f>).
    SELECT SINGLE pathextern
      INTO @DATA(lv_pathextern)
      FROM path
      WHERE pathintern = @<f>-pathintern
        AND filesys = 'UNIX'.

    WRITE: / <f>-document, <f>-archiv_key, <f>-pathintern, lv_pathextern.
  ENDLOOP.

  ULINE.

  DO.
* Datenobjekt aus der Archivdatei lesen
    CALL FUNCTION 'ARCHIVE_GET_NEXT_OBJECT'
      EXPORTING
        archive_handle          = lv_handle
*         IMPORTING
*       OBJECT_ID               =
*       OBJECT_OFFSET           =
*       ARCHIVE_NAME            =
*       COMPR_OBJECT_LENGTH     =
*       SESSION                 =
*       EV_CONTAIN_BLOCKED_DATA =
      EXCEPTIONS
        end_of_file             = 1
        file_io_error           = 2
        internal_error          = 3
        open_error              = 4
        wrong_access_to_archive = 5
        OTHERS                  = 6.

    IF sy-subrc <> 0.
* Keine Objekte mehr
      EXIT.
    ELSE.
      DO.
        DATA(lv_data_struct) = VALUE arc_buffer-rname( ).
* Datenreferenz -> Unicodefähigkeit
        DATA: o_data_ref TYPE REF TO data.

* Sequentielles Lesen der Sätze aus einem Datenobjekt
        CALL FUNCTION 'ARCHIVE_GET_NEXT_RECORD'
          EXPORTING
            archive_handle   = lv_handle
          IMPORTING
            record_structure = lv_data_struct
            record_ref       = o_data_ref
          EXCEPTIONS
            end_of_object    = 1
            OTHERS           = 2.

        IF sy-subrc <> 0.
* Keine Daten mehr
          EXIT.
        ELSE.
* Farbe definieren
          FORMAT COLOR COL_HEADING.
* Ausgabetext
          WRITE: / 'Struktur:', to_upper( lv_data_struct ).
* Leerzeichen am Zeilenende, damit der Farbbalken durchgezogen wird
          WRITE AT sy-linsz space.
* Farbdefinition abschalten
          FORMAT COLOR OFF.

* Generische Datenausgabe
* Strukturbeschreibung der akt. Archivstruktur
          DATA(o_desc) = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_name( lv_data_struct ) ).
* Komponenten
          DATA(gt_comp) = o_desc->get_components( ).
* generische Objekte für Zugriff
          FIELD-SYMBOLS: <row> TYPE any.
          ASSIGN o_data_ref->* TO <row>.

          DATA(lv_head) = ||.
          DATA(lv_data) = ||.

* Alle Felder der Struktur durchloopen
          LOOP AT gt_comp ASSIGNING FIELD-SYMBOL(<c>).
* Spaltenbreite
            DATA(lv_width) = strlen( <c>-name ).

* Prüfen, ob DDIC-Typ
            DATA(o_edesc) = CAST cl_abap_elemdescr( <c>-type ).
            IF o_edesc->is_ddic_type( ) EQ abap_true.
* Feld anhand des Komponentennamens aus der Struktur ermitteln und Feldsymbol zuweisen
              ASSIGN COMPONENT <c>-name OF STRUCTURE <row> TO FIELD-SYMBOL(<cell>).
              IF <cell> IS ASSIGNED.
* Spaltenbreite, falls Zellinhalt breiter
                IF strlen( condense( <cell> ) ) > lv_width.
                  lv_width = strlen( condense( <cell> ) ).
                ENDIF.

* Formatierung Daten
                lv_data = COND #( WHEN lv_data IS INITIAL THEN |{ condense( <cell> ) WIDTH = lv_width }| ELSE |{ lv_data }\|{ condense( <cell> ) WIDTH = lv_width }| ).
              ENDIF.
            ENDIF.

* Formatierung Kopf
            lv_head = COND #( WHEN lv_head IS INITIAL THEN |{ <c>-name WIDTH = lv_width }| ELSE |{ lv_head }\|{ <c>-name WIDTH = lv_width }| ).

          ENDLOOP.

* Ausgabe
          WRITE: / lv_head.
          WRITE: / lv_data.

          ULINE.
        ENDIF.

      ENDDO.
    ENDIF.
  ENDDO.

* Offene Archivdateien werden geschlossen
  CALL FUNCTION 'ARCHIVE_CLOSE_FILE'
    EXPORTING
      archive_handle = lv_handle.

ENDIF.