[ABAP] ITS: HTML aus einem Dynpro generieren

* Paket: SITS_ABAP

* SE11 - Report
DATA: lv_prog TYPE d020s-prog VALUE 'SAPLSD_ENTRY'.
* Dynpro 1000
DATA: lv_dynnr TYPE d020s-dnum VALUE '1000'.
* '' / C - Classic, B - HTML-Business, W - WebGUI
DATA: lv_style TYPE w3style VALUE 'B'.

DATA: lv_html_xstr TYPE xstring.
DATA: it_html TYPE STANDARD TABLE OF w3html WITH DEFAULT KEY.

* Template von Dynpro generieren
CALL FUNCTION 'ITS_GENERATE_HTML_FROM_DYNPRO'
  EXPORTING
    progname                       = lv_prog
    dynnr                          = lv_dynnr
    style_2006                     = lv_style
  IMPORTING
    source_stream                  = lv_html_xstr
  TABLES
    meta_html                      = it_html
  EXCEPTIONS
    style_not_valid                = 1
    dynnr_or_programname_not_valid = 2
    css_not_valid                  = 3
    xsl_not_valid                  = 4
    placeholder_not_valid          = 5
    no_card_identifiers_used       = 6
    error_occured                  = 7
    OTHERS                         = 8.

IF sy-subrc = 0.
  cl_demo_output=>write_data( it_html ).
  DATA(lv_html) = cl_demo_output=>get( ).

* Daten im Inline-Browser im SAP-Fenster anzeigen
  cl_abap_browser=>show_html( EXPORTING
                                title        = 'HTML'
                                html_string  = lv_html
                                container    = cl_gui_container=>default_screen ).

* cl_gui_container=>default_screen erzwingen
  WRITE: space.
ENDIF.

[ABAP] Semantisches Objekt im Fiori-Launchpad anzeigen

* Semantisches Objekt
PARAMETERS: p_semobj TYPE /ui2/v_semobj-sem_obj LOWER CASE DEFAULT 'SalesOrder'.
* Action
PARAMETERS: p_semact TYPE char80 LOWER CASE DEFAULT 'displayFactSheet'.
* Parameter
PARAMETERS: p_sempar TYPE char80 LOWER CASE DEFAULT 'SalesOrder'.
* Value
PARAMETERS: p_parval TYPE char80 LOWER CASE DEFAULT '1'.

START-OF-SELECTION.

* URL Parameter
  DATA(it_parameters) = VALUE tihttpnvp( ( name = 'sap-client'      value = sy-mandt )
                                         ( name = 'sap-ui-language' value = 'DE' )
                                         ( name = 'sap-ui-appcache' value = 'false' ) ).

* Browser URL mit HOST:PORT und Parametern zusammenbauen
  DATA(lv_url) = /ui5/cl_theme_util=>get_server_url( path         = |/sap/bc/ui5_ui5/ui2/ushell/shells/abap/FioriLaunchpad.html|
                                                     parameters   = it_parameters
                                                     always_https = abap_false  ).

* Pattern:
*    #<semantic object>-<action>?<semantic object parameter>=<value1>
* Beispiel:
*    #SalesOrder-displayFactSheet?SalesOrder=1
  lv_url = |{ lv_url }#{ p_semobj }-{ p_semact }?{ p_sempar }={ p_parval }|.

* leere Standard-Toolbar ausblenden
  cl_abap_list_layout=>suppress_toolbar( ).

* URL anzeigen
  DATA(o_hv) = NEW cl_gui_html_viewer( parent = cl_gui_container=>default_screen ).
  o_hv->show_url( url = CONV swk_url( lv_url )
                  in_place = abap_true ). " im SAP-Fenster (abap_true) oder im Externen Browser (abap_false) anzeigen

* cl_gui_container=>default_screen erzwingen
  WRITE: space.

[ABAP] Infos zu ICF-Service lesen / Prüfen, ob SSO2-Service aktiv

* Transaktion: SICF
* Tabelle: ICFSERVICE

* Service-Name, hier z.B. MYSSOCNTL (SSO2-Service)
PARAMETERS: p_srv TYPE icfservice-icf_name DEFAULT 'MYSSOCNTL'.

START-OF-SELECTION.

  TRY.
* Suche im Baum der ICF-Services im Internet-Kommunikations-Framework
      SELECT SINGLE icfparguid
        INTO @DATA(lv_icfparguid)
        FROM icfservice
        WHERE icf_name = @p_srv.

      IF sy-subrc = 0.
        DATA: lv_hostnr	TYPE icfhostnum.       " Nummer eines virtuellen Hosts
        DATA: it_serv_info TYPE icfservtbl.    " Tabelle von ICF-Services und deren zugehörige Handler
        DATA: lv_url TYPE string.              " URL zu Service
        DATA: lv_active	TYPE c.                " Service aktiv oder inaktiv
        DATA: lv_icfdocu TYPE icfdocu.         " Documentation der ICFSERVICE Einträge
        DATA: lv_icf_custstr TYPE icf_custstr. " ICF: String für customizingdaten der Anwendung
        DATA: lv_serv_sign TYPE c.             " Kz, um welche Art v. Service (Host, int Alias, Service)
        DATA: lv_host_info TYPE icfvirhost.    " Internet Communication Framework: Virtuelle Hosts

* Liefert Informationen zu ICF-Service
        cl_icf_tree=>if_icf_tree~get_info_from_serv( EXPORTING
                                                       icf_name        = p_srv
                                                       icfparguid      = lv_icfparguid
                                                       authority_check = abap_false
                                                     IMPORTING
                                                       hostnr          = lv_hostnr
                                                       serv_info       = it_serv_info
                                                       url             = lv_url
                                                       active          = lv_active
                                                       icfdocu         = lv_icfdocu
                                                       icf_custstr     = lv_icf_custstr
                                                       serv_sign       = lv_serv_sign
                                                       host_info       = lv_host_info
                                                   ).

        cl_demo_output=>write_data( lv_hostnr ).

        IF lines( it_serv_info ) > 0.
          DATA(lv_srv_info) = it_serv_info[ 1 ].
          cl_demo_output=>write_data( lv_srv_info-service ).
          cl_demo_output=>write_data( lv_srv_info-handlertbl ).
          cl_demo_output=>write_data( lv_srv_info-pathfields ).
        ENDIF.

        cl_demo_output=>write_data( lv_url ).
        cl_demo_output=>write_data( lv_active ).
        cl_demo_output=>write_data( lv_icfdocu ).
        cl_demo_output=>write_data( lv_icf_custstr ).
        cl_demo_output=>write_data( lv_serv_sign ).
        cl_demo_output=>write_data( lv_host_info ).

        DATA: lv_urlsuffix TYPE icfredurl.    " Rest einer Url nach ICF-Service
        DATA: lv_icfnodguid TYPE icfnodguid.  " Nodguid des letzen service im Pfad
        DATA: lv_icf_name TYPE icfname.       " Name des letzen Service im ICF-Baum
        DATA: lv_int_alias TYPE icfalias.     " Kein Service sondern interner Alias
        DATA: lv_ext_alias TYPE icfalias.     " Kein Service sondern externer Alias
        DATA: lv_icfactive TYPE icfactive.    " Service ist aktiv
        DATA: lv_icfaltnme TYPE icfaltnme.    " Alternative Namensgebung

* Ermittelt aus einer URL dem letzten Service im ICF-Baum
        cl_icf_tree=>if_icf_tree~service_from_url( EXPORTING
                                                    url             = lv_url
                                                    hostnumber      = lv_hostnr
                                                    authority_check = abap_false
                                                   IMPORTING
                                                    urlsuffix  = lv_urlsuffix
                                                    icfnodguid = lv_icfnodguid
                                                    icf_name   = lv_icf_name
                                                    int_alias  = lv_int_alias
                                                    ext_alias  = lv_ext_alias
                                                    icfactive  = lv_icfactive
                                                    icfaltnme  = lv_icfaltnme
                                                  ).

        cl_demo_output=>write_data( lv_urlsuffix ).
        cl_demo_output=>write_data( lv_icfnodguid ).
        cl_demo_output=>write_data( lv_icf_name ).
        cl_demo_output=>write_data( lv_int_alias ).
        cl_demo_output=>write_data( lv_ext_alias ).
        cl_demo_output=>write_data( lv_icfactive ).
        cl_demo_output=>write_data( lv_icfaltnme ).

* ist Service aktiv
        DATA(lv_is_active) = cl_icf_tree=>is_service_active( nodeguid	= lv_icfnodguid
*                                                             URL =
*                                                             HOSTNAME =
                                                           ).

        cl_demo_output=>write_data( lv_is_active ).

* HTML-Code vom Demo-Output holen
        DATA(lv_html) = cl_demo_output=>get( ).

* Daten im Inline-Browser im SAP-Fenster anzeigen
        cl_abap_browser=>show_html( EXPORTING
                                      title        = 'ICF-Service-Info'
                                      html_string  = lv_html
                                      container    = cl_gui_container=>default_screen ).

*         cl_gui_container=>default_screen erzwingen
        WRITE: space.
      ENDIF.
    CATCH cx_root INTO DATA(e_txt).
  ENDTRY.

[ABAP] URL-Aufruf mit SSO-Anmeldung

* NULL-Referenz auf Container
CONSTANTS: null TYPE REF TO cl_gui_container VALUE IS INITIAL.

* aufzurufende URL
DATA(lv_url) = |https://www.google.de|.

* Browserfenster ohne Container
DATA(o_hv) = NEW cl_gui_html_viewer( parent = null ).
* SSO
o_hv->enable_sapsso( enabled = abap_true ).
* URL anzeigen
o_hv->detach_url_in_browser( CONV swk_url( lv_url ) ).
* Führt alle gesammelten OLE-Calls aus
cl_gui_cfw=>flush( ).

[ABAP] RegEx: HTML-Tags aus String entfernen

* HTML
DATA(lv_html) = |<!DOCTYPE html>| &&
                |<html>| &&
                |<head>| &&
                |  <meta charset="utf-8">| &&
                |  <meta name="viewport" content="width=device-width">| &&
                |  <title>DOM Read</title>| &&
                |</head>| &&
                |<body>| &&
                |  <div id="bodytext"><b>Hallo Welt!</b></div>| &&
                |  <div id="bodytext">Weiterlesen: <a href="https://codezentrale.de">Link</a></div>| &&
                |</body>| &&
                |</html>|.

* Alle HTML-Tags finden
DATA(matcher) = cl_abap_matcher=>create( pattern     = '<([!A-Za-z][A-Za-z0-9]*)([^>]*)>|</([A-Za-z][A-Za-z0-9]*)>'
                                         text        = lv_html
                                         ignore_case = abap_true ).

* Alle gefundenen HTML-Tags mit '' ersetzen
IF matcher->replace_all( '' ) > 0.
  WRITE: / matcher->text.
ELSE.
  WRITE: / |Keine Tags gefunden.|.
ENDIF.

[ABAP] Google-API: QR-Code generieren und Bild herunterladen/speichern

* Dateiname der Bilddatei zum hochladen
PARAMETERS: p_fname TYPE file_table-filename OBLIGATORY.

START-OF-SELECTION.
* URL zur Google-API für die Erstellung des QR-Codes
  DATA(lv_url) = |http://chart.apis.google.com/chart?chs=200x200&cht=qr&chld=\|1&chl=viele%20lustige%20Zeichen/chart.png|.

  TRY.
      DATA: o_client TYPE REF TO if_http_client.
* Client-Objekt erzeugen
      cl_http_client=>create_by_url( EXPORTING
                                       url     = lv_url
                                     IMPORTING
                                       client  = o_client ).
      IF sy-subrc = 0.
* HTTP GET senden
        o_client->send( ).

* Response lesen
        o_client->receive( ).

        DATA: lv_http_status TYPE i.
        DATA: lv_status_text TYPE string.

* HTTP Return Code holen
        o_client->response->get_status( IMPORTING
                                          code   = lv_http_status
                                          reason = lv_status_text ).

* Wenn Status 200 (Ok)
        IF lv_http_status = 200.

* Binärdaten (QR-Code) auslesen
          DATA(lv_xdata) = o_client->response->get_data( ).

          o_client->close( ).

* xstring -> solix
          DATA(it_img_conv_data) = cl_bcs_convert=>xstring_to_solix( iv_xstring = lv_xdata ).

          WRITE: / |{ p_fname }.png|.

* Image lokal speichern
          cl_gui_frontend_services=>gui_download( EXPORTING
                                                    filename     = |{ p_fname }.png|
                                                    filetype     = 'BIN'
                                                    bin_filesize = xstrlen( lv_xdata )
                                                  CHANGING
                                                    data_tab     = it_img_conv_data ).

        ENDIF.
      ENDIF.
    CATCH cx_root INTO DATA(e_txt).
      WRITE: / e_txt->get_text( ).
  ENDTRY.

[ABAP] Einfacher REST-Service (ohne OData)

Piyush Philip auf sap.com hat eine simple Möglichkeit beschrieben, wie man in ABAP einen REST-Service mit den entsprechenden CRUD-Methoden implementieren kann. Dazu ist im wesentlichen nur eine eigene Handler-Klasse zu implementieren, die von IF_HTTP_EXTENSION erbt. Diese Handler-Klasse wird von einem Service des ICF gerufen.

  1. SE80 -> Neue Klasse anlegen
  2. In der Klasse im Reiter Interfaces: vom Interface IF_HTTP_EXTENSION erben
  3. die Interface-Methode IF_HTTP_EXTENSION~HANDLE_REQUEST implementieren (implementiert nur REST, kein OData-Sevice!)
    METHOD if_http_extension~handle_request.
    
    * Typen
        TYPES: BEGIN OF ty_json_request,
                 param1 TYPE char64,
                 param2 TYPE char64,
               END OF ty_json_request.
    
        TYPES: BEGIN OF ty_json_response,
                 success   TYPE string,
                 msg       TYPE string,
                 operation TYPE string,
               END OF ty_json_response.
    
    * Variablen
        DATA: rv_response TYPE ty_json_response.
        DATA: it_path_info TYPE stringtab.
        DATA: it_query_strings TYPE stringtab.
    
    * Header Fields auslesen
        DATA: it_header_fields TYPE tihttpnvp.
        server->request->get_header_fields( CHANGING fields = it_header_fields ).
    
    * Request Methode (POST, GET, PUT, DELETE ...)
        DATA(lv_request_method) = server->request->get_header_field( name = '~request_method' ).
    
    * URL Pathinfo
        DATA(lv_path_info) = server->request->get_header_field( name = '~path_info' ).
    * erstes '/' entfernen
        SHIFT lv_path_info LEFT BY 1 PLACES.
        SPLIT lv_path_info AT '/' INTO TABLE it_path_info.
    
    * URL Parameter (Query Strings) für Auswertung
        DATA(lv_query_string) = server->request->get_header_field( name = '~query_string' ).
        SPLIT lv_query_string AT '&' INTO TABLE it_query_strings.
    
    * Request Methoden behandeln
        CASE lv_request_method.
    * C (Create)
          WHEN 'POST'.
    * Beispiel: per Request übermittelte JSON-Daten auslesen und behandeln
    * Content-Typ auslesen
            DATA(lv_request_content_type) = server->request->get_content_type( ).
    
    * Wenn Content-Typ JSON
            IF lv_request_content_type CP if_rest_media_type=>gc_appl_json.
    * JSON-Daten auslesen und nach ABAP-Typ konvertieren -> Parameternamen müssen übereinstimmen, sonst HTTP 500!
              DATA(lv_request_cdata) = server->request->get_cdata( ).
    
              DATA: lv_request_abap TYPE ty_json_request.
    
              TRY.
                  /ui2/cl_json=>deserialize( EXPORTING json = lv_request_cdata
                                                       pretty_name = /ui2/cl_json=>pretty_mode-camel_case
                                             CHANGING  data = lv_request_abap ).
    
                CATCH cx_root INTO DATA(e_txt).
                  MESSAGE e_txt->get_text( ) TYPE 'S' DISPLAY LIKE 'E'.
              ENDTRY.
    
              rv_response = VALUE #( success   = 'true'
                                     msg       = lv_request_abap-param1 && ' | ' && lv_request_abap-param2
                                     operation = lv_request_method ).
            ELSE.
              rv_response = VALUE #( success   = 'false'
                                     msg       = 'Request content type must be application/json'
                                     operation = lv_request_method ).
            ENDIF.
    * R (Read)
          WHEN 'GET'.
            DATA(lv_param) = server->request->get_form_field( 'param' ).
    
            rv_response = VALUE #( success   = 'true'
                                   msg       = lv_param
                                   operation = lv_request_method ).
    * U (Update)
          WHEN 'PUT'.
            rv_response = VALUE #( success   = 'true'
                                   msg       = ''
                                   operation = lv_request_method ).
    * D (Delete)
          WHEN 'DELETE'.
            rv_response = VALUE #( success   = 'true'
                                   msg       = ''
                                   operation = lv_request_method ).
    
    * unerlaubte Methoden abfangen
          WHEN OTHERS.
    * Fehlercode 405 zurückgeben
            server->response->set_status( code   = cl_rest_status_code=>gc_client_error_meth_not_allwd
                                          reason = 'method not allowed' ).
    
            server->response->set_content_type( if_rest_media_type=>gc_appl_json ).
    
            server->response->set_header_field( name  = if_http_header_fields=>allow
                                                value = 'POST,GET,PUT,DELETE' ).
    
            rv_response = VALUE #( success   = 'false'
                                   msg       = 'error'
                                   operation = lv_request_method ).
        ENDCASE.
    
    * wenn erfolgreich, dann Wert zurückgeben
        IF rv_response-success = 'true'.
    * HTTP-Status 200
          server->response->set_status( code   = cl_rest_status_code=>gc_success_ok
                                        reason = 'Ok.' ).
    
    * application/json
          server->response->set_content_type( if_rest_media_type=>gc_appl_json ).
    
    * Service-Response als JSON zurückgeben
          server->response->set_cdata( data = /ui2/cl_json=>serialize( data        = rv_response
                                                                       pretty_name = /ui2/cl_json=>pretty_mode-camel_case ) ).
    
        ENDIF.
    
    ENDMETHOD.
    
  4. SICF -> neue ICF-Node (Sub-Element) unterhalb default_host -> sap -> bc als neuen unabhängigen Service anlegen
  5. in der Handlerliste des Service die erstellte Klasse als „Handler“ angeben
  6. auf die neue ICF-Node rechtsklicken -> Service aktivieren
  7. auf die neue ICF-Node rechtsklicken -> Service testen
  8. URL aus Browserfenster kopieren (http://domain.de/sap/bc/servicename?sap-client=900)
  9. im Browser mir einem Rest-Plugin (FireFox-Prugin: Rested) testen

Links