"~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. "-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~--~-~-~-~- * * Usage: Using transaction SE80 or SE38, copy & paste the contents of * this file into a new report in a package of your choice. * Activate the report and hit execute. * * Authors: @meyro, @frij * "-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~--~-~-~-~- REPORT /awslabs/sdk_installer. INTERFACE lif_sdk_constants DEFERRED. INTERFACE lif_sdk_internet_manager DEFERRED. INTERFACE lif_sdk_report_update_manager DEFERRED. INTERFACE lif_sdk_certificate_manager DEFERRED. INTERFACE lif_sdk_file_manager DEFERRED. INTERFACE lif_sdk_transport_manager DEFERRED. INTERFACE lif_sdk_job_manager DEFERRED. INTERFACE lif_ui_constants DEFERRED. INTERFACE lif_ui_command DEFERRED. CLASS lcl_sdk_zipfile DEFINITION DEFERRED. CLASS lcl_sdk_zipfile_collection DEFINITION DEFERRED. CLASS lcl_sdk_module DEFINITION DEFERRED. CLASS lcl_sdk_module_collection DEFINITION DEFERRED. CLASS lcl_sdk_internet_manager DEFINITION DEFERRED. CLASS lcl_sdk_report_update_manager DEFINITION DEFERRED. CLASS lcl_sdk_certificate_manager DEFINITION DEFERRED. CLASS lcl_sdk_file_manager DEFINITION DEFERRED. CLASS lcl_sdk_transport_manager DEFINITION DEFERRED. CLASS lcl_sdk_job_manager DEFINITION DEFERRED. CLASS lcl_sdk_package_manager DEFINITION DEFERRED. CLASS lcl_sdk_utils DEFINITION DEFERRED. CLASS lcl_ui_tree_controller DEFINITION DEFERRED. CLASS lcl_ui_command_factory DEFINITION DEFERRED. CLASS lcl_ui_command_base DEFINITION DEFERRED. CLASS lcl_ui_command_exe_dia DEFINITION DEFERRED. CLASS lcl_ui_command_exe_btc DEFINITION DEFERRED. CLASS lcl_ui_command_ins_dia DEFINITION DEFERRED. CLASS lcl_ui_command_ins_btc DEFINITION DEFERRED. CLASS lcl_ui_command_del_dia DEFINITION DEFERRED. CLASS lcl_ui_command_del_btc DEFINITION DEFERRED. CLASS lcl_ui_command_ins_all DEFINITION DEFERRED. CLASS lcl_ui_command_dow_crt DEFINITION DEFERRED. CLASS lcl_ui_command_dow_trk DEFINITION DEFERRED. CLASS lcl_ui_command_ref_ctl DEFINITION DEFERRED. CLASS lcl_ui_command_btc_dtl DEFINITION DEFERRED. CLASS lcl_ui_utils DEFINITION DEFERRED. CLASS lcx_error DEFINITION DEFERRED. CLASS lcl_main DEFINITION DEFERRED. INTERFACE lif_sdk_constants. CONSTANTS: c_trans_logical_path TYPE filepath-pathintern VALUE 'ASSEMBLY' ##NO_TEXT, c_logsubdir_name TYPE fileintern VALUE 'BC_RSTEXTA3' ##NO_TEXT, c_download_uri_prefix TYPE string VALUE '://sdk-for-sapabap.aws.amazon.com/awsSdkSapabapV' ##NO_TEXT, c_sdk_inst_file_prefix TYPE string VALUE 'abapsdk-' ##NO_TEXT, c_sdk_uninst_file_prefix TYPE string VALUE 'uninstall-abapsdk-' ##NO_TEXT, c_sdk_index_json_zip_path TYPE string VALUE 'META-INF/sdk_index.json' ##NO_TEXT, c_transports_zip_path TYPE string VALUE 'transports/' ##NO_TEXT, c_url_internet_check TYPE w3_url VALUE 'http://ocsp.r2m02.amazontrust.com' ##NO_TEXT, c_url_github_raw TYPE w3_url VALUE 'https://raw.githubusercontent.com/awslabs/gui-installer-for-sap-abap-sdk/refs/heads/main/src/%23awslabs%23sdk_installer.prog.abap' ##NO_TEXT. ENDINTERFACE. INTERFACE lif_ui_constants. CONSTANTS: c_operation_none TYPE i VALUE 0, c_operation_install TYPE i VALUE 1, c_operation_delete TYPE i VALUE 2, c_operation_update TYPE i VALUE 3, c_batch_rec_threshold TYPE i VALUE 5, c_sapgui_autologout_threshold TYPE i VALUE 900. ENDINTERFACE. TYPES: BEGIN OF ts_sdk_module, tla TYPE c LENGTH 4, " Three-letter-acronym (sometimes two-letter only) name TYPE string, " Human-readable name cvers TYPE string, " Currently installed version ctransport TYPE string, " Currently installed transport id tp_rc TYPE string, " TP returncode tp_icon TYPE string, " TP icon indicating the state of the transport tp_text TYPE string, " TP human-readable status text avers TYPE string, " Available version atransport TYPE string, " Available transport id is_core TYPE boolean, " Is this a core module? is_popular TYPE boolean, " Is this part of the popular modules group? op_icon TYPE string, " Operation icon for ALV Tree View op_text TYPE string, " Human-readable operation text op_code TYPE string, " What will be happening after user hits execute END OF ts_sdk_module. " https://community.sap.com/t5/application-development-discussions/the-type-of-returning-parameter-must-be-fully-specified/td-p/1731970 TYPES: tt_sdk_module TYPE STANDARD TABLE OF ts_sdk_module WITH KEY tla. TYPES: BEGIN OF ts_sdk_tla, tla TYPE c LENGTH 4, version TYPE string, END OF ts_sdk_tla. TYPES tt_sdk_tla TYPE SORTED TABLE OF ts_sdk_tla WITH UNIQUE KEY tla. CLASS lcx_error DEFINITION INHERITING FROM cx_static_check. PUBLIC SECTION. DATA av_msg TYPE string. DATA av_typ TYPE syst_msgty. DATA av_dsp TYPE syst_msgty. METHODS constructor IMPORTING iv_msg TYPE string iv_typ TYPE syst_msgty DEFAULT 'I' iv_dsp TYPE syst_msgty DEFAULT 'E' previous TYPE REF TO cx_root OPTIONAL. METHODS show. ENDCLASS. CLASS lcx_error IMPLEMENTATION. METHOD constructor. super->constructor( previous = previous ). av_msg = iv_msg. av_typ = iv_typ. av_dsp = iv_dsp. ENDMETHOD. METHOD show. MESSAGE av_msg TYPE av_typ DISPLAY LIKE av_dsp. ENDMETHOD. ENDCLASS. CLASS lcl_sdk_utils DEFINITION FINAL. PUBLIC SECTION. CLASS-METHODS: cmp_version_string IMPORTING i_string1 TYPE string i_string2 TYPE string RETURNING VALUE(r_result) TYPE i, get_client_role IMPORTING i_client TYPE mandt RETURNING VALUE(r_result) TYPE cccategory, get_system_name RETURNING VALUE(r_sysnam) TYPE tmssysnam, get_parameter IMPORTING iv_param TYPE string RETURNING VALUE(rv_value) TYPE string RAISING lcx_error, has_prod_client RETURNING VALUE(r_result) TYPE abap_bool, binary_to_xstring IMPORTING it_bintab TYPE table iv_length TYPE i RETURNING VALUE(ov_xstring) TYPE xstring RAISING lcx_error, raise_lpath_exception IMPORTING i_filename TYPE string RAISING lcx_error. ENDCLASS. CLASS lcl_sdk_utils IMPLEMENTATION. METHOD cmp_version_string. IF i_string1 CO '0123456789.' AND i_string2 CO '0123456789.' AND i_string1 CP '*.*.*' AND i_string2 CP '*.*.*'. SPLIT i_string1 AT '.' INTO TABLE DATA(lt_string1). SPLIT i_string2 AT '.' INTO TABLE DATA(lt_string2). DATA(l_result) = 0. DATA wa_string1 TYPE i. DATA wa_string2 TYPE i. DO lines( lt_string1 ) TIMES. wa_string1 = lt_string1[ sy-index ]. wa_string2 = lt_string2[ sy-index ]. IF wa_string1 > wa_string2. l_result = 1. EXIT. ELSEIF wa_string1 < wa_string2. l_result = -1. EXIT. ELSE. l_result = 0. ENDIF. ENDDO. ELSE. l_result = -1. ENDIF. r_result = l_result. ENDMETHOD. METHOD get_client_role. SELECT SINGLE cccategory INTO @r_result FROM t000 AS t WHERE t~mandt = @i_client. IF sy-subrc <> 0. MESSAGE |Could not read client role from T000| TYPE 'I' DISPLAY LIKE 'E' ##NO_TEXT. ENDIF. ENDMETHOD. METHOD get_system_name. CALL FUNCTION 'GET_SYSTEM_NAME' IMPORTING system_name = r_sysnam. ENDMETHOD. "check if at least one client in the system has role "Production" METHOD has_prod_client. SELECT cccategory INTO TABLE @DATA(it_t000) FROM t000 AS t. IF sy-subrc <> 0. MESSAGE |Could not read client category from T000| TYPE 'I' DISPLAY LIKE 'E' ##NO_TEXT. ENDIF. IF line_exists( it_t000[ cccategory = 'P' ] ). r_result = abap_true. ELSE. r_result = abap_false. ENDIF. ENDMETHOD. METHOD binary_to_xstring. CALL FUNCTION 'SCMS_BINARY_TO_XSTRING' EXPORTING input_length = iv_length IMPORTING buffer = ov_xstring TABLES binary_tab = it_bintab EXCEPTIONS failed = 1 OTHERS = 2. IF sy-subrc <> 0. RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = |Could not convert bin table to xstring| ##NO_TEXT. ENDIF. ENDMETHOD. METHOD get_parameter. DATA lv_value TYPE pfepvalue. DATA lv_rc TYPE i. CALL FUNCTION 'TH_GET_PARAMETER' EXPORTING parameter_name = CONV pfeparname( iv_param ) IMPORTING parameter_value = lv_value rc = lv_rc EXCEPTIONS not_authorized = 1 OTHERS = 2. IF lv_rc <> 0 OR sy-subrc <> 0. RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = |Could not determine parameter { iv_param }| ##NO_TEXT. ENDIF. rv_value = lv_value. ENDMETHOD. METHOD raise_lpath_exception. RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = |Could not determine location to save { i_filename }. | && |Please maintain logical path { lif_sdk_constants=>c_trans_logical_path } in transaction FILE | && |to point to physical path //| ##NO_TEXT. ENDMETHOD. ENDCLASS. INTERFACE lif_sdk_internet_manager. METHODS: download IMPORTING i_absolute_uri TYPE w3_url i_blankstocrlf TYPE boolean RETURNING VALUE(r_response_body) TYPE xstring RAISING lcx_error, has_internet_access RETURNING VALUE(r_result) TYPE abap_bool RAISING lcx_error. ENDINTERFACE. CLASS lcl_sdk_internet_manager DEFINITION FINAL. PUBLIC SECTION. INTERFACES: lif_sdk_internet_manager. ENDCLASS. CLASS lcl_sdk_internet_manager IMPLEMENTATION. METHOD lif_sdk_internet_manager~download. DATA status_code TYPE i. DATA status_text TYPE string. DATA response_entity_body_length TYPE i. DATA request_entity_body TYPE STANDARD TABLE OF docs. DATA request_headers TYPE STANDARD TABLE OF docs. DATA response_entity_body TYPE STANDARD TABLE OF docs. DATA response_headers TYPE STANDARD TABLE OF docs. DATA wa_response_entity_body TYPE docs. cl_http_client=>create_by_url( EXPORTING url = CONV string( i_absolute_uri ) ssl_id = 'DFAULT' " use SSLC IMPORTING client = DATA(http_client) ). http_client->request->set_method( if_http_request=>co_request_method_get ). http_client->send( EXPORTING timeout = if_http_client=>co_timeout_default EXCEPTIONS http_communication_failure = 1 http_invalid_state = 2 http_processing_failed = 3 http_invalid_timeout = 4 OTHERS = 99 ). IF sy-subrc = 0. http_client->receive( EXCEPTIONS http_communication_failure = 1 http_invalid_state = 2 http_processing_failed = 3 OTHERS = 99 ). ENDIF. IF sy-subrc > 0. CASE sy-subrc. WHEN 1. DATA(msg) = |HTTP communication error|. WHEN 2. msg = |HTTP invalid state|. WHEN 3. msg = |HTTP processing failed|. WHEN 4. msg = |HTTP invalid timeout|. WHEN OTHERS. msg = |Unknown error|. ENDCASE. RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = |Could not establish a connection to { i_absolute_uri }:| && msg && |Please check the SMICM trace for more details.| ##NO_TEXT. ENDIF. DATA(response) = http_client->response. response->get_status( IMPORTING code = status_code reason = status_text ). r_response_body = response->get_data( ). IF status_code >= 299. RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = |HTTP error { status_text }({ status_code }) when attempting GET from { i_absolute_uri }.| && |Please check the SMICM log for SSL errors such as untrusted certificates| ##NO_TEXT. ENDIF. ENDMETHOD. METHOD lif_sdk_internet_manager~has_internet_access. DATA result TYPE abap_bool. DATA http_client TYPE REF TO if_http_client. DATA reason TYPE string. DATA url TYPE string. DATA http_rc TYPE i. DATA status_text TYPE string. result = abap_false. url = lif_sdk_constants=>c_url_internet_check. TRY. cl_http_client=>create_by_url( EXPORTING url = url IMPORTING client = http_client ). http_client->request->set_method( if_http_request=>co_request_method_get ). http_client->send( timeout = if_http_client=>co_timeout_default ). http_client->receive( EXCEPTIONS http_communication_failure = 1 http_invalid_state = 2 http_processing_failed = 3 OTHERS = 4 ). IF sy-subrc <> 0. result = abap_false. ELSE. result = abap_true. ENDIF. CATCH cx_root INTO DATA(ex). RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = ex->get_text( ). ENDTRY. r_result = result. ENDMETHOD. ENDCLASS. INTERFACE lif_sdk_report_update_manager. METHODS: is_update_available RETURNING VALUE(r_result) TYPE boolean RAISING lcx_error, update_report RAISING lcx_error. ENDINTERFACE. CLASS lcl_sdk_report_update_manager DEFINITION FINAL. PUBLIC SECTION. INTERFACES: lif_sdk_report_update_manager. METHODS: constructor IMPORTING i_sdk_internet_manager TYPE REF TO lif_sdk_internet_manager OPTIONAL. PRIVATE SECTION. DATA: internet_manager TYPE REF TO lif_sdk_internet_manager. DATA: report_github_cached TYPE xstring. METHODS: download_report IMPORTING i_url_github_raw TYPE w3_url RETURNING VALUE(r_report_xstring) TYPE xstring RAISING lcx_error, write_report_update RAISING lcx_error. ENDCLASS. CLASS lcl_sdk_report_update_manager IMPLEMENTATION. METHOD constructor. IF i_sdk_internet_manager IS BOUND. internet_manager = i_sdk_internet_manager. ELSE. internet_manager = NEW lcl_sdk_internet_manager( ). ENDIF. ENDMETHOD. METHOD lif_sdk_report_update_manager~update_report. IF report_github_cached IS NOT INITIAL. write_report_update( ). ELSE. RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = |Check for update first!| ##NO_TEXT.. ENDIF. ENDMETHOD. METHOD lif_sdk_report_update_manager~is_update_available. DATA: report_local TYPE xstring. DATA: report_local_stringtab TYPE TABLE OF string. DATA: report_local_string TYPE string. " retrieve current version from github, store it in private instance variable TRY. report_github_cached = download_report( i_url_github_raw = lif_sdk_constants=>c_url_github_raw ). CATCH lcx_error INTO DATA(ex1). RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = ex1->get_text( ). ENDTRY. " read local report version as xstring TRY. READ REPORT sy-repid INTO report_local_stringtab. CONCATENATE LINES OF report_local_stringtab INTO report_local_string SEPARATED BY cl_abap_char_utilities=>newline. report_local = cl_abap_conv_codepage=>create_out( )->convert( source = report_local_string ). CATCH cx_root INTO DATA(ex2). RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = ex2->get_text( ). ENDTRY. r_result = xsdbool( report_local <> report_github_cached ). ENDMETHOD. METHOD download_report. TRY. r_report_xstring = internet_manager->download( i_absolute_uri = i_url_github_raw i_blankstocrlf = abap_false ). CATCH lcx_error INTO DATA(ex). RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = ex->get_text( ). ENDTRY. ENDMETHOD. METHOD write_report_update. " Safety check, if the cached version is still initial, do not overwrite IF report_github_cached IS INITIAL. RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = |Report content is empty!| ##NO_TEXT.. ENDIF. TRY. DATA(report_string) = cl_abap_conv_codepage=>create_in( )->convert( source = report_github_cached ). CATCH cx_root INTO DATA(ex). RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = ex->get_text( ). ENDTRY. SPLIT report_string AT cl_abap_char_utilities=>newline INTO TABLE DATA(report_stringtab). INSERT REPORT sy-repid FROM report_stringtab. IF sy-subrc <> 0. RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = |Failed to write report update!| ##NO_TEXT.. ENDIF. ENDMETHOD. ENDCLASS. INTERFACE lif_sdk_certificate_manager. TYPES: BEGIN OF ts_amazon_root_certificate, subject TYPE string, uri TYPE w3_url, binary TYPE xstring, installed TYPE abap_bool, END OF ts_amazon_root_certificate. TYPES: tt_amazon_root_certificate TYPE STANDARD TABLE OF ts_amazon_root_certificate WITH KEY subject. METHODS: install_amazon_root_certs RETURNING VALUE(r_success) TYPE abap_bool RAISING lcx_error. ENDINTERFACE. CLASS lcl_sdk_certificate_manager DEFINITION FINAL. PUBLIC SECTION. INTERFACES: lif_sdk_certificate_manager. METHODS: constructor IMPORTING i_internet_manager TYPE REF TO lif_sdk_internet_manager OPTIONAL RAISING lcx_error. PRIVATE SECTION. DATA: internet_manager TYPE REF TO lif_sdk_internet_manager. DATA: mt_amazon_root_certs TYPE lif_sdk_certificate_manager~tt_amazon_root_certificate. " populated in set_amazon_root_cert_values METHODS: set_amazon_root_cert_values, set_amazon_root_cert_status RAISING lcx_error, retrieve_missing_certificates RETURNING VALUE(r_result) TYPE abap_bool RAISING lcx_error, check_bapiret IMPORTING it_bapiret2 TYPE bapiret2_t RAISING lcx_error. ENDCLASS. CLASS lcl_sdk_certificate_manager IMPLEMENTATION. METHOD constructor. IF i_internet_manager IS BOUND. internet_manager = i_internet_manager. ELSE. internet_manager = NEW lcl_sdk_internet_manager( ). ENDIF. set_amazon_root_cert_values( ). " Sets certificate URLs in member table set_amazon_root_cert_status( ). " Sets the certificates' status to installed/not installed retrieve_missing_certificates( ). ENDMETHOD. METHOD retrieve_missing_certificates. DATA lt_missing_certs TYPE lif_sdk_certificate_manager~tt_amazon_root_certificate. LOOP AT mt_amazon_root_certs INTO DATA(wa_amazon_root_cert). IF wa_amazon_root_cert-installed = abap_false AND sy-tabix > 4. " Certs that are mentioned in the ABAP SDK docs appear after tabix 4 APPEND wa_amazon_root_cert TO lt_missing_certs. ENDIF. ENDLOOP. IF lines( lt_missing_certs ) > 0. DATA lv_text TYPE string. lv_text = |It appears your system is missing one or more of the five Amazon Root SSL Certificates. | && |These certificates have to be installed in order to download and use the newest version of the ABAP SDK. | && |The report can download and maintain them automatically for you if your SAP system has an Internet connection. | && |Amazon Root SSL Certificates are available from https://www.amazontrust.com/repository/ | ##NO_TEXT. DATA lv_answer TYPE c. CALL FUNCTION 'POPUP_TO_CONFIRM' EXPORTING titlebar = ' ' diagnose_object = ' ' text_question = lv_text text_button_1 = |Do it for me| icon_button_1 = ' ' text_button_2 = |Not now| icon_button_2 = ' ' default_button = '1' display_cancel_button = ' ' userdefined_f1_help = ' ' start_column = 25 start_row = 6 iv_quickinfo_button_1 = ' ' iv_quickinfo_button_2 = ' ' IMPORTING answer = lv_answer EXCEPTIONS text_not_found = 1 OTHERS = 2 ##NO_TEXT. IF sy-subrc <> 0. RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = |Could not find text for popup| ##NO_TEXT. ENDIF. IF lv_answer = 1. lif_sdk_certificate_manager~install_amazon_root_certs( ). ELSE. LEAVE PROGRAM. ENDIF. ENDIF. ENDMETHOD. METHOD set_amazon_root_cert_values. INSERT VALUE #( subject = 'CN=Amazon RSA 2048 M01, O=Amazon, C=US' uri = 'http://crt.r2m01.amazontrust.com/r2m01.cer' binary = '' installed = abap_false ) INTO me->mt_amazon_root_certs INDEX 1 ##NO_TEXT. INSERT VALUE #( subject = 'CN=Amazon RSA 2048 M02, O=Amazon, C=US' uri = 'http://crt.r2m01.amazontrust.com/r2m02.cer' binary = '' installed = abap_false ) INTO me->mt_amazon_root_certs INDEX 2 ##NO_TEXT. INSERT VALUE #( subject = 'CN=Amazon RSA 2048 M03, O=Amazon, C=US' uri = 'http://crt.r2m01.amazontrust.com/r2m03.cer' binary = '' installed = abap_false ) INTO me->mt_amazon_root_certs INDEX 3 ##NO_TEXT. INSERT VALUE #( subject = 'CN=Amazon RSA 2048 M04, O=Amazon, C=US' uri = 'http://crt.r2m01.amazontrust.com/r2m04.cer' binary = '' installed = abap_false ) INTO me->mt_amazon_root_certs INDEX 4 ##NO_TEXT. INSERT VALUE #( subject = 'CN=Amazon Root CA 1, O=Amazon, C=US' uri = 'https://www.amazontrust.com/repository/AmazonRootCA1.cer' binary = '' installed = abap_false ) INTO me->mt_amazon_root_certs INDEX 5 ##NO_TEXT. INSERT VALUE #( subject = 'CN=Amazon Root CA 2, O=Amazon, C=US' uri = 'https://www.amazontrust.com/repository/AmazonRootCA2.cer' binary = '' installed = abap_false ) INTO me->mt_amazon_root_certs INDEX 6 ##NO_TEXT. INSERT VALUE #( subject = 'CN=Amazon Root CA 3, O=Amazon, C=US' uri = 'https://www.amazontrust.com/repository/AmazonRootCA3.cer' binary = '' installed = abap_false ) INTO me->mt_amazon_root_certs INDEX 7 ##NO_TEXT. INSERT VALUE #( subject = 'CN=Amazon Root CA 4, O=Amazon, C=US' uri = 'https://www.amazontrust.com/repository/AmazonRootCA4.cer' binary = '' installed = abap_false ) INTO me->mt_amazon_root_certs INDEX 8 ##NO_TEXT. INSERT VALUE #( subject = 'CN=Starfield Services Root Certificate Authority - G2, O="Starfield Technologies, Inc.", L=Scottsdale, SP=Arizona, C=US' uri = 'https://www.amazontrust.com/repository/SFSRootCAG2.cer' binary = '' installed = abap_false ) INTO me->mt_amazon_root_certs INDEX 9 ##NO_TEXT. ENDMETHOD. METHOD set_amazon_root_cert_status. DATA ls_strust_identity TYPE ssf_s_strust_identity. DATA lt_certificatelist TYPE ssfbintab. DATA wa_certificate_binary TYPE LINE OF ssfbintab. DATA wa_amazon_root_cert TYPE lif_sdk_certificate_manager~ts_amazon_root_certificate. DATA lt_bapiret2 TYPE STANDARD TABLE OF bapiret2. ls_strust_identity-pse_context = 'SSLC'. ls_strust_identity-pse_applic = 'DFAULT'. ls_strust_identity-pse_descript = 'SSL Client (Standard)' ##NO_TEXT. ls_strust_identity-sprsl = 'E'. CALL FUNCTION 'SSFR_GET_CERTIFICATELIST' EXPORTING is_strust_identity = ls_strust_identity IMPORTING et_certificatelist = lt_certificatelist TABLES et_bapiret2 = lt_bapiret2. check_bapiret( lt_bapiret2 ). CLEAR lt_bapiret2. DATA l_subject TYPE string. DATA l_issuer TYPE string. DATA l_serialno TYPE string. DATA l_validfrom TYPE string. DATA l_validto TYPE string. DATA l_algid TYPE string. LOOP AT lt_certificatelist INTO wa_certificate_binary. CALL FUNCTION 'SSFR_PARSE_CERTIFICATE' EXPORTING iv_certificate = wa_certificate_binary IMPORTING ev_subject = l_subject ev_issuer = l_issuer ev_serialno = l_serialno ev_validfrom = l_validfrom ev_validto = l_validto ev_algid = l_algid TABLES et_bapiret2 = lt_bapiret2. check_bapiret( lt_bapiret2 ). READ TABLE mt_amazon_root_certs WITH TABLE KEY subject = l_subject INTO wa_amazon_root_cert. IF sy-subrc = 0. " found existing certificate wa_amazon_root_cert-binary = wa_certificate_binary. wa_amazon_root_cert-installed = abap_true. MODIFY TABLE mt_amazon_root_certs FROM wa_amazon_root_cert. ENDIF. CLEAR: l_subject, l_issuer, l_serialno, l_validfrom, l_validto, l_algid. CLEAR wa_amazon_root_cert. CLEAR lt_bapiret2. ENDLOOP. ENDMETHOD. METHOD lif_sdk_certificate_manager~install_amazon_root_certs. DATA wa_amazon_root_cert TYPE lif_sdk_certificate_manager~ts_amazon_root_certificate. DATA ls_strust_identity TYPE ssf_s_strust_identity. DATA lt_bapiret2 TYPE STANDARD TABLE OF bapiret2. DATA l_abap_matcher TYPE REF TO cl_abap_matcher. DATA l_abap_regex_pcre TYPE REF TO cl_abap_regex. ls_strust_identity-pse_context = 'SSLC' ##NO_TEXT. ls_strust_identity-pse_applic = 'DFAULT' ##NO_TEXT. ls_strust_identity-pse_descript = 'SSL Client (Standard)' ##NO_TEXT. ls_strust_identity-sprsl = 'E'. " root cert URLS set in set_amazon_root_cert_values LOOP AT mt_amazon_root_certs INTO wa_amazon_root_cert FROM 1 TO 4. IF wa_amazon_root_cert-installed = abap_true. CONTINUE. ENDIF. DATA(root_cert_name_http) = segment( val = wa_amazon_root_cert-uri sep = '/' index = -1 ). wa_amazon_root_cert-binary = internet_manager->download( i_absolute_uri = wa_amazon_root_cert-uri i_blankstocrlf = abap_false ). CALL FUNCTION 'SSFR_PUT_CERTIFICATE' EXPORTING is_strust_identity = ls_strust_identity iv_certificate = wa_amazon_root_cert-binary TABLES et_bapiret2 = lt_bapiret2. check_bapiret( lt_bapiret2 ). ENDLOOP. CALL FUNCTION 'ICM_SSL_PSE_CHANGED' EXCEPTIONS icm_op_failed = 1 icm_get_serv_failed = 2 icm_auth_failed = 3 OTHERS = 4. IF sy-subrc <> 0. RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = |Error updating PSE| ##NO_TEXT. ENDIF. " root cert URLS set in set_amazon_root_cert_values LOOP AT mt_amazon_root_certs INTO wa_amazon_root_cert FROM 5. IF wa_amazon_root_cert-installed = abap_true. CONTINUE. ENDIF. DATA(root_cert_name_https) = segment( val = wa_amazon_root_cert-uri sep = '/' index = -1 ). wa_amazon_root_cert-binary = internet_manager->download( i_absolute_uri = wa_amazon_root_cert-uri i_blankstocrlf = abap_false ). CALL FUNCTION 'SSFR_PUT_CERTIFICATE' EXPORTING is_strust_identity = ls_strust_identity iv_certificate = wa_amazon_root_cert-binary TABLES et_bapiret2 = lt_bapiret2. check_bapiret( lt_bapiret2 ). ENDLOOP. MESSAGE |Certificates installed.| TYPE 'S' ##NO_TEXT. r_success = abap_true . ENDMETHOD. METHOD check_bapiret. LOOP AT it_bapiret2 ASSIGNING FIELD-SYMBOL() WHERE type CA 'AE'. IF -message IS NOT INITIAL. RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = |Could not put certificate: { -message }| ##NO_TEXT. ELSE. DATA lv_msg TYPE string. MESSAGE ID -id TYPE -type NUMBER -number WITH -message_v1 -message_v2 -message_v3 -message_v4 INTO lv_msg. RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = |Could not put certificate: { lv_msg }| ##NO_TEXT. ENDIF. ENDLOOP. ENDMETHOD. ENDCLASS. INTERFACE lif_sdk_file_manager. METHODS: get_file_from_zip IMPORTING i_zipfile_absolute_path TYPE string i_file_to_retrieve TYPE string RETURNING VALUE(r_file_xstring) TYPE xstring, check_file_writable_at IMPORTING i_path TYPE string RETURNING VALUE(r_result) TYPE abap_bool, check_file_exists_at IMPORTING i_path TYPE string RETURNING VALUE(r_result) TYPE abap_bool, open_for_input IMPORTING iv_filename TYPE clike RAISING lcx_error, open_for_output IMPORTING iv_filename TYPE clike RAISING lcx_error. ENDINTERFACE. CLASS lcl_sdk_file_manager DEFINITION FINAL. PUBLIC SECTION. INTERFACES: lif_sdk_file_manager. ENDCLASS. CLASS lcl_sdk_file_manager IMPLEMENTATION. METHOD lif_sdk_file_manager~get_file_from_zip. DATA lv_zipfile_content TYPE xstring. TRY. lif_sdk_file_manager~open_for_input( i_zipfile_absolute_path ). READ DATASET i_zipfile_absolute_path INTO lv_zipfile_content. CLOSE DATASET i_zipfile_absolute_path. CATCH cx_sy_file_authority INTO DATA(r_ex1). MESSAGE r_ex1->get_text( ) TYPE 'I' DISPLAY LIKE 'E'. RETURN. CATCH cx_sy_file_access_error INTO DATA(r_ex2). MESSAGE r_ex2->get_text( ) TYPE 'I' DISPLAY LIKE 'E'. RETURN. CATCH cx_root INTO DATA(r_ex). MESSAGE r_ex->get_text( ) TYPE 'I' DISPLAY LIKE 'E'. RETURN. ENDTRY. DATA(r_zip) = NEW cl_abap_zip( ). r_zip->load( zip = lv_zipfile_content ). r_zip->get( EXPORTING name = i_file_to_retrieve IMPORTING content = r_file_xstring EXCEPTIONS zip_index_error = 1 zip_decompression_error = 2 OTHERS = 3 ). CASE sy-subrc. WHEN 0. " success WHEN 1. MESSAGE 'Zip Index Error' TYPE 'I' DISPLAY LIKE 'E' ##NO_TEXT. RETURN. WHEN 2. MESSAGE 'Zip Decompression Error' TYPE 'I' DISPLAY LIKE 'E' ##NO_TEXT. RETURN. WHEN OTHERS. MESSAGE 'Unknown Zip error' TYPE 'I' DISPLAY LIKE 'E' ##NO_TEXT. RETURN. ENDCASE. ENDMETHOD. METHOD lif_sdk_file_manager~check_file_writable_at. TRY. lif_sdk_file_manager~open_for_output( i_path ). CLOSE DATASET i_path. r_result = abap_true. CATCH lcx_error INTO DATA(lo_ex). MESSAGE |Path { i_path } not writable, reason: { lo_ex->av_msg }| TYPE 'I' DISPLAY LIKE 'E' ##NO_TEXT. ENDTRY. ENDMETHOD. METHOD lif_sdk_file_manager~check_file_exists_at. DATA(lv_path) = CONV pfebackuppro( i_path ). CALL FUNCTION 'PFL_CHECK_OS_FILE_EXISTENCE' EXPORTING long_filename = lv_path IMPORTING file_exists = r_result EXCEPTIONS authorization_missing = 1 OTHERS = 2. CASE sy-subrc. WHEN 0. " all good WHEN 1. RAISE EXCEPTION TYPE cx_sy_file_authority. WHEN 2. RAISE EXCEPTION TYPE cx_sy_file_io. " TODO: Find/Create more appropriate exception for generic case ENDCASE. ENDMETHOD. METHOD lif_sdk_file_manager~open_for_input. DATA lv_os_msg TYPE text255. OPEN DATASET iv_filename FOR INPUT IN BINARY MODE MESSAGE lv_os_msg. IF sy-subrc <> 0. RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = |Error opening { iv_filename }: { lv_os_msg }| ##NO_TEXT. ENDIF. ENDMETHOD. METHOD lif_sdk_file_manager~open_for_output. DATA(lv_filename_to_check) = CONV fileextern( iv_filename ). AUTHORITY-CHECK OBJECT 'S_DATASET' ID 'PROGRAM' FIELD sy-repid ID 'ACTVT' FIELD '34' ID 'FILENAME' FIELD lv_filename_to_check ##AUTH_FLD_LEN. IF sy-subrc <> 0. RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = |No permission to write to { iv_filename }| ##NO_TEXT. ENDIF. DATA lv_os_msg TYPE text255. OPEN DATASET iv_filename FOR OUTPUT IN BINARY MODE MESSAGE lv_os_msg. IF sy-subrc <> 0. RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = |Error opening { iv_filename }: { lv_os_msg }| ##NO_TEXT. ENDIF. ENDMETHOD. ENDCLASS. INTERFACE lif_sdk_transport_manager. METHODS: get_sdk_cofile_from_zip IMPORTING i_tla TYPE ts_sdk_module-tla i_transport TYPE ts_sdk_module-atransport i_operation TYPE string i_version TYPE string i_zipfile_absolute_path TYPE string EXPORTING e_cofile_name TYPE string e_cofile_blob TYPE xstring, get_sdk_datafile_from_zip IMPORTING i_tla TYPE ts_sdk_module-tla i_transport TYPE ts_sdk_module-atransport i_operation TYPE string i_version TYPE string i_zipfile_absolute_path TYPE string EXPORTING e_datafile_name TYPE string e_datafile_blob TYPE xstring, write_sdk_transport_trdir IMPORTING i_cofile_name TYPE string i_datafile_name TYPE string i_cofile_blob TYPE xstring i_datafile_blob TYPE xstring RETURNING VALUE(r_success) TYPE boolean RAISING lcx_error, import_sdk_transports IMPORTING it_transport_names TYPE stms_tr_requests EXPORTING e_tp_retcode TYPE stpa-retcode es_exception TYPE stmscalert. ENDINTERFACE. CLASS lcl_sdk_transport_manager DEFINITION FINAL. PUBLIC SECTION. INTERFACES: lif_sdk_transport_manager. METHODS: constructor IMPORTING i_file_manager TYPE REF TO lcl_sdk_file_manager OPTIONAL. PRIVATE SECTION. DATA: file_manager TYPE REF TO lcl_sdk_file_manager. ENDCLASS. CLASS lcl_sdk_transport_manager IMPLEMENTATION. METHOD constructor. IF i_file_manager IS BOUND. file_manager = i_file_manager. ELSE. file_manager = NEW lcl_sdk_file_manager( ). ENDIF. ENDMETHOD. METHOD lif_sdk_transport_manager~write_sdk_transport_trdir. DATA lv_rc TYPE i. DATA lv_validation_active TYPE abap_bool. DATA lv_filepath_cofile TYPE string. DATA lv_filepath_datafile TYPE string. DATA gv_file_name(255) TYPE c. CALL FUNCTION 'FILE_GET_NAME_USING_PATH' EXPORTING client = sy-mandt logical_path = lif_sdk_constants=>c_trans_logical_path operating_system = sy-opsys parameter_1 = 'cofiles' file_name = i_cofile_name IMPORTING file_name_with_path = lv_filepath_cofile EXCEPTIONS path_not_found = 1 missing_parameter = 2 operating_system_not_found = 3 file_system_not_found = 4 OTHERS = 5. IF sy-subrc <> 0. lcl_sdk_utils=>raise_lpath_exception( i_cofile_name ). ENDIF. CALL FUNCTION 'FILE_VALIDATE_NAME' EXPORTING logical_filename = lif_sdk_constants=>c_logsubdir_name parameter_1 = 'cofiles' CHANGING physical_filename = lv_filepath_cofile EXCEPTIONS OTHERS = 1. IF sy-subrc <> 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. ENDIF. CALL FUNCTION 'FILE_GET_NAME_USING_PATH' EXPORTING client = sy-mandt logical_path = lif_sdk_constants=>c_trans_logical_path operating_system = sy-opsys parameter_1 = 'data' file_name = i_datafile_name IMPORTING file_name_with_path = lv_filepath_datafile EXCEPTIONS path_not_found = 1 missing_parameter = 2 operating_system_not_found = 3 file_system_not_found = 4 OTHERS = 5. IF sy-subrc <> 0. lcl_sdk_utils=>raise_lpath_exception( i_datafile_name ). ENDIF. CALL FUNCTION 'FILE_VALIDATE_NAME' EXPORTING logical_filename = lif_sdk_constants=>c_logsubdir_name parameter_1 = 'data' CHANGING physical_filename = lv_filepath_datafile EXCEPTIONS OTHERS = 1. IF sy-subrc <> 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. ENDIF. TRY. file_manager->lif_sdk_file_manager~open_for_output( lv_filepath_cofile ). TRANSFER i_cofile_blob TO lv_filepath_cofile. CLOSE DATASET lv_filepath_cofile. file_manager->lif_sdk_file_manager~open_for_output( lv_filepath_datafile ). TRANSFER i_datafile_blob TO lv_filepath_datafile. CLOSE DATASET lv_filepath_datafile. CATCH cx_sy_file_authority INTO DATA(r_ex1). MESSAGE r_ex1->get_text( ) TYPE 'I' DISPLAY LIKE 'E'. RETURN. CATCH cx_sy_file_access_error INTO DATA(r_ex2). MESSAGE r_ex2->get_text( ) TYPE 'I' DISPLAY LIKE 'E'. RETURN. CATCH cx_root INTO DATA(r_ex). MESSAGE r_ex->get_text( ) TYPE 'I' DISPLAY LIKE 'E'. RETURN. ENDTRY. r_success = abap_true. ENDMETHOD. METHOD lif_sdk_transport_manager~get_sdk_cofile_from_zip. DATA l_cofile_zip_path TYPE string. DATA l_cofile_name TYPE string. DATA l_cofile_blob TYPE xstring. e_cofile_name = 'K' && i_transport+4 && '.' && i_transport+0(3). l_cofile_zip_path = lif_sdk_constants=>c_transports_zip_path && i_tla && '/' && e_cofile_name. e_cofile_blob = file_manager->lif_sdk_file_manager~get_file_from_zip( i_zipfile_absolute_path = i_zipfile_absolute_path i_file_to_retrieve = l_cofile_zip_path ). ENDMETHOD. METHOD lif_sdk_transport_manager~get_sdk_datafile_from_zip. DATA l_datafile_zip_path TYPE string. DATA l_datafile_name TYPE string. DATA l_datafile_blob TYPE xstring. e_datafile_name = 'R' && i_transport+4 && '.' && i_transport+0(3). l_datafile_zip_path = lif_sdk_constants=>c_transports_zip_path && i_tla && '/' && e_datafile_name. e_datafile_blob = file_manager->lif_sdk_file_manager~get_file_from_zip( i_zipfile_absolute_path = i_zipfile_absolute_path i_file_to_retrieve = l_datafile_zip_path ). ENDMETHOD. METHOD lif_sdk_transport_manager~import_sdk_transports. DATA: l_system TYPE tmssysnam. DATA: l_tp_ret_code TYPE stpa-retcode. DATA: ls_exception TYPE stmscalert. l_system = lcl_sdk_utils=>get_system_name( ). " TODO: Needs to go into its own method CALL FUNCTION 'TMS_MGR_FORWARD_TR_REQUEST' EXPORTING iv_request = 'SOME' iv_tarcli = sy-mandt iv_import_again = abap_true iv_target = l_system it_requests = it_transport_names IMPORTING ev_tp_ret_code = l_tp_ret_code es_exception = ls_exception EXCEPTIONS read_config_failed = 1 table_of_requests_is_empty = 2 OTHERS = 3. CASE sy-subrc. WHEN 0. " all good WHEN 2. " empty import list WHEN 4. " finished with warnings WHEN OTHERS. MESSAGE |Error forwarding requests to { l_system }| TYPE 'I' DISPLAY LIKE 'E' ##NO_TEXT. ENDCASE. " TODO: DO SOMETHING USEFUL WITH THESE. CLEAR: l_tp_ret_code. CLEAR: ls_exception. * WARNING: Turning off offline processing (IV_OFFLINE = abap_false) makes the * FM call spawn a new logon session for every transport, which can lead to resource * exhaustion for very large module import numbers (> 200), check also SAP Profile * parameters rdisp/user_resource_limit and rdisp/tm_max_no * ADD: Turning on offline processing (IV_OFFLINE = abap_true) apparently leads to the * background job finishing prematurely, which is not desired. IF sy-batch = abap_true. CALL FUNCTION 'TMS_MGR_IMPORT_TR_REQUEST' EXPORTING iv_system = l_system iv_request = 'SOME' iv_client = sy-mandt iv_import_again = abap_true iv_ignore_cvers = abap_true iv_offline = abap_false iv_monitor = abap_false it_requests = it_transport_names IMPORTING ev_tp_ret_code = l_tp_ret_code es_exception = ls_exception EXCEPTIONS read_config_failed = 1 table_of_requests_is_empty = 2 OTHERS = 3. CASE sy-subrc. WHEN 0. " all good WHEN 2. " empty import list WHEN 4. " finished with warnings WHEN OTHERS: . MESSAGE |Error importing requests to { l_system }| TYPE 'I' DISPLAY LIKE 'E' ##NO_TEXT. ENDCASE. ELSE. CALL FUNCTION 'TMS_MGR_IMPORT_TR_REQUEST' EXPORTING iv_system = l_system iv_request = 'SOME' iv_client = sy-mandt iv_import_again = abap_true iv_ignore_cvers = abap_true iv_offline = abap_false iv_monitor = abap_true it_requests = it_transport_names IMPORTING ev_tp_ret_code = l_tp_ret_code es_exception = ls_exception EXCEPTIONS read_config_failed = 1 table_of_requests_is_empty = 2 OTHERS = 3. CASE sy-subrc. WHEN 0. " all good WHEN 2. " empty import list WHEN 4. " finished with warnings WHEN OTHERS. MESSAGE |Error importing requests to { l_system }| TYPE 'I' DISPLAY LIKE 'E' ##NO_TEXT. ENDCASE. ENDIF. e_tp_retcode = l_tp_ret_code. es_exception = ls_exception. ENDMETHOD. ENDCLASS. INTERFACE lif_sdk_job_manager. METHODS: get_running_jobs IMPORTING i_jobname TYPE syst_repi2 RETURNING VALUE(r_result) TYPE tbtcjob_tt, is_job_running RETURNING VALUE(r_result) TYPE abap_bool, submit_batch_job IMPORTING i_modules_to_be_installed TYPE tt_sdk_tla i_modules_to_be_deleted TYPE tt_sdk_tla i_target_version TYPE string RETURNING VALUE(r_result) TYPE tbtco-jobcount RAISING lcx_error. ENDINTERFACE. CLASS lcl_sdk_job_manager DEFINITION FINAL. PUBLIC SECTION. INTERFACES: lif_sdk_job_manager. ENDCLASS. CLASS lcl_sdk_job_manager IMPLEMENTATION. METHOD lif_sdk_job_manager~submit_batch_job. DATA(lt_modules_to_be_installed) = i_modules_to_be_installed. DATA(lt_modules_to_be_deleted) = i_modules_to_be_deleted. DATA(lv_target_version) = i_target_version. " Export to shared memory and batch job submission need to go together DELETE FROM SHARED BUFFER indx(mi) ID 'MOD_INST'. EXPORT st_modules_to_be_installed = lt_modules_to_be_installed TO SHARED BUFFER indx(mi) ID 'MOD_INST'. DELETE FROM SHARED BUFFER indx(md) ID 'MOD_DELE'. EXPORT st_modules_to_be_deleted = lt_modules_to_be_deleted TO SHARED BUFFER indx(md) ID 'MOD_DELE'. DELETE FROM SHARED BUFFER indx(tv) ID 'TAR_VERS'. EXPORT s_target_version = lv_target_version TO SHARED BUFFER indx(tv) ID 'TAR_VERS'. DATA(lo_job) = NEW cl_bp_abap_job( ). lo_job->set_name( CONV char32( sy-repid ) ). lo_job->set_report( sy-repid ). lo_job->if_bp_job_engine~generate_job_count( EXCEPTIONS cant_create_job = 1 invalid_job_data = 2 jobname_missing = 3 ). IF sy-subrc = 0. lo_job->if_bp_job_engine~plan_job_step( EXCEPTIONS bad_priparams = 11 bad_xpgflags = 12 invalid_jobdata = 13 jobname_missing = 14 job_notex = 15 job_submit_failed = 16 program_missing = 17 prog_abap_and_extpg_set = 18 ). ENDIF. IF sy-subrc = 0. lo_job->if_bp_job_engine~start_immediately( EXCEPTIONS cant_start_immediate = 21 invalid_startdate = 22 jobname_missing = 23 job_close_failed = 24 job_nosteps = 25 job_notex = 26 ). ENDIF. IF sy-subrc <> 0. RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = |Failed to submit job { sy-repid }: subrc = { sy-subrc }| ##NO_TEXT. ENDIF. r_result = lo_job->jobcount. ENDMETHOD. METHOD lif_sdk_job_manager~get_running_jobs. " --- Job already running? CALL FUNCTION 'BP_FIND_JOBS_WITH_PROGRAM' EXPORTING abap_program_name = i_jobname status = 'R' " Batch job already running in background? TABLES joblist = r_result EXCEPTIONS no_jobs_found = 1 program_specification_missing = 2 invalid_dialog_type = 3 job_find_canceled = 4 OTHERS = 5. IF sy-subrc <> 0. * Implement suitable error handling here ENDIF. ENDMETHOD. METHOD lif_sdk_job_manager~is_job_running. DATA lt_joblist TYPE TABLE OF tbtcjob. lt_joblist = lif_sdk_job_manager~get_running_jobs( i_jobname = sy-repid ). IF lines( lt_joblist ) > 0. r_result = abap_true. ELSE. r_result = abap_false. ENDIF. ENDMETHOD. ENDCLASS. CLASS lcl_sdk_zipfile DEFINITION FINAL. PUBLIC SECTION. DATA: op TYPE string READ-ONLY, version TYPE string READ-ONLY, name TYPE string READ-ONLY, uri TYPE w3_url READ-ONLY, path TYPE string READ-ONLY, json_web TYPE w3_url READ-ONLY. METHODS: constructor IMPORTING i_op TYPE string i_version TYPE string i_name TYPE string OPTIONAL i_uri TYPE w3_url OPTIONAL i_path TYPE string OPTIONAL i_json_web TYPE w3_url OPTIONAL RAISING lcx_error, set_op IMPORTING i_op TYPE string, set_version IMPORTING i_version TYPE string, set_name IMPORTING i_name TYPE string, set_uri IMPORTING i_uri TYPE w3_url, set_path IMPORTING i_path TYPE string, set_json_web IMPORTING i_json_web TYPE w3_url. PRIVATE SECTION. METHODS: build_download_uri_prefix IMPORTING i_protocol TYPE string DEFAULT 'https' i_major_version TYPE string DEFAULT '1' i_branch TYPE string DEFAULT 'release' RETURNING VALUE(r_result) TYPE string, build_zipfile_name IMPORTING i_operation TYPE string i_version TYPE string DEFAULT 'LATEST' RETURNING VALUE(r_result) TYPE string, build_jsonfile_name IMPORTING i_operation TYPE string i_version TYPE string DEFAULT 'LATEST' RETURNING VALUE(r_result) TYPE string, build_zipfile_path IMPORTING i_zipfile_name TYPE string i_trans_logical_path TYPE filepath-pathintern RETURNING VALUE(r_result) TYPE string RAISING lcx_error, validate_zipfile_path IMPORTING i_zipfile_path TYPE string i_logsubdir_name TYPE fileintern RETURNING VALUE(r_result) TYPE abap_bool. ENDCLASS. CLASS lcl_sdk_zipfile IMPLEMENTATION. METHOD constructor. op = i_op. version = i_version. IF i_name IS INITIAL. name = |{ build_zipfile_name( i_operation = op i_version = version ) }|. ELSE. name = i_name. ENDIF. IF i_uri IS INITIAL. uri = |{ build_download_uri_prefix( ) }{ name }|. ELSE. uri = i_uri. ENDIF. IF i_json_web IS INITIAL. json_web = |{ build_download_uri_prefix( ) }{ build_jsonfile_name( i_operation = op i_version = version ) }|. ELSE. json_web = i_json_web. ENDIF. IF i_path IS INITIAL. path = build_zipfile_path( i_zipfile_name = name i_trans_logical_path = lif_sdk_constants=>c_trans_logical_path ). ELSE. path = i_path. ENDIF. validate_zipfile_path( i_zipfile_path = path i_logsubdir_name = lif_sdk_constants=>c_logsubdir_name ). ENDMETHOD. METHOD set_op. op = i_op. ENDMETHOD. METHOD set_version. version = i_version. ENDMETHOD. METHOD set_name. name = i_name. ENDMETHOD. METHOD set_uri. uri = i_uri. ENDMETHOD. METHOD set_path. path = i_path. ENDMETHOD. METHOD set_json_web. json_web = i_json_web. ENDMETHOD. METHOD build_download_uri_prefix. r_result = |{ i_protocol }{ lif_sdk_constants=>c_download_uri_prefix }{ i_major_version }/{ i_branch }/| ##NO_TEXT.. ENDMETHOD. METHOD build_zipfile_name. CASE i_operation. WHEN 'install'. r_result = |{ lif_sdk_constants=>c_sdk_inst_file_prefix }{ i_version }.zip| ##NO_TEXT.. WHEN 'uninstall'. r_result = |{ lif_sdk_constants=>c_sdk_uninst_file_prefix }{ i_version }.zip| ##NO_TEXT.. WHEN OTHERS. ENDCASE. ENDMETHOD. METHOD build_jsonfile_name. CASE i_operation. WHEN 'install'. r_result = |{ lif_sdk_constants=>c_sdk_inst_file_prefix }{ i_version }.json| ##NO_TEXT.. WHEN 'uninstall'. r_result = |{ lif_sdk_constants=>c_sdk_uninst_file_prefix }{ i_version }.json| ##NO_TEXT.. WHEN OTHERS. ENDCASE. ENDMETHOD. METHOD build_zipfile_path. CALL FUNCTION 'FILE_GET_NAME_USING_PATH' EXPORTING client = sy-mandt logical_path = i_trans_logical_path operating_system = sy-opsys parameter_1 = 'tmp' file_name = i_zipfile_name IMPORTING file_name_with_path = r_result EXCEPTIONS path_not_found = 1 missing_parameter = 2 operating_system_not_found = 3 file_system_not_found = 4 OTHERS = 5. IF sy-subrc <> 0. lcl_sdk_utils=>raise_lpath_exception( i_zipfile_name ). ENDIF. ENDMETHOD. METHOD validate_zipfile_path. DATA(lv_zipfile_path) = i_zipfile_path. CALL FUNCTION 'FILE_VALIDATE_NAME' EXPORTING logical_filename = i_logsubdir_name parameter_1 = 'tmp' IMPORTING validation_active = r_result CHANGING physical_filename = lv_zipfile_path EXCEPTIONS OTHERS = 1. IF sy-subrc <> 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. ENDIF. ENDMETHOD. ENDCLASS. CLASS lcl_sdk_zipfile_collection DEFINITION FINAL. PUBLIC SECTION. TYPES tt_sdk_zipfile TYPE STANDARD TABLE OF REF TO lcl_sdk_zipfile. METHODS: constructor IMPORTING i_zipfiles TYPE tt_sdk_zipfile OPTIONAL i_internet_manager TYPE REF TO lif_sdk_internet_manager OPTIONAL i_file_manager TYPE REF TO lif_sdk_file_manager OPTIONAL RAISING lcx_error, get_by_op_version IMPORTING i_op TYPE string i_version TYPE string RETURNING VALUE(r_zipfile) TYPE REF TO lcl_sdk_zipfile, add_pair IMPORTING i_zipfile_inst TYPE REF TO lcl_sdk_zipfile i_zipfile_uninst TYPE REF TO lcl_sdk_zipfile RAISING lcx_error, exists_in_collection_pair IMPORTING i_version TYPE string RETURNING VALUE(r_result) TYPE abap_bool, exists_on_disk_pair IMPORTING i_version TYPE string RETURNING VALUE(r_result) TYPE abap_bool, download_zipfile_pair IMPORTING i_version TYPE string DEFAULT 'LATEST' RAISING lcx_error, ensure_zipfiles_downloaded IMPORTING i_version TYPE string DEFAULT 'LATEST' RETURNING VALUE(r_result) TYPE abap_bool RAISING lcx_error. PRIVATE SECTION. DATA: mt_sdk_zipfiles TYPE tt_sdk_zipfile, internet_manager TYPE REF TO lif_sdk_internet_manager, file_manager TYPE REF TO lif_sdk_file_manager. METHODS: add IMPORTING i_zipfile TYPE REF TO lcl_sdk_zipfile RAISING lcx_error, exists_in_collection IMPORTING i_op TYPE string i_version TYPE string RETURNING VALUE(r_result) TYPE abap_bool, exists_on_disk IMPORTING i_operation TYPE string i_version TYPE string RETURNING VALUE(r_result) TYPE abap_bool, download_zipfile IMPORTING i_zipfile TYPE REF TO lcl_sdk_zipfile RAISING lcx_error, clear_missing_zipfile_paths IMPORTING i_file_manager TYPE REF TO lcl_sdk_file_manager. ENDCLASS. CLASS lcl_sdk_zipfile_collection IMPLEMENTATION. METHOD constructor. IF i_zipfiles IS NOT INITIAL. mt_sdk_zipfiles = i_zipfiles. ELSE. add( NEW lcl_sdk_zipfile( i_op = 'install' i_version = 'LATEST' ) ). add( NEW lcl_sdk_zipfile( i_op = 'uninstall' i_version = 'LATEST' ) ). ENDIF. IF i_internet_manager IS BOUND. internet_manager = i_internet_manager. ELSE. internet_manager = NEW lcl_sdk_internet_manager( ). ENDIF. IF i_file_manager IS BOUND. file_manager = i_file_manager. ELSE. file_manager = NEW lcl_sdk_file_manager( ). ENDIF. ENDMETHOD. METHOD add. IF i_zipfile IS NOT BOUND. RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = |Unbound zipfile object reference.| ##NO_TEXT. ENDIF. APPEND i_zipfile TO mt_sdk_zipfiles. ENDMETHOD. METHOD add_pair. IF i_zipfile_inst IS NOT BOUND OR i_zipfile_uninst IS NOT BOUND. RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = |Unbound zipfile object reference.| ##NO_TEXT. ENDIF. APPEND i_zipfile_inst TO mt_sdk_zipfiles. APPEND i_zipfile_uninst TO mt_sdk_zipfiles. ENDMETHOD. METHOD exists_in_collection. IF get_by_op_version( i_op = i_op i_version = i_version ) IS BOUND. r_result = abap_true. ELSE. r_result = abap_false. ENDIF. ENDMETHOD. METHOD exists_in_collection_pair. r_result = xsdbool( exists_in_collection( i_op = 'install' i_version = i_version ) = abap_true AND exists_in_collection( i_op = 'uninstall' i_version = i_version ) = abap_true ). ENDMETHOD. METHOD get_by_op_version. LOOP AT mt_sdk_zipfiles INTO DATA(wa_zipfile). IF wa_zipfile->op = i_op AND wa_zipfile->version = i_version. r_zipfile = wa_zipfile. RETURN. ENDIF. ENDLOOP. " returns unbound r_zipfile if no zipfile matches op and version ENDMETHOD. METHOD exists_on_disk. IF exists_in_collection( i_op = i_operation i_version = i_version ). r_result = file_manager->check_file_exists_at( get_by_op_version( i_op = i_operation i_version = i_version )->path ). ELSE. r_result = abap_false. ENDIF. ENDMETHOD. METHOD exists_on_disk_pair. r_result = xsdbool( exists_on_disk( i_operation = 'install' i_version = i_version ) = abap_true AND exists_on_disk( i_operation = 'uninstall' i_version = i_version ) = abap_true ). ENDMETHOD. METHOD download_zipfile_pair. DATA l_dir_tmp_path TYPE text255. DATA lv_result TYPE abap_bool VALUE abap_true. DATA(wa_zipfile_inst) = get_by_op_version( i_op = 'install' i_version = i_version ). DATA(wa_zipfile_uninst) = get_by_op_version( i_op = 'uninstall' i_version = i_version ). IF wa_zipfile_inst IS NOT BOUND AND wa_zipfile_uninst IS NOT BOUND. " TODO: This should not be necessary and will be removed when refactoring has progressed wa_zipfile_inst = NEW lcl_sdk_zipfile( i_op = 'install' i_version = i_version ). wa_zipfile_uninst = NEW lcl_sdk_zipfile( i_op = 'uninstall' i_version = i_version ). add_pair( i_zipfile_inst = wa_zipfile_inst i_zipfile_uninst = wa_zipfile_uninst ). ENDIF. download_zipfile( wa_zipfile_inst ). download_zipfile( wa_zipfile_uninst ). ENDMETHOD. METHOD download_zipfile. IF file_manager->check_file_writable_at( i_path = i_zipfile->path ) = abap_false. MESSAGE |File at path { i_zipfile->path } not writable!| TYPE 'I' DISPLAY LIKE 'E' ##NO_TEXT. EXIT. ENDIF. cl_progress_indicator=>progress_indicate( i_text = |Downloading { i_zipfile->name } ...| i_processed = sy-tabix i_output_immediately = abap_true ) ##NO_TEXT. DATA(e_zipfile_blob) = internet_manager->download( i_absolute_uri = i_zipfile->uri i_blankstocrlf = abap_false ). TRY. file_manager->open_for_output( i_zipfile->path ). TRANSFER e_zipfile_blob TO i_zipfile->path. CLOSE DATASET i_zipfile->path. CATCH cx_sy_file_authority INTO DATA(r_ex1). RAISE EXCEPTION TYPE lcx_error EXPORTING previous = r_ex1 iv_msg = r_ex1->get_text( ). CATCH cx_sy_file_access_error INTO DATA(r_ex2). RAISE EXCEPTION TYPE lcx_error EXPORTING previous = r_ex2 iv_msg = r_ex1->get_text( ). CATCH cx_root INTO DATA(r_ex). RAISE EXCEPTION TYPE lcx_error EXPORTING previous = r_ex iv_msg = r_ex1->get_text( ). ENDTRY. IF sy-subrc <> 0. RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = |Could not convert data to XSTRING.| ##NO_TEXT. ENDIF. IF NOT exists_in_collection( i_op = i_zipfile->op i_version = i_zipfile->version ). add( i_zipfile ). ENDIF. ENDMETHOD. " TODO:Needs to go into UI layer METHOD ensure_zipfiles_downloaded. DATA lv_result TYPE abap_bool. lv_result = abap_true. IF NOT exists_on_disk_pair( i_version = i_version ). MESSAGE |ABAP SDK zipfile for installation/uninstallation in version { i_version } not present. Downloading them now.| TYPE 'I' ##NO_TEXT. TRY. download_zipfile_pair( i_version = i_version ). CATCH lcx_error. MESSAGE 'One or more ABAP SDK zipfiles could not be successfully downloaded, aborting' TYPE 'I' DISPLAY LIKE 'E' ##NO_TEXT. ENDTRY. ENDIF. r_result = lv_result. ENDMETHOD. " TODO: Currently not being used. Kept for future implementation of a mgmt dialog for zipfiles on disk METHOD clear_missing_zipfile_paths. DATA(zipfile_available) = abap_false. LOOP AT mt_sdk_zipfiles INTO DATA(wa_zipfile). zipfile_available = i_file_manager->lif_sdk_file_manager~check_file_exists_at( i_path = wa_zipfile->path ). IF zipfile_available = abap_false. wa_zipfile->set_path( i_path = '' ). ENDIF. ENDLOOP. ENDMETHOD. ENDCLASS. CLASS lcl_sdk_module DEFINITION. PUBLIC SECTION. TYPES: t_tla TYPE c LENGTH 4. DATA: tla TYPE t_tla READ-ONLY, " Three-letter-acronym (sometimes two-letter only) name TYPE string READ-ONLY, " Human-readable name cvers TYPE string READ-ONLY, " Currently installed version ctransport_inst TYPE string READ-ONLY, " Currently installed transport id ctransport_uninst TYPE string READ-ONLY, " Deletion transport id for the currently installed transport tp_rc TYPE string READ-ONLY, " TP returncode tp_icon TYPE string READ-ONLY, " TP icon indicating the state of the transport tp_text TYPE string READ-ONLY, " TP human-readable status text avers TYPE string READ-ONLY, " Available version atransport_inst TYPE string READ-ONLY, " Available transport id for installation is_core TYPE boolean READ-ONLY, " Is this a core module? is_popular TYPE boolean READ-ONLY, " Is this part of the popular modules group? op_icon TYPE string READ-ONLY, " Operation icon for ALV Tree View op_text TYPE string READ-ONLY, " Human-readable operation text op_code TYPE string READ-ONLY. " What will be happening after user hits execute METHODS: constructor IMPORTING i_tla TYPE t_tla i_name TYPE string OPTIONAL i_cvers TYPE string OPTIONAL i_ctransport_inst TYPE string OPTIONAL i_ctransport_uninst TYPE string OPTIONAL i_tp_rc TYPE string OPTIONAL i_tp_icon TYPE string OPTIONAL i_tp_text TYPE string OPTIONAL i_avers TYPE string OPTIONAL i_atransport_inst TYPE string OPTIONAL i_is_core TYPE boolean OPTIONAL i_is_popular TYPE boolean OPTIONAL i_op_icon TYPE string OPTIONAL i_op_text TYPE string OPTIONAL i_op_code TYPE string OPTIONAL, set_tla IMPORTING i_tla TYPE t_tla, set_name IMPORTING i_name TYPE string, set_cvers IMPORTING i_cvers TYPE string, set_ctransport_inst IMPORTING i_ctransport_inst TYPE string, set_ctransport_uninst IMPORTING i_ctransport_uninst TYPE string, set_tp_rc IMPORTING i_tp_rc TYPE string, set_tp_icon IMPORTING i_tp_icon TYPE string, set_tp_text IMPORTING i_tp_text TYPE string, set_avers IMPORTING i_avers TYPE string, set_atransport_inst IMPORTING i_atransport_inst TYPE string, set_is_core IMPORTING i_is_core TYPE boolean, set_is_popular IMPORTING i_is_popular TYPE boolean, set_op_icon IMPORTING i_op_icon TYPE string, set_op_text IMPORTING i_op_text TYPE string, set_op_code IMPORTING i_op_code TYPE string. ENDCLASS. CLASS lcl_sdk_module IMPLEMENTATION. METHOD constructor. tla = i_tla. name = i_name. cvers = i_cvers. ctransport_inst = i_ctransport_inst. ctransport_uninst = i_ctransport_uninst. tp_rc = i_tp_rc. tp_icon = i_tp_icon. tp_text = i_tp_text. avers = i_avers. atransport_inst = i_atransport_inst. is_core = i_is_core. is_popular = i_is_popular. op_icon = i_op_code. op_text = i_op_text. op_code = i_op_code. ENDMETHOD. METHOD set_tla. tla = i_tla. ENDMETHOD. METHOD set_name. name = i_name. ENDMETHOD. METHOD set_cvers. cvers = i_cvers. ENDMETHOD. METHOD set_ctransport_inst. ctransport_inst = i_ctransport_inst. ENDMETHOD. METHOD set_ctransport_uninst. ctransport_uninst = i_ctransport_uninst. ENDMETHOD. METHOD set_tp_rc. tp_rc = i_tp_rc. ENDMETHOD. METHOD set_tp_icon. tp_icon = i_tp_icon. ENDMETHOD. METHOD set_tp_text. tp_text = i_tp_text. ENDMETHOD. METHOD set_avers. avers = i_avers. ENDMETHOD. METHOD set_atransport_inst. atransport_inst = i_atransport_inst. ENDMETHOD. METHOD set_is_core. is_core = i_is_core. ENDMETHOD. METHOD set_is_popular. is_popular = i_is_popular. ENDMETHOD. METHOD set_op_icon. op_icon = i_op_icon. ENDMETHOD. METHOD set_op_text. op_text = i_op_text. ENDMETHOD. METHOD set_op_code. op_code = i_op_code. ENDMETHOD. ENDCLASS. CLASS lcl_sdk_module_collection DEFINITION. PUBLIC SECTION. TYPES: tt_sdk_module TYPE STANDARD TABLE OF REF TO lcl_sdk_module. DATA: mt_sdk_modules TYPE tt_sdk_module. METHODS: constructor IMPORTING i_modules TYPE tt_sdk_module RAISING lcx_error, add_module IMPORTING i_module TYPE REF TO lcl_sdk_module RAISING lcx_error, exists_in_collection IMPORTING i_tla TYPE lcl_sdk_module=>t_tla RETURNING VALUE(r_result) TYPE boolean, get_by_tla IMPORTING i_tla TYPE lcl_sdk_module=>t_tla RETURNING VALUE(r_module) TYPE REF TO lcl_sdk_module. ENDCLASS. CLASS lcl_sdk_module_collection IMPLEMENTATION. METHOD constructor. IF i_modules IS NOT INITIAL. mt_sdk_modules = i_modules. ENDIF. ENDMETHOD. METHOD add_module. IF i_module IS NOT BOUND. RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = |Unbound module object reference.| ##NO_TEXT. ENDIF. APPEND i_module TO mt_sdk_modules. ENDMETHOD. METHOD exists_in_collection. IF get_by_tla( i_tla = i_tla ) IS BOUND. r_result = abap_true. ELSE. r_result = abap_false. ENDIF. ENDMETHOD. METHOD get_by_tla. LOOP AT mt_sdk_modules INTO DATA(wa_module). IF wa_module->tla = i_tla. r_module = wa_module. RETURN. ENDIF. ENDLOOP. " returns unbound r_module if no module matches the tla ENDMETHOD. ENDCLASS. CLASS lcl_sdk_package_manager DEFINITION FINAL. PUBLIC SECTION. DATA: sdk_zipfiles TYPE REF TO lcl_sdk_zipfile_collection READ-ONLY, mt_installed_modules TYPE tt_sdk_module, mt_available_modules_inst TYPE tt_sdk_module, " available modules for installation (i.e. install transports) mt_available_modules_uninst TYPE tt_sdk_module. " available modules for uninstallation (i.e. uninstall transports) DATA: internet_manager TYPE REF TO lif_sdk_internet_manager READ-ONLY. DATA: certificate_manager TYPE REF TO lif_sdk_certificate_manager READ-ONLY. DATA: file_manager TYPE REF TO lif_sdk_file_manager READ-ONLY. DATA: transport_manager TYPE REF TO lif_sdk_transport_manager READ-ONLY. DATA: job_manager TYPE REF TO lif_sdk_job_manager READ-ONLY. METHODS: constructor IMPORTING i_batch_mode TYPE syst-batch OPTIONAL i_internet_manager TYPE REF TO lif_sdk_internet_manager OPTIONAL i_certificate_manager TYPE REF TO lif_sdk_certificate_manager OPTIONAL i_file_manager TYPE REF TO lcl_sdk_file_manager OPTIONAL i_transport_manager TYPE REF TO lif_sdk_transport_manager OPTIONAL i_job_manager TYPE REF TO lif_sdk_job_manager OPTIONAL i_sdk_zipfiles TYPE REF TO lcl_sdk_zipfile_collection OPTIONAL RAISING lcx_error, install_all_modules IMPORTING it_modules_to_be_installed TYPE tt_sdk_tla it_modules_to_be_deleted TYPE tt_sdk_tla RETURNING VALUE(r_jobnumber) TYPE btcjobcnt RAISING lcx_error, is_deprecated IMPORTING i_tla TYPE lcl_sdk_module=>t_tla RETURNING VALUE(r_result) TYPE abap_bool, is_core_installed RETURNING VALUE(r_result) TYPE abap_bool, is_module_core IMPORTING i_tla TYPE lcl_sdk_module=>t_tla RETURNING VALUE(r_result) TYPE abap_bool, is_version_latest IMPORTING i_version TYPE string RETURNING VALUE(r_result) TYPE abap_bool, get_sdk_installed_modules RETURNING VALUE(r_installed_modules) TYPE tt_sdk_module RAISING lcx_error, get_sdk_deprecated_mod_inst RETURNING VALUE(r_deprecated_modules) TYPE tt_sdk_module, get_sdk_avail_modules_json IMPORTING i_operation TYPE string i_source TYPE string i_version TYPE string DEFAULT 'LATEST' RETURNING VALUE(r_available_modules) TYPE tt_sdk_module RAISING lcx_error, update_zipfiles_if_outdated IMPORTING i_avers_core_inst TYPE string i_avers_core_uninst TYPE string RETURNING VALUE(r_result) TYPE abap_bool RAISING lcx_error, run_foreground IMPORTING i_modules_to_be_installed TYPE tt_sdk_tla i_modules_to_be_deleted TYPE tt_sdk_tla i_target_version TYPE string EXPORTING e_tp_rc_inst TYPE stpa-retcode es_exception_inst TYPE stmscalert e_tp_rc_uninst TYPE stpa-retcode es_exception_uninst TYPE stmscalert RAISING lcx_error, run_background RAISING lcx_error. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl_sdk_package_manager IMPLEMENTATION. METHOD constructor. IF lcl_sdk_utils=>has_prod_client( ). MESSAGE |System has at least one productive client, please use TMS.| TYPE 'A' ##NO_TEXT. ENDIF. IF i_internet_manager IS BOUND. internet_manager = i_internet_manager. ELSE. internet_manager = NEW lcl_sdk_internet_manager( ). ENDIF. IF i_certificate_manager IS BOUND. certificate_manager = i_certificate_manager. ELSE. certificate_manager = NEW lcl_sdk_certificate_manager( i_internet_manager = internet_manager ). ENDIF. IF i_file_manager IS BOUND. file_manager = i_file_manager. ELSE. file_manager = file_manager = NEW lcl_sdk_file_manager( ). ENDIF. IF i_transport_manager IS BOUND. transport_manager = i_transport_manager. ELSE. transport_manager = NEW lcl_sdk_transport_manager( ). ENDIF. IF i_job_manager IS BOUND. job_manager = i_job_manager. ELSE. job_manager = NEW lcl_sdk_job_manager( ). ENDIF. IF i_sdk_zipfiles IS BOUND. sdk_zipfiles = i_sdk_zipfiles. ELSE. sdk_zipfiles = NEW lcl_sdk_zipfile_collection( ). ENDIF. TRY. IF internet_manager->has_internet_access( ) = abap_false. MESSAGE |This report requires HTTP(S) Internet access, please enable before usage.| TYPE 'A' ##NO_TEXT. ENDIF. CATCH lcx_error INTO DATA(r_error). MESSAGE |This report requires HTTP(S) Internet access, please enable before usage.| TYPE 'A' ##NO_TEXT. ENDTRY. mt_installed_modules = get_sdk_installed_modules( ). mt_available_modules_inst = get_sdk_avail_modules_json( i_operation = 'install' i_source = 'web' i_version = 'LATEST' ) ##NO_TEXT. mt_available_modules_uninst = get_sdk_avail_modules_json( i_operation = 'uninstall' i_source = 'web' i_version = 'LATEST' ) ##NO_TEXT. IF i_batch_mode = abap_true. run_background( ). ENDIF. ENDMETHOD. METHOD is_deprecated. DATA(deprecated_modules) = get_sdk_deprecated_mod_inst( ). r_result = xsdbool( line_exists( deprecated_modules[ tla = i_tla ] ) ). ENDMETHOD. METHOD install_all_modules. DATA: lt_modules_to_be_installed TYPE tt_sdk_tla. DATA: lt_modules_to_be_deleted TYPE tt_sdk_tla. DATA: lv_target_version TYPE string VALUE 'LATEST'. DATA(lt_available_modules_cv) = get_sdk_avail_modules_json( i_operation = 'install' i_source = 'web' i_version = lv_target_version ). DATA: wa_available_module_cv TYPE ts_sdk_module. LOOP AT lt_available_modules_cv INTO wa_available_module_cv. INSERT VALUE ts_sdk_tla( tla = wa_available_module_cv-tla version = lv_target_version ) INTO TABLE lt_modules_to_be_installed . ENDLOOP. IF lines( lt_modules_to_be_installed ) > 0. IF sdk_zipfiles->ensure_zipfiles_downloaded( i_version = lv_target_version ) = abap_false. RETURN. ENDIF. IF update_zipfiles_if_outdated( i_avers_core_inst = mt_available_modules_inst[ tla = 'core' ]-avers i_avers_core_uninst = mt_available_modules_uninst[ tla = 'core' ]-avers ) = abap_false. RETURN. ENDIF. ENDIF. r_jobnumber = job_manager->submit_batch_job( i_modules_to_be_installed = lt_modules_to_be_installed i_modules_to_be_deleted = lt_modules_to_be_deleted i_target_version = lv_target_version ). ENDMETHOD. "TODO: refactor and compare with ensure_zipfiles_present METHOD update_zipfiles_if_outdated. DATA lv_result TYPE abap_bool. DATA lv_dl_result TYPE abap_bool. r_result = abap_true. DATA(lt_mod_avail_inst_zip) = get_sdk_avail_modules_json( i_operation = 'install' i_source = 'zip' i_version = 'LATEST' ). DATA(lt_mod_avail_uninst_zip) = get_sdk_avail_modules_json( i_operation = 'uninstall' i_source = 'zip' i_version = 'LATEST' ). IF lcl_sdk_utils=>cmp_version_string( i_string1 = i_avers_core_inst i_string2 = lt_mod_avail_inst_zip[ tla = 'core' ]-avers ) = 1 OR lcl_sdk_utils=>cmp_version_string( i_string1 = i_avers_core_uninst i_string2 = lt_mod_avail_uninst_zip[ tla = 'core' ]-avers ) = 1. MESSAGE 'One or more ABAP SDK zipfiles not current. Downloading new version now.' TYPE 'I' ##NO_TEXT. TRY. sdk_zipfiles->download_zipfile_pair( i_version = 'LATEST' ). CATCH lcx_error. MESSAGE 'One or more ABAP SDK zipfiles could not be successfully downloaded, aborting' TYPE 'I' DISPLAY LIKE 'E' ##NO_TEXT. r_result = abap_false. ENDTRY. ENDIF. ENDMETHOD. METHOD get_sdk_installed_modules. DATA lt_installed_modules_list TYPE tt_sdk_module. DATA ls_installed_module TYPE ts_sdk_module. DATA l_abap_matcher TYPE REF TO cl_abap_matcher. DATA l_abap_regex_posix TYPE REF TO cl_abap_regex. SELECT devclass, ctext FROM tdevct WHERE spras = 'E' AND devclass LIKE '/AWS1/API_%' INTO (@DATA(l_sdk_devclass), @DATA(l_sdk_ctext)). "#EC CI_SGLSELECT IF strlen( l_sdk_devclass ) <= 13. ls_installed_module-tla = to_lower( substring_after( val = l_sdk_devclass sub = '/AWS1/API_' ) ). ls_installed_module-name = l_sdk_ctext. APPEND ls_installed_module TO lt_installed_modules_list. ENDIF. ENDSELECT. IF sy-subrc <> 0. " no issue, no SDK modules are installed yet CLEAR lt_installed_modules_list. ENDIF. DATA: l_collect_date TYPE sy-datum, l_collect_time TYPE sy-uzeit, l_collect_flag TYPE stms_flag, ls_exception TYPE stmscalert. DATA: lt_buffer TYPE STANDARD TABLE OF tmsbuffer, lt_counter TYPE STANDARD TABLE OF tmsbufcnt, lt_project TYPE STANDARD TABLE OF tmsbufpro, lt_domain TYPE STANDARD TABLE OF tmscdom, lt_system TYPE STANDARD TABLE OF tmscsys, lt_group TYPE STANDARD TABLE OF tmscnfs. CALL FUNCTION 'TMS_MGR_READ_TRANSPORT_QUEUE' IMPORTING ev_collect_date = l_collect_date ev_collect_time = l_collect_time ev_collect_flag = l_collect_flag es_exception = ls_exception TABLES tt_buffer = lt_buffer tt_counter = lt_counter tt_project = lt_project tt_domain = lt_domain tt_system = lt_system tt_group = lt_group EXCEPTIONS read_config_failed = 1 OTHERS = 2. IF sy-subrc <> 0. RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = |Could not read TMS queue| ##NO_TEXT. ENDIF. CLEAR ls_exception. DATA l_system TYPE tmssysnam. DATA: l_service_vers TYPE tmsrel, lt_tmstpalogs TYPE tmstpalogs, lt_irt_requests TYPE STANDARD TABLE OF ctrs_requ. l_system = lcl_sdk_utils=>get_system_name( ). CALL FUNCTION 'TMS_TM_GET_TRLIST' EXPORTING iv_system = l_system iv_startdate = '19000101' iv_starttime = '000000' iv_enddate = sy-datum iv_endtime = sy-uzeit iv_allcli = '' iv_imports = 'X' IMPORTING ev_service_vers = l_service_vers et_tmstpalog = lt_tmstpalogs es_exception = ls_exception TABLES irt_requests = lt_irt_requests EXCEPTIONS alert = 1 OTHERS = 2. IF sy-subrc <> 0. RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = |Could not read get TR list from { l_system }| ##NO_TEXT. ENDIF. DATA ls_tmstpalog TYPE tmstpalog. LOOP AT lt_installed_modules_list ASSIGNING FIELD-SYMBOL(). LOOP AT lt_tmstpalogs ASSIGNING FIELD-SYMBOL(). DATA(l_truser) = 'AWS_' && -tla. IF is_module_core( -tla ). l_truser = 'AWS_CORE'. IF lines( mt_available_modules_inst ) > 0. -avers = me->mt_available_modules_inst[ tla = 'core' ]-avers. ENDIF. ENDIF. " Find the transport log line pertaining to the tla of the installed module under scrutiny IF -truser = to_upper( l_truser ). "AND ( -retcode = '0000' OR -retcode = '0004' ). " If the transport log line has no timestamp, assume it's our latest transport IF ls_tmstpalog-trtime IS INITIAL. ls_tmstpalog = . ENDIF. " If we find a more recent transport while cycling through the transport log, this becomes our candidate for figuring out the current version IF -trtime >= ls_tmstpalog-trtime. ls_tmstpalog = . ENDIF. ENDIF. ENDLOOP. DATA(lo_regex) = NEW cl_abap_regex( pattern = '\d{1,}\.\d{1,}\.\d{0,}' ) ##REGEX_POSIX. l_abap_matcher = lo_regex->create_matcher( text = ls_tmstpalog-as4text ). DATA(lt_results) = l_abap_matcher->find_all( ). READ TABLE lt_results INTO DATA(wa_result) INDEX 1. IF sy-subrc <> 0. MESSAGE |Expected to find exactly one version number in text { ls_tmstpalog-as4text }| TYPE 'I' DISPLAY LIKE 'E' ##NO_TEXT. RETURN. ENDIF. DATA l_cvers_string TYPE string. l_cvers_string = substring( val = ls_tmstpalog-as4text off = wa_result-offset len = wa_result-length ). -cvers = l_cvers_string. " if not already set as part of core IF -avers IS INITIAL AND lines( mt_available_modules_inst ) > 0. -avers = VALUE #( me->mt_available_modules_inst[ tla = -tla ]-avers DEFAULT 'n.a.' ). ENDIF. -ctransport = ls_tmstpalog-trkorr. -tp_rc = ls_tmstpalog-retcode. CASE -tp_rc. WHEN '0000'. -tp_icon = '@5B@'. -tp_text = 'Imported successfully.'. WHEN '0004'. -tp_icon = '@5D@'. -tp_text = 'Imported with warnings.'. WHEN '0008'. -tp_icon = '@5C@'. -tp_text = 'Imported with errors.'. WHEN 'OTHERS'. -tp_icon = '@AG@'. -tp_text = 'Unknown error, check transport logs.'. ENDCASE. CLEAR ls_tmstpalog. ENDLOOP. r_installed_modules = lt_installed_modules_list. ENDMETHOD. METHOD get_sdk_deprecated_mod_inst. TRY. DATA(lt_installed_modules) = get_sdk_installed_modules( ). CATCH lcx_error. ENDTRY. LOOP AT lt_installed_modules INTO DATA(wa_inst). IF is_module_core( wa_inst-tla ). CONTINUE. ELSE. READ TABLE mt_available_modules_inst WITH KEY tla = wa_inst-tla TRANSPORTING NO FIELDS. IF sy-subrc <> 0. APPEND VALUE #( tla = wa_inst-tla ) TO r_deprecated_modules. ENDIF. ENDIF. ENDLOOP. ENDMETHOD. METHOD get_sdk_avail_modules_json. DATA l_sdk_json TYPE w3_url. DATA lts_sdk_avail_modules TYPE tt_sdk_module. CASE i_source. WHEN 'web'. DATA(l_jsonx) = internet_manager->download( i_absolute_uri = sdk_zipfiles->get_by_op_version( i_op = i_operation i_version = i_version )->json_web i_blankstocrlf = abap_false ). WHEN 'zip'. l_jsonx = file_manager->get_file_from_zip( i_zipfile_absolute_path = sdk_zipfiles->get_by_op_version( i_op = i_operation i_version = i_version )->path i_file_to_retrieve = lif_sdk_constants=>c_sdk_index_json_zip_path ). WHEN 'others'. ENDCASE. DATA(l_reader) = cl_sxml_string_reader=>create( input = l_jsonx normalizing = abap_true ). DATA: BEGIN OF wa_node, node_type TYPE string, name TYPE string, value TYPE string, depth TYPE i VALUE 0, END OF wa_node, lt_transport_nodes LIKE TABLE OF wa_node. DATA depth_counter TYPE i VALUE 0. DO. CLEAR wa_node. DATA(l_node) = l_reader->read_next_node( ). IF l_node IS INITIAL. EXIT. ENDIF. CASE l_node->type. WHEN if_sxml_node=>co_nt_element_open. depth_counter = depth_counter + 1. DATA(l_open_element) = CAST if_sxml_open_element( l_node ). DATA(lt_attributes) = l_open_element->get_attributes( ). LOOP AT lt_attributes INTO DATA(l_attribute_node). wa_node-node_type = 'attribute'. wa_node-name = l_attribute_node->qname-name. IF l_attribute_node->value_type = if_sxml_value=>co_vt_text. wa_node-value = l_attribute_node->get_value( ). ENDIF. wa_node-depth = depth_counter. APPEND wa_node TO lt_transport_nodes. ENDLOOP. CONTINUE. WHEN if_sxml_node=>co_nt_element_close. depth_counter = depth_counter - 1. CONTINUE. WHEN if_sxml_node=>co_nt_value. DATA(l_value_node) = CAST if_sxml_value_node( l_node ). wa_node-node_type = 'value'. IF l_value_node->value_type = if_sxml_value=>co_vt_text. wa_node-value = l_value_node->get_value( ). ENDIF. wa_node-depth = depth_counter. APPEND wa_node TO lt_transport_nodes. CONTINUE. ENDCASE. ENDDO. DATA wa_module TYPE ts_sdk_module. DATA(i) = 1. DATA(j) = 0. " Offset for TLA -> name DATA(k) = 0. " Offset for Groups -> popular -> title -> tla LOOP AT lt_transport_nodes ASSIGNING FIELD-SYMBOL(). CLEAR wa_module. IF -value = 'core'. wa_module-tla = 'core'. " tla nametag wa_module-atransport = lt_transport_nodes[ 8 ]-value. " transport name wa_module-avers = lt_transport_nodes[ 4 ]-value. " version wa_module-is_core = abap_true. " is core INSERT wa_module INTO TABLE lts_sdk_avail_modules. CONTINUE. ENDIF. IF i >= 16 AND j < i AND i < lines( lt_transport_nodes ) AND lt_transport_nodes[ i ]-depth > 2. wa_module-tla = lt_transport_nodes[ i ]-value. " tla nametag wa_module-atransport = lt_transport_nodes[ i + 2 ]-value. " transport name wa_module-is_core = lt_transport_nodes[ i + 6 ]-value. " is core wa_module-avers = lt_transport_nodes[ 4 ]-value. " version INSERT wa_module INTO TABLE lts_sdk_avail_modules. i = i + 7. ELSEIF i < 16. i = i + 1. CONTINUE. ELSE. j = i. EXIT. ENDIF. ENDLOOP. LOOP AT lts_sdk_avail_modules INTO wa_module. IF wa_module-tla = 'core'. wa_module-name = 'AWS SDK for SAP ABAP core [s3, smr, rla, sts]' ##NO_TEXT. ENDIF. DATA(j_offset) = 0. WHILE j_offset < lines( lt_transport_nodes ) - j. IF lt_transport_nodes[ j + j_offset ]-value = wa_module-tla. wa_module-name = lt_transport_nodes[ j_offset + j + 2 ]-value. EXIT. ENDIF. j_offset = j_offset + 1. ENDWHILE. MODIFY lts_sdk_avail_modules FROM wa_module TRANSPORTING tla name. ENDLOOP. k = j + j_offset + 8. DATA(k_offset) = 0. WHILE k_offset <= lines( lt_transport_nodes ) - k. IF line_exists( lts_sdk_avail_modules[ tla = lt_transport_nodes[ k + k_offset ]-value ] ). lts_sdk_avail_modules[ tla = lt_transport_nodes[ k + k_offset ]-value ]-is_popular = abap_true . ENDIF. k_offset = k_offset + 1. ENDWHILE. r_available_modules = lts_sdk_avail_modules. ENDMETHOD. METHOD is_core_installed. DATA: lv_result TYPE abap_bool VALUE abap_false. DATA(lt_installed_modules) = mt_installed_modules. IF line_exists( lt_installed_modules[ tla = 'sts' ] ) AND line_exists( lt_installed_modules[ tla = 's3' ] ) AND line_exists( lt_installed_modules[ tla = 'smr' ] ) AND line_exists( lt_installed_modules[ tla = 'rla' ] ). lv_result = abap_true. ENDIF. r_result = lv_result. ENDMETHOD. METHOD is_module_core. r_result = xsdbool( i_tla = 'sts' OR i_tla = 's3' OR i_tla = 'smr' OR i_tla = 'rla' ). ENDMETHOD. METHOD is_version_latest. TRY. DATA(lt_latest_inst_modules) = get_sdk_avail_modules_json( i_operation = 'install' i_source = 'web' i_version = 'LATEST' ). CATCH lcx_error. ENDTRY. IF i_version = lt_latest_inst_modules[ tla = 'core' ]-avers. r_result = abap_true. ELSE. r_result = abap_false. ENDIF. ENDMETHOD. METHOD run_foreground. DATA: l_tp_ret_code_inst TYPE stpa-retcode. DATA: ls_exception_inst TYPE stmscalert. DATA: l_tp_ret_code_uninst TYPE stpa-retcode. DATA: ls_exception_uninst TYPE stmscalert. DATA(lt_modules_to_be_installed) = i_modules_to_be_installed. DATA(lt_modules_to_be_deleted) = i_modules_to_be_deleted. DATA lt_transport_list_inst TYPE stms_tr_requests. DATA lt_transport_list_uninst TYPE stms_tr_requests. DATA lt_avail_modules_inst TYPE tt_sdk_module. lt_avail_modules_inst = get_sdk_avail_modules_json( i_operation = 'install' i_source = 'zip' i_version = i_target_version ). LOOP AT lt_modules_to_be_installed ASSIGNING FIELD-SYMBOL(). transport_manager->get_sdk_cofile_from_zip( EXPORTING i_tla = lt_avail_modules_inst[ tla = -tla ]-tla i_transport = lt_avail_modules_inst[ tla = -tla ]-atransport i_operation = 'install' i_version = i_target_version i_zipfile_absolute_path = sdk_zipfiles->get_by_op_version( i_op = 'install' i_version = i_target_version )->path IMPORTING e_cofile_name = DATA(l_cofile_name) e_cofile_blob = DATA(l_cofile_blob) ). transport_manager->get_sdk_datafile_from_zip( EXPORTING i_tla = lt_avail_modules_inst[ tla = -tla ]-tla i_transport = lt_avail_modules_inst[ tla = -tla ]-atransport i_operation = 'install' i_version = i_target_version i_zipfile_absolute_path = sdk_zipfiles->get_by_op_version( i_op = 'install' i_version = i_target_version )->path IMPORTING e_datafile_name = DATA(l_datafile_name) e_datafile_blob = DATA(l_datafile_blob) ). DATA(l_success_write) = transport_manager->write_sdk_transport_trdir( i_cofile_name = l_cofile_name i_datafile_name = l_datafile_name i_cofile_blob = l_cofile_blob i_datafile_blob = l_datafile_blob ). INSERT VALUE stms_tr_request( trkorr = lt_avail_modules_inst[ tla = -tla ]-atransport tarcli = sy-mandt ) INTO TABLE lt_transport_list_inst. ENDLOOP. CALL METHOD transport_manager->import_sdk_transports EXPORTING it_transport_names = lt_transport_list_inst IMPORTING e_tp_retcode = l_tp_ret_code_inst es_exception = ls_exception_inst. e_tp_rc_inst = l_tp_ret_code_inst. es_exception_inst = ls_exception_inst. LOOP AT lt_modules_to_be_deleted ASSIGNING FIELD-SYMBOL(). DATA lt_avail_modules_uninst TYPE tt_sdk_module. lt_avail_modules_uninst = get_sdk_avail_modules_json( i_operation = 'uninstall' i_source = 'zip' i_version = i_target_version ). transport_manager->get_sdk_cofile_from_zip( EXPORTING i_tla = lt_avail_modules_uninst[ tla = -tla ]-tla i_transport = lt_avail_modules_uninst[ tla = -tla ]-atransport i_operation = 'uninstall' i_version = i_target_version i_zipfile_absolute_path = sdk_zipfiles->get_by_op_version( i_op = 'uninstall' i_version = i_target_version )->path IMPORTING e_cofile_name = DATA(l_uninstall_cofile_name) e_cofile_blob = DATA(l_uninstall_cofile_blob) ). transport_manager->get_sdk_datafile_from_zip( EXPORTING i_tla = lt_avail_modules_uninst[ tla = -tla ]-tla i_transport = lt_avail_modules_uninst[ tla = -tla ]-atransport i_operation = 'uninstall' i_version = i_target_version i_zipfile_absolute_path = sdk_zipfiles->get_by_op_version( i_op = 'uninstall' i_version = i_target_version )->path IMPORTING e_datafile_name = DATA(l_uninstall_datafile_name) e_datafile_blob = DATA(l_uninstall_datafile_blob) ). transport_manager->write_sdk_transport_trdir( EXPORTING i_cofile_name = l_uninstall_cofile_name i_datafile_name = l_uninstall_datafile_name i_cofile_blob = l_uninstall_cofile_blob i_datafile_blob = l_uninstall_datafile_blob RECEIVING r_success = DATA(l_uninstall_success_write) ). INSERT VALUE stms_tr_request( trkorr = lt_avail_modules_uninst[ tla = -tla ]-atransport tarcli = sy-mandt ) INTO TABLE lt_transport_list_uninst. ENDLOOP. CALL METHOD transport_manager->import_sdk_transports EXPORTING it_transport_names = lt_transport_list_uninst IMPORTING e_tp_retcode = l_tp_ret_code_uninst es_exception = ls_exception_uninst. e_tp_rc_uninst = l_tp_ret_code_uninst. es_exception_uninst = ls_exception_uninst. ENDMETHOD. METHOD run_background. DATA: l_tp_rc_inst TYPE stpa-retcode. DATA: ls_exception_inst TYPE stmscalert. DATA: l_tp_rc_uninst TYPE stpa-retcode. DATA: ls_exception_uninst TYPE stmscalert. DATA: st_modules_to_be_installed TYPE tt_sdk_tla. DATA: st_modules_to_be_deleted TYPE tt_sdk_tla. DATA: s_target_version TYPE string. DATA: lt_transport_list_inst TYPE stms_tr_requests. DATA: lt_transport_list_uninst TYPE stms_tr_requests. IMPORT st_modules_to_be_installed = st_modules_to_be_installed FROM SHARED BUFFER indx(mi) ID 'MOD_INST'. IMPORT st_modules_to_be_deleted = st_modules_to_be_deleted FROM SHARED BUFFER indx(md) ID 'MOD_DELE'. IMPORT s_target_version = s_target_version FROM SHARED BUFFER indx(tv) ID 'TAR_VERS'. IF sdk_zipfiles->exists_on_disk_pair( i_version = s_target_version ) = abap_false. DATA(wa_zipfile_inst) = NEW lcl_sdk_zipfile( i_op = 'install' i_version = s_target_version ). DATA(wa_zipfile_uninst) = NEW lcl_sdk_zipfile( i_op = 'uninstall' i_version = s_target_version ). sdk_zipfiles->add_pair( i_zipfile_inst = wa_zipfile_inst i_zipfile_uninst = wa_zipfile_uninst ). sdk_zipfiles->download_zipfile_pair( i_version = s_target_version ). ELSE. wa_zipfile_inst = sdk_zipfiles->get_by_op_version( i_op = 'install' i_version = s_target_version ). wa_zipfile_uninst = sdk_zipfiles->get_by_op_version( i_op = 'uninstall' i_version = s_target_version ). ENDIF. WRITE / |In background mode| ##NO_TEXT. WRITE /. WRITE /. WRITE / |Modules to be installed (transport file { wa_zipfile_inst->path }| ##NO_TEXT. LOOP AT st_modules_to_be_installed ASSIGNING FIELD-SYMBOL(). WRITE -tla && | |. ENDLOOP. WRITE /. WRITE / |to be deleted (transport file { wa_zipfile_uninst->path }| ##NO_TEXT. LOOP AT st_modules_to_be_deleted ASSIGNING FIELD-SYMBOL(). WRITE / -tla && | |. ENDLOOP. DATA lt_avail_modules_inst TYPE tt_sdk_module. lt_avail_modules_inst = get_sdk_avail_modules_json( i_operation = wa_zipfile_inst->op i_source = 'zip' i_version = wa_zipfile_inst->version ). LOOP AT st_modules_to_be_installed ASSIGNING FIELD-SYMBOL(). transport_manager->get_sdk_cofile_from_zip( EXPORTING i_tla = lt_avail_modules_inst[ tla = -tla ]-tla i_transport = lt_avail_modules_inst[ tla = -tla ]-atransport i_operation = 'install' i_version = s_target_version i_zipfile_absolute_path = sdk_zipfiles->get_by_op_version( i_op = 'install' i_version = s_target_version )->path IMPORTING e_cofile_name = DATA(l_cofile_name) e_cofile_blob = DATA(l_cofile_blob) ). WRITE / |Downloaded cofile | && lt_avail_modules_inst[ tla = -tla ]-atransport && | for TLA | && lt_avail_modules_inst[ tla = -tla ]-tla ##NO_TEXT. transport_manager->get_sdk_datafile_from_zip( EXPORTING i_tla = lt_avail_modules_inst[ tla = -tla ]-tla i_transport = lt_avail_modules_inst[ tla = -tla ]-atransport i_operation = 'install' i_version = s_target_version i_zipfile_absolute_path = sdk_zipfiles->get_by_op_version( i_op = 'install' i_version = s_target_version )->path IMPORTING e_datafile_name = DATA(l_datafile_name) e_datafile_blob = DATA(l_datafile_blob) ). WRITE / |Downloaded data file | && lt_avail_modules_inst[ tla = -tla ]-atransport && | for TLA | && lt_avail_modules_inst[ tla = -tla ]-tla ##NO_TEXT. transport_manager->write_sdk_transport_trdir( EXPORTING i_cofile_name = l_cofile_name i_datafile_name = l_datafile_name i_cofile_blob = l_cofile_blob i_datafile_blob = l_datafile_blob RECEIVING r_success = DATA(l_success_write) ). WRITE / |Wrote cofile and datafile for transport | && lt_avail_modules_inst[ tla = -tla ]-atransport && | for TLA | && lt_avail_modules_inst[ tla = -tla ]-tla && | successfully? -> | && l_success_write ##NO_TEXT. INSERT VALUE stms_tr_request( trkorr = lt_avail_modules_inst[ tla = -tla ]-atransport ) INTO TABLE lt_transport_list_inst. ENDLOOP. CALL METHOD transport_manager->import_sdk_transports EXPORTING it_transport_names = lt_transport_list_inst IMPORTING e_tp_retcode = l_tp_rc_inst es_exception = ls_exception_inst. WRITE / |Imported installation transport with tp return code: | && l_tp_rc_inst && |, message was: | && ls_exception_inst-error ##NO_TEXT. DATA lt_avail_modules_uninst TYPE tt_sdk_module. lt_avail_modules_uninst = get_sdk_avail_modules_json( i_operation = wa_zipfile_uninst->op i_source = 'zip' i_version = wa_zipfile_uninst->version ). LOOP AT st_modules_to_be_deleted ASSIGNING FIELD-SYMBOL(). transport_manager->get_sdk_cofile_from_zip( EXPORTING i_tla = lt_avail_modules_uninst[ tla = -tla ]-tla i_transport = lt_avail_modules_uninst[ tla = -tla ]-atransport i_operation = 'uninstall' i_version = s_target_version i_zipfile_absolute_path = sdk_zipfiles->get_by_op_version( i_op = 'uninstall' i_version = s_target_version )->path IMPORTING e_cofile_name = DATA(l_uninstall_cofile_name) e_cofile_blob = DATA(l_uninstall_cofile_blob) ). transport_manager->get_sdk_datafile_from_zip( EXPORTING i_tla = lt_avail_modules_uninst[ tla = -tla ]-tla i_transport = lt_avail_modules_uninst[ tla = -tla ]-atransport i_operation = 'uninstall' i_version = s_target_version i_zipfile_absolute_path = sdk_zipfiles->get_by_op_version( i_op = 'uninstall' i_version = s_target_version )->path IMPORTING e_datafile_name = DATA(l_uninstall_datafile_name) e_datafile_blob = DATA(l_uninstall_datafile_blob) ). transport_manager->write_sdk_transport_trdir( EXPORTING i_cofile_name = l_uninstall_cofile_name i_datafile_name = l_uninstall_datafile_name i_cofile_blob = l_uninstall_cofile_blob i_datafile_blob = l_uninstall_datafile_blob RECEIVING r_success = DATA(l_uninstall_success_write) ). INSERT VALUE stms_tr_request( trkorr = lt_avail_modules_uninst[ tla = -tla ]-atransport ) INTO TABLE lt_transport_list_uninst. ENDLOOP. CALL METHOD transport_manager->import_sdk_transports EXPORTING it_transport_names = lt_transport_list_uninst IMPORTING e_tp_retcode = l_tp_rc_uninst es_exception = ls_exception_uninst. WRITE / |Imported uninstallation transports with tp return code: | && l_tp_rc_uninst && |, message was: | && ls_exception_uninst-error ##NO_TEXT. DELETE FROM SHARED BUFFER indx(mi) ID 'MOD_INST'. DELETE FROM SHARED BUFFER indx(md) ID 'MOD_DELE'. DELETE FROM SHARED BUFFER indx(tv) ID 'TAR_VERS'. ENDMETHOD. ENDCLASS. CLASS lcl_ui_tree_controller DEFINITION FINAL. PUBLIC SECTION. INTERFACES if_salv_csqt_content_manager. TYPES: BEGIN OF ts_named_salv_node_key, node_name TYPE string, key TYPE salv_de_node_key, END OF ts_named_salv_node_key, tt_named_salv_node_key TYPE STANDARD TABLE OF ts_named_salv_node_key WITH KEY node_name. DATA: sdk_package_manager TYPE REF TO lcl_sdk_package_manager READ-ONLY, mr_container TYPE REF TO cl_gui_container, mr_tree TYPE REF TO cl_salv_tree, mt_treetab TYPE tt_sdk_module, mt_popular_modules TYPE tt_sdk_tla, mt_modules_to_be_installed TYPE tt_sdk_tla, mt_modules_to_be_deleted TYPE tt_sdk_tla, mt_modules_to_be_updated TYPE tt_sdk_tla, m_sdk_available_version TYPE string, mt_folder_node_keys TYPE tt_named_salv_node_key, m_sdk_core_expanded TYPE abap_bool VALUE abap_true, m_available_modules_expanded TYPE abap_bool VALUE abap_true, m_installed_modules_expanded TYPE abap_bool VALUE abap_true, m_fullscreen TYPE abap_bool VALUE abap_false. ALIASES fill_container_content FOR if_salv_csqt_content_manager~fill_container_content. METHODS: constructor IMPORTING i_sdk_package_manager TYPE REF TO lcl_sdk_package_manager RAISING lcx_error, get_modules_to_be_installed IMPORTING i_target_version TYPE string RETURNING VALUE(rt_modules_to_be_installed) TYPE tt_sdk_tla, get_modules_to_be_deleted IMPORTING i_target_version TYPE string RETURNING VALUE(rt_modules_to_be_deleted) TYPE tt_sdk_tla, get_modules_to_be_updated IMPORTING i_target_version TYPE string RETURNING VALUE(rt_modules_to_be_updated) TYPE tt_sdk_tla, save_node_key IMPORTING ir_node_name TYPE string ir_node_key TYPE salv_de_node_key, toggle_inst_modules IMPORTING i_checked TYPE abap_bool, fill_fullscreen_content, create_container, create_fullscreen, draw_tree, draw_columns, draw_nodes, draw_node_sdk_core, draw_node_installed_modules, draw_node_available_modules, draw_header, draw_footer, delete_nodes, refresh RAISING lcx_error, refresh_nodes, refresh_buttons, set_handlers, set_settings, set_functions, handle_user_command FOR EVENT added_function OF cl_salv_events_tree IMPORTING e_salv_function , handle_checkbox_changed FOR EVENT checkbox_change OF cl_salv_events_tree IMPORTING node_key columnname checked, handle_double_click FOR EVENT double_click OF cl_salv_events_tree IMPORTING node_key columnname, handle_on_close FOR EVENT close OF cl_gui_dialogbox_container IMPORTING sender. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS lcl_ui_selection_validator DEFINITION FINAL. PUBLIC SECTION. CLASS-METHODS: validate_selection IMPORTING it_modules_tbi TYPE tt_sdk_tla it_modules_tbd TYPE tt_sdk_tla i_op TYPE string i_salv_function TYPE syst_ucomm i_tree_controller TYPE REF TO lcl_ui_tree_controller RETURNING VALUE(r_result) TYPE abap_bool RAISING lcx_error, check_mod_thresholds IMPORTING it_modules_tbi TYPE tt_sdk_tla it_modules_tbd TYPE tt_sdk_tla i_op TYPE string i_salv_function TYPE syst_ucomm i_tree_controller TYPE REF TO lcl_ui_tree_controller RETURNING VALUE(r_result) TYPE abap_bool RAISING lcx_error, check_core_validity IMPORTING it_modules_tbi TYPE tt_sdk_tla it_modules_tbd TYPE tt_sdk_tla i_op TYPE string i_salv_function TYPE syst_ucomm i_tree_controller TYPE REF TO lcl_ui_tree_controller RETURNING VALUE(r_result) TYPE abap_bool RAISING lcx_error, check_populated IMPORTING it_modules_tbi TYPE tt_sdk_tla it_modules_tbd TYPE tt_sdk_tla i_op TYPE string i_salv_function TYPE syst_ucomm i_tree_controller TYPE REF TO lcl_ui_tree_controller RETURNING VALUE(r_result) TYPE abap_bool RAISING lcx_error. ENDCLASS. CLASS lcl_ui_selection_validator IMPLEMENTATION. METHOD validate_selection. CHECK check_populated( it_modules_tbi = it_modules_tbi it_modules_tbd = it_modules_tbd i_op = i_op i_salv_function = i_salv_function i_tree_controller = i_tree_controller ). CHECK check_core_validity( it_modules_tbi = it_modules_tbi it_modules_tbd = it_modules_tbd i_op = i_op i_salv_function = i_salv_function i_tree_controller = i_tree_controller ). CHECK check_mod_thresholds( it_modules_tbi = it_modules_tbi it_modules_tbd = it_modules_tbd i_op = i_op i_salv_function = i_salv_function i_tree_controller = i_tree_controller ). r_result = abap_true. ENDMETHOD. METHOD check_mod_thresholds. DATA lv_text TYPE string. DATA lv_answer TYPE c. CASE i_op. WHEN 'install'. DATA(lv_number_modules_inst) = lines( it_modules_tbi ). DATA(lv_number_new_modules) = 0. DATA(lv_number_modules_avail_inst) = lines( i_tree_controller->sdk_package_manager->mt_available_modules_inst ). " determine modules to be net newly installed LOOP AT it_modules_tbi INTO DATA(wa_module_tbi). IF ( wa_module_tbi-tla <> 'core' ) AND NOT line_exists( i_tree_controller->sdk_package_manager->mt_installed_modules[ tla = wa_module_tbi-tla ] ). lv_number_new_modules = lv_number_new_modules + 1. lv_number_modules_inst = lv_number_modules_inst - 1. ENDIF. IF ( wa_module_tbi-tla = 'core' ) AND ( NOT i_tree_controller->sdk_package_manager->is_core_installed( ) ). lv_number_new_modules = lv_number_new_modules + 1. lv_number_modules_inst = lv_number_modules_inst - 1. ENDIF. ENDLOOP. IF ( lv_number_modules_inst + lv_number_new_modules ) >= lv_number_modules_avail_inst. lv_text = |You have selected all { lv_number_modules_inst + lv_number_new_modules } modules available for installation. | && |Having all modules installed is discouraged and should only be done in demo systems. | && |Continue? | ##NO_TEXT. CALL FUNCTION 'POPUP_TO_CONFIRM' EXPORTING titlebar = ' ' diagnose_object = ' ' text_question = lv_text text_button_1 = |Do it anyway| icon_button_1 = ' ' text_button_2 = |Go back| icon_button_2 = ' ' default_button = '2' display_cancel_button = ' ' userdefined_f1_help = ' ' start_column = 25 start_row = 6 iv_quickinfo_button_1 = ' ' iv_quickinfo_button_2 = ' ' IMPORTING answer = lv_answer EXCEPTIONS text_not_found = 1 OTHERS = 2 ##NO_TEXT. IF sy-subrc <> 0. RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = |Could not find text for popup| ##NO_TEXT. ENDIF. IF lv_answer = 1. r_result = abap_true. ELSE. r_result = abap_false. RETURN. ENDIF. ENDIF. IF ( lv_number_new_modules > lif_ui_constants=>c_batch_rec_threshold OR lv_number_modules_inst > lif_ui_constants=>c_batch_rec_threshold ) AND ( i_salv_function = 'STRT' OR i_salv_function = 'EXE_FGND' OR i_salv_function = 'INS_FGND' ). lv_text = |You have selected { lv_number_new_modules + lv_number_modules_inst } modules for installation (or update). | & |This can take a while (using batch mode is recommended). | & |Continue with foreground mode? | ##NO_TEXT. CALL FUNCTION 'POPUP_TO_CONFIRM' EXPORTING titlebar = ' ' diagnose_object = ' ' text_question = lv_text text_button_1 = |Yes, please| icon_button_1 = ' ' text_button_2 = |Go back| icon_button_2 = ' ' default_button = '2' display_cancel_button = ' ' userdefined_f1_help = ' ' start_column = 25 start_row = 6 iv_quickinfo_button_1 = ' ' iv_quickinfo_button_2 = ' ' IMPORTING answer = lv_answer EXCEPTIONS text_not_found = 1 OTHERS = 2 ##NO_TEXT. IF sy-subrc <> 0. RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = |Could not find text for popup| ##NO_TEXT. ENDIF. IF lv_answer = 1. r_result = abap_true. ELSE. r_result = abap_false. ENDIF. ELSE. r_result = abap_true. ENDIF. RETURN. WHEN 'uninstall'. DATA(lv_number_modules_tbd) = lines( it_modules_tbd ). IF lv_number_modules_tbd > lif_ui_constants=>c_batch_rec_threshold AND ( i_salv_function = 'STRT' OR i_salv_function = 'EXE_FGND' OR i_salv_function = 'DEL_FGND' ). lv_text = |You have selected { lv_number_modules_tbd } modules for deletion. | && |This can take a while (using batch mode is recommended). | && |Continue in foreground mode? | ##NO_TEXT. CALL FUNCTION 'POPUP_TO_CONFIRM' EXPORTING titlebar = ' ' diagnose_object = ' ' text_question = lv_text text_button_1 = |Yes, please| icon_button_1 = ' ' text_button_2 = |Go back| icon_button_2 = ' ' default_button = '2' display_cancel_button = ' ' userdefined_f1_help = ' ' start_column = 25 start_row = 6 iv_quickinfo_button_1 = ' ' iv_quickinfo_button_2 = ' ' IMPORTING answer = lv_answer EXCEPTIONS text_not_found = 1 OTHERS = 2 ##NO_TEXT. IF sy-subrc <> 0. RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = |Could not find text for popup| ##NO_TEXT. ENDIF. IF lv_answer = 1. r_result = abap_true. ELSE. r_result = abap_false. ENDIF. ELSE. r_result = abap_true. ENDIF. RETURN. WHEN OTHERS. ENDCASE. ENDMETHOD. METHOD check_core_validity. DATA: lv_result TYPE abap_bool VALUE abap_false. CASE i_op. WHEN 'install'. IF i_tree_controller->sdk_package_manager->is_core_installed( ) = abap_false " core is NOT installed AND NOT line_exists( it_modules_tbi[ tla = 'core' ] ) " and NOT selected for installation AND lines( it_modules_tbi ) > 0. " are other modules selected for installation? MESSAGE |Please install core module with first deployment.| TYPE 'S' DISPLAY LIKE 'E' ##NO_TEXT. lv_result = abap_false. " then block the request ELSEIF i_tree_controller->sdk_package_manager->is_core_installed( ) = abap_true " core is installed AND line_exists( it_modules_tbd[ tla = 'core' ] ) " and marked for deletion AND ( lines( it_modules_tbd ) < lines( i_tree_controller->sdk_package_manager->mt_installed_modules ) - 3 " are any installed modules NOT selected for deletion? OR lines( it_modules_tbi ) > 0 ). " or did the user select additional modules for installation? MESSAGE |To delete core, additionally mark all installed modules for deletion.| TYPE 'S' DISPLAY LIKE 'E' ##NO_TEXT. lv_result = abap_false. " then block the request ELSE. lv_result = abap_true. ENDIF. WHEN 'uninstall'. IF i_tree_controller->sdk_package_manager->is_core_installed( ) = abap_true " core is installed AND line_exists( it_modules_tbd[ tla = 'core' ] ) " and marked for deletion AND ( lines( it_modules_tbd ) < lines( i_tree_controller->sdk_package_manager->mt_installed_modules ) - 3 " are any installed modules NOT selected for deletion? OR lines( it_modules_tbi ) > 0 ). " or did the user select additional modules for installation? MESSAGE |To delete core, additionally mark all installed modules for deletion.| TYPE 'S' DISPLAY LIKE 'E' ##NO_TEXT. lv_result = abap_false. " then block the request ELSE. lv_result = abap_true. ENDIF. ENDCASE. r_result = lv_result. ENDMETHOD. METHOD check_populated. DATA: lv_result TYPE abap_bool VALUE abap_false. CASE i_op. WHEN 'install'. IF lines( it_modules_tbi ) + lines( it_modules_tbd ) > 0. lv_result = abap_true. ELSE. MESSAGE |Nothing to do.| TYPE 'S' ##NO_TEXT. lv_result = abap_false. ENDIF. WHEN 'uninstall'. IF lines( it_modules_tbd ) > 0. lv_result = abap_true. ELSE. MESSAGE |Nothing to do.| TYPE 'S' ##NO_TEXT. lv_result = abap_false. ENDIF. ENDCASE. r_result = lv_result. ENDMETHOD. ENDCLASS. CLASS lcl_ui_utils DEFINITION FINAL. PUBLIC SECTION. CLASS-METHODS: get_running_jobs_message IMPORTING i_job_manager TYPE REF TO lif_sdk_job_manager RETURNING VALUE(r_message) TYPE string, display_job_submitted_message IMPORTING i_job_number TYPE btcjobcnt, confirm_install_all RETURNING VALUE(r_result) TYPE abap_bool RAISING lcx_error, display_job_details_statusbar IMPORTING i_job_manager TYPE REF TO lif_sdk_job_manager, is_fullscreen IMPORTING i_container TYPE REF TO cl_gui_container RETURNING VALUE(r_result) TYPE abap_bool, is_sapgui_html RETURNING VALUE(r_result) TYPE abap_bool, is_sapgui_timeout_sufficient RETURNING VALUE(r_result) TYPE abap_bool RAISING lcx_error. ENDCLASS. CLASS lcl_ui_utils IMPLEMENTATION. METHOD display_job_submitted_message. CONCATENATE `Submitted job with number ` i_job_number INTO DATA(job_message) ##NO_TEXT. MESSAGE i000(0k) WITH job_message. ENDMETHOD. METHOD get_running_jobs_message. DATA: lt_joblist TYPE tbtcjob_tt. lt_joblist = i_job_manager->get_running_jobs( i_jobname = sy-repid ). DATA wa_job TYPE tbtcjob. READ TABLE lt_joblist INTO wa_job INDEX 1. IF sy-subrc <> 0. MESSAGE |Expected to find exactly one job matching { sy-repid } but found { lines( lt_joblist ) }| TYPE 'I' DISPLAY LIKE 'E' ##NO_TEXT. ENDIF. DATA l_job_message TYPE string. CONCATENATE `Import background job currently running with number` wa_job-jobcount INTO r_message SEPARATED BY ' ' ##NO_TEXT. ENDMETHOD. METHOD confirm_install_all. DATA(lv_text) = |Installing all modules is discouraged and should only be done in demo systems. | && |Continue? | ##NO_TEXT. DATA: lv_answer TYPE string. CALL FUNCTION 'POPUP_TO_CONFIRM' EXPORTING titlebar = ' ' diagnose_object = ' ' text_question = lv_text text_button_1 = |Do it anyway| icon_button_1 = ' ' text_button_2 = |Go back| icon_button_2 = ' ' default_button = '2' display_cancel_button = ' ' userdefined_f1_help = ' ' start_column = 25 start_row = 6 iv_quickinfo_button_1 = ' ' iv_quickinfo_button_2 = ' ' IMPORTING answer = lv_answer EXCEPTIONS text_not_found = 1 OTHERS = 2 ##NO_TEXT. IF sy-subrc <> 0. RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = |Could not find text for popup| ##NO_TEXT. ENDIF. IF lv_answer = 1. r_result = abap_true. ELSE. r_result = abap_false. ENDIF. ENDMETHOD. METHOD display_job_details_statusbar. " Job already running? IF i_job_manager->is_job_running( ). MESSAGE get_running_jobs_message( i_job_manager = i_job_manager ) TYPE 'S' DISPLAY LIKE 'W'. ENDIF. ENDMETHOD. METHOD is_fullscreen. DATA lr_gui_container TYPE REF TO cl_gui_container. IF i_container IS NOT INITIAL. lr_gui_container = i_container. ELSE. lr_gui_container = CAST #( cl_gui_container=>screen0->children[ 1 ] ). ENDIF. IF lr_gui_container->get_name( ) = 'TREE_CONTAINER'. r_result = abap_true. ELSE. r_result = abap_false. ENDIF. ENDMETHOD. METHOD is_sapgui_html. DATA: lv_result TYPE abap_bool VALUE abap_false. CALL FUNCTION 'GUI_IS_ITS' IMPORTING return = lv_result. r_result = lv_result. ENDMETHOD. METHOD is_sapgui_timeout_sufficient. DATA: lv_gui_auto_timeout TYPE spfpflpar-pvalue VALUE '0'. DATA: lv_result TYPE abap_bool VALUE abap_false. CALL FUNCTION 'RSAN_SYSTEM_PARAMETER_READ' EXPORTING i_name = 'rdisp/gui_auto_logout' IMPORTING e_value = lv_gui_auto_timeout EXCEPTIONS read_error = 1 OTHERS = 2. IF sy-subrc <> 0. RAISE EXCEPTION TYPE lcx_error EXPORTING iv_msg = |Could not find text for popup| ##NO_TEXT. ENDIF. IF lv_gui_auto_timeout > lif_ui_constants=>c_sapgui_autologout_threshold. lv_result = abap_true. ENDIF. r_result = lv_result. ENDMETHOD. ENDCLASS. INTERFACE lif_ui_command. METHODS: execute IMPORTING i_tree_controller TYPE REF TO lcl_ui_tree_controller RAISING lcx_error, can_execute IMPORTING i_tree_controller TYPE REF TO lcl_ui_tree_controller RETURNING VALUE(r_result) TYPE abap_bool RAISING lcx_error. ENDINTERFACE. CLASS lcl_ui_command_base DEFINITION ABSTRACT. PUBLIC SECTION. INTERFACES: lif_ui_command. METHODS: constructor IMPORTING i_tree_controller TYPE REF TO lcl_ui_tree_controller. PROTECTED SECTION. DATA: tree_controller TYPE REF TO lcl_ui_tree_controller, target_version TYPE string. METHODS: get_target_version RETURNING VALUE(r_version) TYPE string. ENDCLASS. CLASS lcl_ui_command_base IMPLEMENTATION. METHOD constructor. tree_controller = i_tree_controller. ENDMETHOD. METHOD lif_ui_command~execute. " Do nothing in base case. ENDMETHOD. METHOD lif_ui_command~can_execute. r_result = abap_true. ENDMETHOD. METHOD get_target_version. " Return cached version if already determined IF target_version IS NOT INITIAL. r_version = target_version. RETURN. ENDIF. " we only use the same version as core (given it is installed at all) " if the installed version of core is NOT the latest version IF tree_controller->sdk_package_manager->is_core_installed( ) = abap_true. IF NOT tree_controller->sdk_package_manager->is_version_latest( tree_controller->sdk_package_manager->mt_installed_modules[ tla = 'sts' ]-cvers ). target_version = tree_controller->sdk_package_manager->mt_installed_modules[ tla = 'sts' ]-cvers. ELSE. target_version = 'LATEST'. ENDIF. ELSE. target_version = 'LATEST'. ENDIF. r_version = target_version. ENDMETHOD. ENDCLASS. CLASS lcl_ui_command_exe_dia DEFINITION INHERITING FROM lcl_ui_command_base FINAL. PUBLIC SECTION. METHODS: lif_ui_command~execute REDEFINITION, lif_ui_command~can_execute REDEFINITION. PROTECTED SECTION. METHODS: get_target_version REDEFINITION. ENDCLASS. CLASS lcl_ui_command_exe_dia IMPLEMENTATION. METHOD lif_ui_command~execute. tree_controller->sdk_package_manager->run_foreground( i_modules_to_be_installed = tree_controller->mt_modules_to_be_installed i_modules_to_be_deleted = tree_controller->mt_modules_to_be_deleted i_target_version = get_target_version( ) ). tree_controller->refresh( ). ENDMETHOD. METHOD lif_ui_command~can_execute. CLEAR: tree_controller->mt_modules_to_be_installed. CLEAR: tree_controller->mt_modules_to_be_deleted. CLEAR: tree_controller->mt_modules_to_be_updated. tree_controller->mt_modules_to_be_installed = tree_controller->get_modules_to_be_installed( i_target_version = get_target_version( ) ). tree_controller->mt_modules_to_be_deleted = tree_controller->get_modules_to_be_deleted( i_target_version = get_target_version( ) ). tree_controller->mt_modules_to_be_updated = tree_controller->get_modules_to_be_updated( i_target_version = get_target_version( ) ). INSERT LINES OF tree_controller->mt_modules_to_be_updated INTO TABLE tree_controller->mt_modules_to_be_installed. CHECK lcl_ui_selection_validator=>validate_selection( it_modules_tbi = tree_controller->mt_modules_to_be_installed it_modules_tbd = tree_controller->mt_modules_to_be_deleted i_salv_function = 'EXE_FGND' i_op = 'install' i_tree_controller = i_tree_controller ). CHECK lines( tree_controller->mt_modules_to_be_installed ) > 0 OR lines( tree_controller->mt_modules_to_be_deleted ) > 0 OR lines( tree_controller->mt_modules_to_be_updated ) > 0. CHECK tree_controller->sdk_package_manager->sdk_zipfiles->ensure_zipfiles_downloaded( i_version = get_target_version( ) ). CHECK tree_controller->sdk_package_manager->update_zipfiles_if_outdated( i_avers_core_inst = tree_controller->sdk_package_manager->mt_available_modules_inst[ tla = 'core' ]-avers i_avers_core_uninst = tree_controller->sdk_package_manager->mt_available_modules_uninst[ tla = 'core' ]-avers ). r_result = abap_true. ENDMETHOD. METHOD get_target_version. r_version = 'LATEST'. ENDMETHOD. ENDCLASS. CLASS lcl_ui_command_exe_btc DEFINITION INHERITING FROM lcl_ui_command_base FINAL. PUBLIC SECTION. METHODS: lif_ui_command~execute REDEFINITION, lif_ui_command~can_execute REDEFINITION. PROTECTED SECTION. METHODS: get_target_version REDEFINITION. ENDCLASS. CLASS lcl_ui_command_exe_btc IMPLEMENTATION. METHOD lif_ui_command~execute. DATA(job_manager) = tree_controller->sdk_package_manager->job_manager. DATA(job_number) = tree_controller->sdk_package_manager->job_manager->submit_batch_job( i_modules_to_be_installed = tree_controller->mt_modules_to_be_installed i_modules_to_be_deleted = tree_controller->mt_modules_to_be_deleted i_target_version = get_target_version( ) ). lcl_ui_utils=>display_job_submitted_message( i_job_number = job_number ). tree_controller->refresh( ). ENDMETHOD. METHOD lif_ui_command~can_execute. CLEAR: tree_controller->mt_modules_to_be_installed. CLEAR: tree_controller->mt_modules_to_be_deleted. CLEAR: tree_controller->mt_modules_to_be_updated. tree_controller->mt_modules_to_be_installed = tree_controller->get_modules_to_be_installed( i_target_version = get_target_version( ) ). tree_controller->mt_modules_to_be_deleted = tree_controller->get_modules_to_be_deleted( i_target_version = get_target_version( ) ). tree_controller->mt_modules_to_be_updated = tree_controller->get_modules_to_be_updated( i_target_version = get_target_version( ) ). INSERT LINES OF tree_controller->mt_modules_to_be_updated INTO TABLE tree_controller->mt_modules_to_be_installed. CHECK lcl_ui_selection_validator=>validate_selection( it_modules_tbi = tree_controller->mt_modules_to_be_installed it_modules_tbd = tree_controller->mt_modules_to_be_deleted i_salv_function = 'EXE_BGND' i_op = 'install' i_tree_controller = i_tree_controller ). CHECK lines( tree_controller->mt_modules_to_be_installed ) > 0 OR lines( tree_controller->mt_modules_to_be_deleted ) > 0 OR lines( tree_controller->mt_modules_to_be_updated ) > 0. CHECK tree_controller->sdk_package_manager->sdk_zipfiles->ensure_zipfiles_downloaded( i_version = get_target_version( ) ). CHECK tree_controller->sdk_package_manager->update_zipfiles_if_outdated( i_avers_core_inst = tree_controller->sdk_package_manager->mt_available_modules_inst[ tla = 'core' ]-avers i_avers_core_uninst = tree_controller->sdk_package_manager->mt_available_modules_uninst[ tla = 'core' ]-avers ). r_result = abap_true. ENDMETHOD. METHOD get_target_version. r_version = 'LATEST'. ENDMETHOD. ENDCLASS. CLASS lcl_ui_command_ins_dia DEFINITION INHERITING FROM lcl_ui_command_base FINAL. PUBLIC SECTION. METHODS: lif_ui_command~execute REDEFINITION, lif_ui_command~can_execute REDEFINITION. ENDCLASS. CLASS lcl_ui_command_ins_dia IMPLEMENTATION. METHOD lif_ui_command~execute. tree_controller->sdk_package_manager->run_foreground( i_modules_to_be_installed = tree_controller->mt_modules_to_be_installed i_modules_to_be_deleted = tree_controller->mt_modules_to_be_deleted i_target_version = get_target_version( ) ). " empty since modules tbd are not collected here tree_controller->refresh( ). ENDMETHOD. METHOD lif_ui_command~can_execute. CLEAR: tree_controller->mt_modules_to_be_installed. CLEAR: tree_controller->mt_modules_to_be_deleted. tree_controller->mt_modules_to_be_installed = tree_controller->get_modules_to_be_installed( i_target_version = get_target_version( ) ). CHECK lcl_ui_selection_validator=>validate_selection( it_modules_tbi = tree_controller->mt_modules_to_be_installed it_modules_tbd = tree_controller->mt_modules_to_be_deleted i_salv_function = 'INS_FGND' i_op = 'install' i_tree_controller = tree_controller ) = abap_false. CHECK lines( tree_controller->mt_modules_to_be_installed ) > 0. CHECK tree_controller->sdk_package_manager->sdk_zipfiles->ensure_zipfiles_downloaded( i_version = get_target_version( ) ). r_result = abap_true. ENDMETHOD. ENDCLASS. CLASS lcl_ui_command_ins_btc DEFINITION INHERITING FROM lcl_ui_command_base FINAL. PUBLIC SECTION. METHODS: lif_ui_command~execute REDEFINITION, lif_ui_command~can_execute REDEFINITION. ENDCLASS. CLASS lcl_ui_command_ins_btc IMPLEMENTATION. METHOD lif_ui_command~execute. DATA(job_manager) = tree_controller->sdk_package_manager->job_manager. DATA(job_number) = tree_controller->sdk_package_manager->job_manager->submit_batch_job( i_modules_to_be_installed = tree_controller->mt_modules_to_be_installed i_modules_to_be_deleted = tree_controller->mt_modules_to_be_deleted i_target_version = get_target_version( ) ). " empty since modules tbd are not collected here lcl_ui_utils=>display_job_submitted_message( i_job_number = job_number ). tree_controller->refresh( ). ENDMETHOD. METHOD lif_ui_command~can_execute. CLEAR: tree_controller->mt_modules_to_be_installed. CLEAR: tree_controller->mt_modules_to_be_deleted. tree_controller->mt_modules_to_be_installed = tree_controller->get_modules_to_be_installed( i_target_version = get_target_version( ) ). CHECK lcl_ui_selection_validator=>validate_selection( it_modules_tbi = tree_controller->mt_modules_to_be_installed it_modules_tbd = tree_controller->mt_modules_to_be_deleted i_salv_function = 'INS_BGND' i_op = 'install' i_tree_controller = tree_controller ) = abap_false. CHECK lines( tree_controller->mt_modules_to_be_installed ) > 0. CHECK tree_controller->sdk_package_manager->sdk_zipfiles->ensure_zipfiles_downloaded( i_version = get_target_version( ) ). r_result = abap_true. ENDMETHOD. ENDCLASS. CLASS lcl_ui_command_del_dia DEFINITION INHERITING FROM lcl_ui_command_base FINAL. PUBLIC SECTION. METHODS: lif_ui_command~execute REDEFINITION, lif_ui_command~can_execute REDEFINITION. ENDCLASS. CLASS lcl_ui_command_del_dia IMPLEMENTATION. METHOD lif_ui_command~execute. tree_controller->sdk_package_manager->run_foreground( i_modules_to_be_installed = tree_controller->mt_modules_to_be_installed " empty since modules tbi are not collected here i_modules_to_be_deleted = tree_controller->mt_modules_to_be_deleted i_target_version = get_target_version( ) ). tree_controller->refresh( ). ENDMETHOD. METHOD lif_ui_command~can_execute. CLEAR: tree_controller->mt_modules_to_be_installed. CLEAR: tree_controller->mt_modules_to_be_deleted. tree_controller->mt_modules_to_be_deleted = tree_controller->get_modules_to_be_deleted( i_target_version = get_target_version( ) ). CHECK lcl_ui_selection_validator=>validate_selection( it_modules_tbi = tree_controller->mt_modules_to_be_installed it_modules_tbd = tree_controller->mt_modules_to_be_deleted i_salv_function = 'DEL_FGND' i_op = 'uninstall' i_tree_controller = tree_controller ). CHECK lines( tree_controller->mt_modules_to_be_deleted ) > 0. CHECK tree_controller->sdk_package_manager->sdk_zipfiles->ensure_zipfiles_downloaded( i_version = get_target_version( ) ). r_result = abap_true. ENDMETHOD. ENDCLASS. CLASS lcl_ui_command_del_btc DEFINITION INHERITING FROM lcl_ui_command_base FINAL. PUBLIC SECTION. METHODS: lif_ui_command~execute REDEFINITION, lif_ui_command~can_execute REDEFINITION. ENDCLASS. CLASS lcl_ui_command_del_btc IMPLEMENTATION. METHOD lif_ui_command~execute. DATA(job_manager) = tree_controller->sdk_package_manager->job_manager. DATA(job_number) = job_manager->submit_batch_job( i_modules_to_be_installed = tree_controller->mt_modules_to_be_installed " empty since modules tbi are not collected here i_modules_to_be_deleted = tree_controller->mt_modules_to_be_deleted i_target_version = get_target_version( ) ). lcl_ui_utils=>display_job_submitted_message( i_job_number = job_number ). tree_controller->refresh( ). ENDMETHOD. METHOD lif_ui_command~can_execute. CLEAR: tree_controller->mt_modules_to_be_installed. CLEAR: tree_controller->mt_modules_to_be_deleted. tree_controller->mt_modules_to_be_deleted = tree_controller->get_modules_to_be_deleted( i_target_version = get_target_version( ) ). CHECK lcl_ui_selection_validator=>validate_selection( it_modules_tbi = tree_controller->mt_modules_to_be_installed it_modules_tbd = tree_controller->mt_modules_to_be_deleted i_salv_function = 'DEL_BGND' i_op = 'uninstall' i_tree_controller = tree_controller ). CHECK lines( tree_controller->mt_modules_to_be_deleted ) > 0. CHECK tree_controller->sdk_package_manager->sdk_zipfiles->ensure_zipfiles_downloaded( i_version = get_target_version( ) ). r_result = abap_true. ENDMETHOD. ENDCLASS. CLASS lcl_ui_command_ref_ctl DEFINITION INHERITING FROM lcl_ui_command_base FINAL. PUBLIC SECTION. METHODS: lif_ui_command~execute REDEFINITION, lif_ui_command~can_execute REDEFINITION. ENDCLASS. CLASS lcl_ui_command_ref_ctl IMPLEMENTATION. METHOD lif_ui_command~execute. tree_controller->refresh( ). ENDMETHOD. METHOD lif_ui_command~can_execute. r_result = super->lif_ui_command~can_execute( i_tree_controller = i_tree_controller ). ENDMETHOD. ENDCLASS. CLASS lcl_ui_command_btc_dtl DEFINITION INHERITING FROM lcl_ui_command_base FINAL. PUBLIC SECTION. METHODS: lif_ui_command~execute REDEFINITION, lif_ui_command~can_execute REDEFINITION. ENDCLASS. CLASS lcl_ui_command_btc_dtl IMPLEMENTATION. METHOD lif_ui_command~execute. MESSAGE lcl_ui_utils=>get_running_jobs_message( i_job_manager = i_tree_controller->sdk_package_manager->job_manager ) TYPE 'I'. ENDMETHOD. METHOD lif_ui_command~can_execute. IF tree_controller->sdk_package_manager->job_manager->is_job_running( ). r_result = abap_true. ELSE. MESSAGE 'No background job currently running.' TYPE 'I' ##NO_TEXT. ENDIF. ENDMETHOD. ENDCLASS. CLASS lcl_ui_command_upd_ins DEFINITION INHERITING FROM lcl_ui_command_base FINAL. PUBLIC SECTION. METHODS: lif_ui_command~execute REDEFINITION, lif_ui_command~can_execute REDEFINITION. ENDCLASS. CLASS lcl_ui_command_upd_ins IMPLEMENTATION. METHOD lif_ui_command~execute. i_tree_controller->toggle_inst_modules( i_checked = abap_true ). ENDMETHOD. METHOD lif_ui_command~can_execute. r_result = super->lif_ui_command~can_execute( i_tree_controller = i_tree_controller ). ENDMETHOD. ENDCLASS. CLASS lcl_ui_command_des_ins DEFINITION INHERITING FROM lcl_ui_command_base FINAL. PUBLIC SECTION. METHODS: lif_ui_command~execute REDEFINITION, lif_ui_command~can_execute REDEFINITION. ENDCLASS. CLASS lcl_ui_command_des_ins IMPLEMENTATION. METHOD lif_ui_command~execute. i_tree_controller->toggle_inst_modules( i_checked = abap_false ). ENDMETHOD. METHOD lif_ui_command~can_execute. r_result = super->lif_ui_command~can_execute( i_tree_controller = i_tree_controller ). ENDMETHOD. ENDCLASS. CLASS lcl_ui_command_ins_all DEFINITION INHERITING FROM lcl_ui_command_base FINAL. PUBLIC SECTION. METHODS: lif_ui_command~execute REDEFINITION, lif_ui_command~can_execute REDEFINITION. ENDCLASS. CLASS lcl_ui_command_ins_all IMPLEMENTATION. METHOD lif_ui_command~execute. DATA(job_number) = i_tree_controller->sdk_package_manager->install_all_modules( it_modules_to_be_installed = i_tree_controller->mt_modules_to_be_installed it_modules_to_be_deleted = i_tree_controller->mt_modules_to_be_deleted ). lcl_ui_utils=>display_job_submitted_message( i_job_number = job_number ). i_tree_controller->refresh( ). ENDMETHOD. METHOD lif_ui_command~can_execute. r_result = lcl_ui_utils=>confirm_install_all( ). ENDMETHOD. ENDCLASS. CLASS lcl_ui_command_dow_crt DEFINITION INHERITING FROM lcl_ui_command_base FINAL. PUBLIC SECTION. METHODS: lif_ui_command~execute REDEFINITION, lif_ui_command~can_execute REDEFINITION. ENDCLASS. CLASS lcl_ui_command_dow_crt IMPLEMENTATION. METHOD lif_ui_command~execute. i_tree_controller->sdk_package_manager->certificate_manager->install_amazon_root_certs( ). ENDMETHOD. METHOD lif_ui_command~can_execute. r_result = i_tree_controller->sdk_package_manager->internet_manager->has_internet_access( ). ENDMETHOD. ENDCLASS. CLASS lcl_ui_command_dow_trk DEFINITION INHERITING FROM lcl_ui_command_base FINAL. PUBLIC SECTION. METHODS: lif_ui_command~execute REDEFINITION, lif_ui_command~can_execute REDEFINITION. ENDCLASS. CLASS lcl_ui_command_dow_trk IMPLEMENTATION. METHOD lif_ui_command~execute. i_tree_controller->sdk_package_manager->sdk_zipfiles->download_zipfile_pair( i_version = 'LATEST' ). ENDMETHOD. METHOD lif_ui_command~can_execute. r_result = i_tree_controller->sdk_package_manager->internet_manager->has_internet_access( ). ENDMETHOD. ENDCLASS. CLASS lcl_ui_command_factory DEFINITION FINAL. PUBLIC SECTION. CLASS-METHODS: create_command IMPORTING i_function_code TYPE syst_ucomm i_tree_controller TYPE REF TO lcl_ui_tree_controller RETURNING VALUE(r_command) TYPE REF TO lif_ui_command RAISING lcx_error. ENDCLASS. CLASS lcl_ui_command_factory IMPLEMENTATION. METHOD create_command. CASE i_function_code. WHEN 'STRT' OR 'EXE_FGND'. r_command = NEW lcl_ui_command_exe_dia( i_tree_controller = i_tree_controller ). WHEN 'BTCH' OR 'EXE_BGND'. r_command = NEW lcl_ui_command_exe_btc( i_tree_controller = i_tree_controller ). WHEN 'INS_FGND'. r_command = NEW lcl_ui_command_ins_dia( i_tree_controller = i_tree_controller ). WHEN 'INS_BGND'. r_command = NEW lcl_ui_command_ins_btc( i_tree_controller = i_tree_controller ). WHEN 'DEL_FGND'. r_command = NEW lcl_ui_command_del_dia( i_tree_controller = i_tree_controller ). WHEN 'DEL_BGND'. r_command = NEW lcl_ui_command_del_btc( i_tree_controller = i_tree_controller ). WHEN 'UPD_INST'. r_command = NEW lcl_ui_command_upd_ins( i_tree_controller = i_tree_controller ). WHEN 'DES_INST'. r_command = NEW lcl_ui_command_des_ins( i_tree_controller = i_tree_controller ). WHEN 'REF_TREE'. r_command = NEW lcl_ui_command_ref_ctl( i_tree_controller = i_tree_controller ). WHEN 'BTC_DTLS'. r_command = NEW lcl_ui_command_btc_dtl( i_tree_controller = i_tree_controller ). WHEN 'DOW_CERT'. r_command = NEW lcl_ui_command_dow_crt( i_tree_controller = i_tree_controller ). WHEN 'DOW_TRAK'. r_command = NEW lcl_ui_command_dow_trk( i_tree_controller = i_tree_controller ). WHEN 'INS_ALL'. r_command = NEW lcl_ui_command_ins_all( i_tree_controller = i_tree_controller ). WHEN OTHERS. ENDCASE. ENDMETHOD. ENDCLASS. CLASS lcl_ui_tree_controller IMPLEMENTATION. METHOD constructor. IF i_sdk_package_manager IS BOUND. sdk_package_manager = i_sdk_package_manager. ELSE. sdk_package_manager = NEW lcl_sdk_package_manager( ). ENDIF. "mt_installed_modules = sdk_package_manager->get_sdk_installed_modules( ). " "mt_available_modules_inst = sdk_package_manager->get_sdk_avail_modules_json( i_operation = 'install' " i_source = 'web' " i_version = 'LATEST' ). "mt_available_modules_uninst = sdk_package_manager->get_sdk_avail_modules_json( i_operation = 'uninstall' " i_source = 'web' " i_version = 'LATEST' ). SELECT tla FROM @sdk_package_manager->mt_available_modules_inst AS am WHERE is_popular = 'X' INTO TABLE @mt_popular_modules . " re-hydrate the module staging area if report is restarted IMPORT st_modules_to_be_installed = mt_modules_to_be_installed FROM SHARED BUFFER indx(mi) ID 'MOD_INST'. IMPORT st_modules_to_be_deleted = mt_modules_to_be_deleted FROM SHARED BUFFER indx(md) ID 'MOD_DELE'. IF m_fullscreen = abap_false. create_container( ). ELSE. create_fullscreen( ). ENDIF. ENDMETHOD. METHOD draw_tree. draw_header( ). draw_footer( ). draw_columns( ). draw_nodes( ). set_settings( ). set_functions( ). set_handlers( ). mr_tree->display( ). ENDMETHOD. METHOD draw_columns. DATA: lr_columns TYPE REF TO cl_salv_columns_tree, lr_column TYPE REF TO cl_salv_column_tree. lr_columns = mr_tree->get_columns( ). lr_columns->set_optimize( abap_true ). TRY. lr_column ?= lr_columns->get_column( 'TLA' ). lr_column->set_long_text( 'TLA' ). lr_column->set_medium_text( 'TLA' ). lr_column->set_short_text( 'TLA' ). lr_column->set_alignment( if_salv_c_alignment=>centered ). lr_column->set_visible( abap_false ). CLEAR lr_column. lr_column ?= lr_columns->get_column( 'NAME' ). lr_column->set_long_text( 'Module name' ) ##NO_TEXT. lr_column->set_medium_text( 'Mod. name' ) ##NO_TEXT. lr_column->set_short_text( 'Name' ) ##NO_TEXT. CLEAR lr_column. lr_column ?= lr_columns->get_column( 'CVERS' ). lr_column->set_long_text( 'Installed version' ) ##NO_TEXT. lr_column->set_medium_text( 'Inst. version' ) ##NO_TEXT. lr_column->set_short_text( 'Ins. vers.' ) ##NO_TEXT. lr_column->set_alignment( if_salv_c_alignment=>centered ). CLEAR lr_column. lr_column ?= lr_columns->get_column( 'CTRANSPORT' ). lr_column->set_long_text( 'Installed Transport ID' ) ##NO_TEXT. lr_column->set_medium_text( 'Inst. Transport ID' ) ##NO_TEXT. lr_column->set_short_text( 'Ins. TID' ) ##NO_TEXT. lr_column->set_alignment( if_salv_c_alignment=>centered ). CLEAR lr_column. lr_column ?= lr_columns->get_column( 'TP_RC' ). lr_column->set_long_text( 'Last TP Returncode' ) ##NO_TEXT. lr_column->set_medium_text( 'Last TP RC' ) ##NO_TEXT. lr_column->set_short_text( 'TP RC' ) ##NO_TEXT. lr_column->set_alignment( if_salv_c_alignment=>centered ). CLEAR lr_column. lr_column ?= lr_columns->get_column( 'TP_ICON' ). lr_column->set_long_text( '' ). lr_column->set_medium_text( '' ). lr_column->set_short_text( '' ). lr_column->set_icon( abap_true ). lr_column->set_alignment( if_salv_c_alignment=>left ). CLEAR lr_column. lr_column ?= lr_columns->get_column( 'TP_TEXT' ). lr_column->set_long_text( 'Last tp status message' ). lr_column->set_medium_text( 'Last tp status msg.' ). lr_column->set_short_text( 'Last msg' ). lr_column->set_alignment( if_salv_c_alignment=>left ). CLEAR lr_column. lr_column ?= lr_columns->get_column( 'AVERS' ). lr_column->set_long_text( 'Currently available version' ) ##NO_TEXT. lr_column->set_medium_text( 'Available version' ) ##NO_TEXT. lr_column->set_short_text( 'Avl. vers.' ) ##NO_TEXT. lr_column->set_alignment( if_salv_c_alignment=>centered ). CLEAR lr_column. lr_column ?= lr_columns->get_column( 'ATRANSPORT' ). lr_column->set_long_text( 'Avail Transport ID' ) ##NO_TEXT. lr_column->set_medium_text( 'Avail. Transport ID' ) ##NO_TEXT. lr_column->set_short_text( 'Avail. TID' ) ##NO_TEXT. lr_column->set_alignment( if_salv_c_alignment=>centered ). CLEAR lr_column. lr_column ?= lr_columns->get_column( 'IS_CORE' ). lr_column->set_long_text( 'Is core transport?' ) ##NO_TEXT. lr_column->set_medium_text( 'Is core ?' ) ##NO_TEXT. lr_column->set_short_text( 'Core?' ) ##NO_TEXT. lr_column->set_alignment( if_salv_c_alignment=>centered ). lr_column->set_technical( abap_true ). CLEAR lr_column. lr_column ?= lr_columns->get_column( 'IS_POPULAR' ). lr_column->set_long_text( 'Is popular module?' ) ##NO_TEXT. lr_column->set_medium_text( 'Is popular?' ) ##NO_TEXT. lr_column->set_short_text( 'Popular?' ) ##NO_TEXT. lr_column->set_alignment( if_salv_c_alignment=>centered ). lr_column->set_technical( abap_true ). CLEAR lr_column. lr_column ?= lr_columns->get_column( 'OP_ICON' ). lr_column->set_long_text( '' ). lr_column->set_medium_text( '' ). lr_column->set_short_text( '' ). lr_column->set_icon( abap_true ). lr_column->set_alignment( if_salv_c_alignment=>centered ). CLEAR lr_column. lr_column ?= lr_columns->get_column( 'OP_TEXT' ). lr_column->set_long_text( 'Planned Operation' ) ##NO_TEXT. lr_column->set_medium_text( 'Planned Op.' ) ##NO_TEXT. lr_column->set_short_text( 'Operation' ) ##NO_TEXT. lr_column->set_alignment( if_salv_c_alignment=>left ). CLEAR lr_column. lr_column ?= lr_columns->get_column( 'OP_CODE' ). lr_column->set_long_text( 'Operation code' ) ##NO_TEXT. lr_column->set_medium_text( 'Operation code' ) ##NO_TEXT. lr_column->set_short_text( 'Op. code' ) ##NO_TEXT. lr_column->set_alignment( if_salv_c_alignment=>left ). lr_column->set_technical( abap_true ). CLEAR lr_column. CATCH cx_salv_not_found. ENDTRY. ENDMETHOD. METHOD draw_nodes. CLEAR mt_folder_node_keys. draw_node_sdk_core( ). draw_node_installed_modules( ). draw_node_available_modules( ). ENDMETHOD. METHOD draw_node_sdk_core. DATA: lr_nodes TYPE REF TO cl_salv_nodes, lr_node TYPE REF TO cl_salv_node, lr_item TYPE REF TO cl_salv_item, l_text TYPE lvc_value, lr_key TYPE salv_de_node_key. lr_nodes = mr_tree->get_nodes( ). * --- ABAP SDK Core folder TRY. lr_nodes->add_node( EXPORTING related_node = space relationship = cl_gui_column_tree=>relat_last_child text = 'ABAP SDK Core (1)' folder = abap_true expander = abap_true RECEIVING node = lr_node ) ##NO_TEXT. CATCH cx_salv_msg. ENDTRY. IF m_sdk_core_expanded = abap_true. TRY. lr_node->expand( ). CATCH cx_salv_msg. ENDTRY. ENDIF. lr_key = lr_node->get_key( ). save_node_key( ir_node_name = |sdk| ir_node_key = lr_key ). DATA wa_core_module TYPE ts_sdk_module. READ TABLE sdk_package_manager->mt_installed_modules WITH KEY tla = 'sts' INTO wa_core_module. " core module installed? IF sy-subrc <> 0. ENDIF. wa_core_module-tla = 'core'. wa_core_module-name = 'AWS SDK for SAP ABAP core [s3, smr, rla, sts]' ##NO_TEXT. wa_core_module-avers = sdk_package_manager->mt_available_modules_inst[ tla = 'core' ]-avers. wa_core_module-atransport = sdk_package_manager->mt_available_modules_inst[ tla = 'core' ]-atransport. IF wa_core_module-cvers IS NOT INITIAL. IF lcl_sdk_utils=>cmp_version_string( i_string1 = sdk_package_manager->mt_available_modules_inst[ tla = 'core' ]-avers i_string2 = wa_core_module-cvers ) = 0. wa_core_module-op_icon = '@08@'. wa_core_module-op_text = 'Module up to date, no operation planned.' ##NO_TEXT. wa_core_module-op_code = lif_ui_constants=>c_operation_none. ELSEIF lcl_sdk_utils=>cmp_version_string( i_string1 = sdk_package_manager->mt_available_modules_inst[ tla = 'core' ]-avers i_string2 = wa_core_module-cvers ) = 1. wa_core_module-op_icon = '@09@'. wa_core_module-op_text = 'Module will be updated.' ##NO_TEXT. wa_core_module-op_code = lif_ui_constants=>c_operation_update. ELSE. wa_core_module-op_icon = '@0A@'. wa_core_module-op_text = 'Current version higher than available version. Module may be deprecated.' ##NO_TEXT. wa_core_module-op_code = lif_ui_constants=>c_operation_none. ENDIF. ELSE. wa_core_module-op_text = 'Will NOT be installed.' ##NO_TEXT. wa_core_module-op_code = lif_ui_constants=>c_operation_none. wa_core_module-op_icon = '@EB@'. ENDIF. " Draw processing status when bg job is running IF line_exists( mt_modules_to_be_installed[ tla = 'core' ] ) OR line_exists( mt_modules_to_be_deleted[ tla = 'core' ] ). wa_core_module-tp_icon = '@4A@'. wa_core_module-tp_text = 'Processing...' ##NO_TEXT. wa_core_module-tp_rc = '8888' ##NO_TEXT. wa_core_module-op_icon = '@62@'. " is_core_installed( ) does not always work here as not all 4 core modules might " be fully present yet during an installation run IF sdk_package_manager->is_core_installed( ) = abap_false OR wa_core_module-cvers IS NOT INITIAL AND line_exists( mt_modules_to_be_installed[ tla = 'core' ] ). wa_core_module-op_text = 'Installation operation in progress.' ##NO_TEXT. ELSEIF sdk_package_manager->is_core_installed( ) = abap_true OR wa_core_module-cvers IS INITIAL AND line_exists( mt_modules_to_be_deleted[ tla = 'core' ] ). wa_core_module-op_text = 'Delete operation in progress.' ##NO_TEXT. ELSE. " Do nothing ENDIF. ENDIF. TRY. lr_nodes->add_node( EXPORTING related_node = lr_key relationship = cl_gui_column_tree=>relat_last_child data_row = wa_core_module text = 'core' RECEIVING node = lr_node ). CATCH cx_salv_msg. ENDTRY. lr_node->set_collapsed_icon( '@X1@' ). " Changes the doc icon of leaf nodes lr_item = lr_node->get_hierarchy_item( ). lr_item->set_type( if_salv_c_item_type=>checkbox ). lr_item->set_editable( abap_true ). * IF is_core_installed( ) = abap_true * AND lines( mt_installed_modules ) > 4. "sts, s3, smr, rla * lr_item->set_checked( abap_true ). * lr_item->set_editable( abap_false ). * ELSEIF is_core_installed( ) = abap_true * AND lines( mt_installed_modules ) = 4. " core is the only module left * lr_item->set_checked( abap_true ). * lr_item->set_editable( abap_true ). * ELSE. " < 4 modules installed, maybe faulty installation, make checkbox editable for import * lr_item->set_checked( abap_false ). * lr_item->set_editable( abap_true ). * ENDIF. IF sdk_package_manager->is_core_installed( ) = abap_true " core installed and should be updated AND line_exists( mt_modules_to_be_installed[ tla = 'core' ] ). lr_item->set_checked( abap_true ). ELSEIF sdk_package_manager->is_core_installed( ) = abap_true " core installed and should be deleted AND line_exists( mt_modules_to_be_deleted[ tla = 'core' ] ). lr_item->set_checked( abap_false ). ELSEIF sdk_package_manager->is_core_installed( ) = abap_true " core installed and should NOT be updated AND NOT line_exists( mt_modules_to_be_installed[ tla = 'core' ] ). lr_item->set_checked( abap_true ). ELSEIF NOT sdk_package_manager->is_core_installed( ) = abap_true " core NOT installed and should be installed AND line_exists( mt_modules_to_be_installed[ tla = 'core' ] ). lr_item->set_checked( abap_true ). ELSE. " Do nothing ENDIF. IF sdk_package_manager->job_manager->is_job_running( ). lr_item->set_editable( abap_false ). ENDIF. ENDMETHOD. METHOD draw_node_installed_modules. DATA: lr_nodes TYPE REF TO cl_salv_nodes, lr_node TYPE REF TO cl_salv_node, lr_item TYPE REF TO cl_salv_item, l_text TYPE lvc_value, lr_key TYPE salv_de_node_key. lr_nodes = mr_tree->get_nodes( ). " TODO: returning the no of modules (installed, available) should go into a dedicated function. DATA(l_inst_mod_no) = lines( sdk_package_manager->mt_installed_modules ). IF l_inst_mod_no >= 4. l_inst_mod_no = l_inst_mod_no - 3. ENDIF. DATA(l_installed_modules_text) = 'Installed ABAP SDK Modules (' && l_inst_mod_no && ')' ##NO_TEXT. DATA(l_installed_modules_lvc) = CONV lvc_value( l_installed_modules_text ). TRY. lr_nodes->add_node( EXPORTING related_node = space relationship = cl_gui_column_tree=>relat_last_child text = l_installed_modules_lvc folder = abap_true expander = abap_true RECEIVING node = lr_node ). CATCH cx_salv_msg. ENDTRY. IF lines( sdk_package_manager->mt_installed_modules ) > 0. TRY. lr_node->expand( ). CATCH cx_salv_msg. ENDTRY. ELSE. TRY. lr_node->collapse( ). CATCH cx_salv_msg. ENDTRY. ENDIF. lr_key = lr_node->get_key( ). save_node_key( ir_node_name = |installed_modules| ir_node_key = lr_key ). SORT sdk_package_manager->mt_installed_modules BY tla. DATA wa_installed_module TYPE ts_sdk_module. LOOP AT sdk_package_manager->mt_installed_modules INTO wa_installed_module. " Skip modules that are part of AWS_CORE IF sdk_package_manager->is_module_core( wa_installed_module-tla ). CONTINUE. ELSE. wa_installed_module-avers = VALUE #( sdk_package_manager->mt_available_modules_inst[ tla = wa_installed_module-tla ]-avers DEFAULT 'n.a.' ). wa_installed_module-atransport = VALUE #( sdk_package_manager->mt_available_modules_inst[ tla = wa_installed_module-tla ]-atransport DEFAULT 'n.a.' ). l_text = wa_installed_module-tla. IF lcl_sdk_utils=>cmp_version_string( i_string1 = wa_installed_module-avers i_string2 = wa_installed_module-cvers ) = 0. wa_installed_module-op_icon = '@08@'. wa_installed_module-op_text = 'Module up to date, no operation planned.' ##NO_TEXT. wa_installed_module-op_code = lif_ui_constants=>c_operation_none. ELSEIF lcl_sdk_utils=>cmp_version_string( i_string1 = wa_installed_module-avers i_string2 = wa_installed_module-cvers ) = 1. wa_installed_module-op_icon = '@09@'. wa_installed_module-op_text = 'Module will be updated.' ##NO_TEXT. wa_installed_module-op_code = lif_ui_constants=>c_operation_update. ELSE. wa_installed_module-op_icon = '@0A@'. wa_installed_module-op_text = 'Current version higher than available version. Module may be deprecated.' ##NO_TEXT. wa_installed_module-op_code = lif_ui_constants=>c_operation_none. ENDIF. IF line_exists( mt_modules_to_be_installed[ tla = wa_installed_module-tla ] ) OR line_exists( mt_modules_to_be_deleted[ tla = wa_installed_module-tla ] ). wa_installed_module-tp_icon = '@4A@'. wa_installed_module-tp_text = 'Processing...' ##NO_TEXT. wa_installed_module-tp_rc = '8888' ##NO_TEXT. wa_installed_module-op_icon = '@62@'. IF line_exists( mt_modules_to_be_installed[ tla = wa_installed_module-tla ] ). wa_installed_module-op_text = 'Installation operation in progress.' ##NO_TEXT. ELSE. wa_installed_module-op_text = 'Delete operation in progress.' ##NO_TEXT. ENDIF. ENDIF. TRY. lr_nodes->add_node( EXPORTING related_node = lr_key relationship = cl_gui_column_tree=>relat_last_child data_row = wa_installed_module text = l_text RECEIVING node = lr_node ). CATCH cx_salv_msg. ENDTRY. lr_node->set_collapsed_icon( '@X1@' ). " Changes the doc icon of leaf nodes lr_item = lr_node->get_hierarchy_item( ). lr_item->set_type( if_salv_c_item_type=>checkbox ). IF line_exists( mt_modules_to_be_deleted[ tla = wa_installed_module-tla ] ). lr_item->set_checked( abap_false ). ELSE. lr_item->set_checked( abap_true ). ENDIF. IF sdk_package_manager->job_manager->is_job_running( ). lr_item->set_editable( abap_false ). ELSE. lr_item->set_editable( abap_true ). ENDIF. ENDIF. ENDLOOP. ENDMETHOD. METHOD draw_node_available_modules. DATA: lr_nodes TYPE REF TO cl_salv_nodes, lr_node TYPE REF TO cl_salv_node, lr_item TYPE REF TO cl_salv_item, l_text TYPE lvc_value, lr_key TYPE salv_de_node_key, lr_popular_mod_key TYPE salv_de_node_key, lr_other_mod_key TYPE salv_de_node_key, lr_popular_mod_node TYPE REF TO cl_salv_node, lr_other_mod_node TYPE REF TO cl_salv_node. lr_nodes = mr_tree->get_nodes( ). DATA(l_inst_mod_no) = lines( sdk_package_manager->mt_installed_modules ). IF l_inst_mod_no >= 4. l_inst_mod_no = l_inst_mod_no - 3. ENDIF. DATA(l_inst_deprecated_mod_ins_no) = lines( sdk_package_manager->get_sdk_deprecated_mod_inst( ) ). DATA(l_avail_modules_no) = lines( sdk_package_manager->mt_available_modules_inst ) - ( l_inst_mod_no - l_inst_deprecated_mod_ins_no ). IF lines( sdk_package_manager->mt_installed_modules ) = 0. l_avail_modules_no = l_avail_modules_no - 4. ENDIF. "------ Available Modules parent folder DATA(l_avail_modules_text) = 'Available ABAP SDK Modules (' && l_avail_modules_no && ')' ##NO_TEXT. DATA(l_avail_modules_lvc) = CONV lvc_value( l_avail_modules_text ). TRY. lr_nodes->add_node( EXPORTING related_node = space relationship = cl_gui_column_tree=>relat_last_child text = l_avail_modules_lvc folder = abap_true expander = abap_true RECEIVING node = lr_node ). CATCH cx_salv_msg. ENDTRY. IF m_available_modules_expanded = abap_true. TRY. lr_node->expand( ). CATCH cx_salv_msg. ENDTRY. ENDIF. lr_key = lr_node->get_key( ). save_node_key( ir_node_name = |available_modules| ir_node_key = lr_key ) ##NO_TEXT. "------ Available Modules subfolder Popular Modules DATA(l_popular_modules_no) = lines( mt_popular_modules ) - lines( FILTER #( sdk_package_manager->mt_installed_modules IN mt_popular_modules WHERE tla = tla ) ). DATA(l_popular_modules_text) = 'Popular Modules (' && l_popular_modules_no && ')' ##NO_TEXT. DATA(l_popular_modules_lvc) = CONV lvc_value( l_popular_modules_text ). TRY. lr_nodes->add_node( EXPORTING related_node = lr_key relationship = cl_gui_column_tree=>relat_last_child text = l_popular_modules_lvc folder = abap_true expander = abap_true RECEIVING node = lr_popular_mod_node ). CATCH cx_salv_msg. ENDTRY. IF m_available_modules_expanded = abap_true. TRY. lr_popular_mod_node->expand( ). CATCH cx_salv_msg. ENDTRY. ENDIF. lr_popular_mod_key = lr_popular_mod_node->get_key( ). "------ Available Modules subfolder Other Modules DATA(l_other_modules_no) = l_avail_modules_no - l_popular_modules_no. DATA(l_other_modules_text) = 'Other Modules (' && l_other_modules_no && ')' ##NO_TEXT. DATA(l_other_modules_lvc) = CONV lvc_value( l_other_modules_text ). TRY. lr_nodes->add_node( EXPORTING related_node = lr_key relationship = cl_gui_column_tree=>relat_last_child text = l_other_modules_lvc folder = abap_true expander = abap_true RECEIVING node = lr_other_mod_node ). CATCH cx_salv_msg. ENDTRY. lr_other_mod_key = lr_other_mod_node->get_key( ). "------ Module list compilation SORT sdk_package_manager->mt_available_modules_inst BY tla. DATA wa_installed_module TYPE ts_sdk_module. LOOP AT sdk_package_manager->mt_available_modules_inst ASSIGNING FIELD-SYMBOL(). CLEAR: lr_node. IF -tla = 'core'. CONTINUE. ELSE. CLEAR wa_installed_module. READ TABLE sdk_package_manager->mt_installed_modules WITH KEY tla = -tla INTO wa_installed_module. IF sy-subrc = 0. CONTINUE. " Module is already installed, skipping... ELSE. l_text = -tla. -op_text = 'Will NOT be installed.' ##NO_TEXT. -op_code = lif_ui_constants=>c_operation_none. -op_icon = '@EB@'. " Draw processing status when bg job is running IF line_exists( mt_modules_to_be_installed[ tla = -tla ] ) OR line_exists( mt_modules_to_be_deleted[ tla = -tla ] ). -tp_icon = '@4A@'. -tp_text = 'Processing...' ##NO_TEXT. -tp_rc = '8888' ##NO_TEXT. -op_icon = '@62@'. IF line_exists( mt_modules_to_be_installed[ tla = -tla ] ). -op_text = 'Installation operation in progress.' ##NO_TEXT. ELSEIF line_exists( mt_modules_to_be_deleted[ tla = -tla ] ). -op_text = 'Delete operation in progress.' ##NO_TEXT. ELSE. " Do nothing ENDIF. ENDIF. TRY. IF line_exists( mt_popular_modules[ tla = l_text ] ). lr_nodes->add_node( EXPORTING related_node = lr_popular_mod_key relationship = cl_gui_column_tree=>relat_last_child data_row = text = l_text RECEIVING node = lr_node ). ELSE. lr_nodes->add_node( EXPORTING related_node = lr_other_mod_key relationship = cl_gui_column_tree=>relat_last_child data_row = text = l_text RECEIVING node = lr_node ). ENDIF. CATCH cx_salv_msg. ENDTRY. lr_node->set_collapsed_icon( '@X1@' ). " Changes the doc icon of leaf nodes lr_item = lr_node->get_hierarchy_item( ). lr_item->set_type( if_salv_c_item_type=>checkbox ). IF line_exists( mt_modules_to_be_installed[ tla = -tla ] ). lr_item->set_checked( abap_true ). ELSE. lr_item->set_checked( abap_false ). ENDIF. lr_item->set_editable( abap_true ). * IF is_core_installed( ) = abap_true. * * lr_item->set_editable( abap_true ). * * ELSE. * * lr_item->set_editable( abap_false ). * * ENDIF. ENDIF. ENDIF. IF sdk_package_manager->job_manager->is_job_running( ). lr_item->set_editable( abap_false ). ENDIF. ENDLOOP. ENDMETHOD. METHOD save_node_key. DATA wa_folder_node_key TYPE ts_named_salv_node_key. wa_folder_node_key-node_name = ir_node_name. wa_folder_node_key-key = ir_node_key. APPEND wa_folder_node_key TO mt_folder_node_keys. ENDMETHOD. " Draw header with warning if an import job is currently running in the background METHOD draw_header. " Job already running? IF sdk_package_manager->job_manager->is_job_running( ). " get job number DATA: lt_joblist TYPE tbtcjob_tt. lt_joblist = sdk_package_manager->job_manager->get_running_jobs( i_jobname = sy-repid ). DATA wa_job TYPE tbtcjob. READ TABLE lt_joblist INTO wa_job INDEX 1. IF sy-subrc <> 0. MESSAGE |Expected to find exactly one job matching { sy-repid } but found { lines( lt_joblist ) }| TYPE 'I' DISPLAY LIKE 'E' ##NO_TEXT. ENDIF. DATA lr_header_content TYPE REF TO cl_salv_form_header_info. DATA l_job_message TYPE string. CONCATENATE `Warning: Import background job currently running with number` wa_job-jobcount INTO l_job_message SEPARATED BY ' ' ##NO_TEXT. IF lcl_ui_utils=>is_fullscreen( i_container = mr_container ). lr_header_content = NEW #( text = l_job_message tooltip = l_job_message ). mr_tree->set_top_of_list( lr_header_content ). ELSE. MESSAGE l_job_message TYPE 'I' DISPLAY LIKE 'W'. ENDIF. ENDIF. ENDMETHOD. " Currently no footer planned METHOD draw_footer. IF lcl_ui_utils=>is_fullscreen( i_container = mr_container ). DATA l_message TYPE string. DATA lr_footer_content TYPE REF TO cl_salv_form_header_info. lr_footer_content = NEW #( text = l_message tooltip = l_message ). mr_tree->set_end_of_list( lr_footer_content ). ENDIF. ENDMETHOD. METHOD delete_nodes. TRY. mr_tree->get_nodes( )->delete_all( ). CATCH cx_salv_error. ENDTRY. ENDMETHOD. METHOD refresh. sdk_package_manager->mt_installed_modules = sdk_package_manager->get_sdk_installed_modules( ). sdk_package_manager->mt_available_modules_inst = sdk_package_manager->get_sdk_avail_modules_json( i_operation = 'install' i_source = 'web' i_version = 'LATEST' ). sdk_package_manager->mt_available_modules_uninst = sdk_package_manager->get_sdk_avail_modules_json( i_operation = 'uninstall' i_source = 'web' i_version = 'LATEST' ). IF NOT sdk_package_manager->job_manager->is_job_running( ). CLEAR: mt_modules_to_be_installed. CLEAR: mt_modules_to_be_deleted. ENDIF. refresh_nodes( ). refresh_buttons( ). MESSAGE |Refresh complete.| TYPE 'S' ##NO_TEXT. IF sdk_package_manager->job_manager->is_job_running( ). lcl_ui_utils=>display_job_details_statusbar( i_job_manager = sdk_package_manager->job_manager ). ENDIF. ENDMETHOD. METHOD refresh_nodes. delete_nodes( ). draw_nodes( ). ENDMETHOD. METHOD refresh_buttons. DATA: lr_functions TYPE REF TO cl_salv_functions_tree, lr_function TYPE REF TO cl_salv_function, lt_functions TYPE salv_t_ui_func. TRY. lr_functions = mr_tree->get_functions( ). " If a job is running we deactivate all buttons that could interfere with the running op IF sdk_package_manager->job_manager->is_job_running( ) = abap_true. lr_functions->enable_function( name = 'EXE_FGND' boolean = ' ' ). lr_functions->enable_function( name = 'EXE_BGND' boolean = ' ' ). lr_functions->enable_function( name = 'INS_FGND' boolean = ' ' ). lr_functions->enable_function( name = 'INS_BGND' boolean = ' ' ). lr_functions->enable_function( name = 'DEL_FGND' boolean = ' ' ). lr_functions->enable_function( name = 'DEL_BGND' boolean = ' ' ). lr_functions->enable_function( name = 'BTC_DTLS' boolean = 'X' ). lr_functions->enable_function( name = 'UPD_INST' boolean = ' ' ). lr_functions->enable_function( name = 'DES_INST' boolean = ' ' ). lr_functions->enable_function( name = 'DOW_CERT' boolean = ' ' ). lr_functions->enable_function( name = 'DOW_TRAK' boolean = ' ' ). lr_functions->enable_function( name = 'INS_ALL' boolean = ' ' ). ELSE. "if not, activate all the buttons IF lcl_ui_utils=>is_sapgui_html( ) = abap_false " if we're not in SAPGUI for HTML, AND AND lcl_ui_utils=>is_sapgui_timeout_sufficient( ) = abap_true. " if we have a sufficiently large (900) auto logout value, foreground processing is enabled lr_functions->enable_function( name = 'EXE_FGND' boolean = 'X' ). lr_functions->enable_function( name = 'INS_FGND' boolean = 'X' ). lr_functions->enable_function( name = 'DEL_FGND' boolean = 'X' ). ELSE. lr_functions->enable_function( name = 'EXE_FGND' boolean = ' ' ). lr_functions->enable_function( name = 'INS_FGND' boolean = ' ' ). lr_functions->enable_function( name = 'DEL_FGND' boolean = ' ' ). ENDIF. lr_functions->enable_function( name = 'EXE_BGND' boolean = 'X' ). lr_functions->enable_function( name = 'DEL_BGND' boolean = 'X' ). lr_functions->enable_function( name = 'INS_BGND' boolean = 'X' ). lr_functions->enable_function( name = 'BTC_DTLS' boolean = ' ' ). IF lines( sdk_package_manager->mt_installed_modules ) > 4. " if core is installed, activate the select/deslected buttons lr_functions->enable_function( name = 'UPD_INST' boolean = 'X' ). lr_functions->enable_function( name = 'DES_INST' boolean = 'X' ). ELSE. lr_functions->enable_function( name = 'UPD_INST' boolean = ' ' ). lr_functions->enable_function( name = 'DES_INST' boolean = ' ' ). ENDIF. lr_functions->enable_function( name = 'DOW_CERT' boolean = 'X' ). lr_functions->enable_function( name = 'DOW_TRAK' boolean = 'X' ). lr_functions->enable_function( name = 'INS_ALL' boolean = 'X' ). ENDIF. CATCH cx_salv_wrong_call INTO DATA(r_ex1). MESSAGE r_ex1->get_text( ) TYPE 'I' DISPLAY LIKE 'E'. CATCH cx_salv_not_found INTO DATA(r_ex2). MESSAGE r_ex2->get_text( ) TYPE 'I' DISPLAY LIKE 'E'. CATCH cx_root INTO DATA(r_ex). MESSAGE r_ex->get_text( ) TYPE 'I' DISPLAY LIKE 'E'. ENDTRY. ENDMETHOD. METHOD set_handlers. DATA lr_tree_events TYPE REF TO cl_salv_events_tree. lr_tree_events = mr_tree->get_event( ). SET HANDLER handle_user_command FOR lr_tree_events. SET HANDLER handle_checkbox_changed FOR lr_tree_events. SET HANDLER handle_double_click FOR lr_tree_events. ENDMETHOD. METHOD set_settings. DATA lr_settings TYPE REF TO cl_salv_tree_settings. lr_settings = mr_tree->get_tree_settings( ). lr_settings->set_hierarchy_header( 'Modules' ) ##NO_TEXT. IF lcl_ui_utils=>is_fullscreen( i_container = mr_container ). lr_settings->set_header( 'AWS ABAP SDK package control (fullscreen)' ) ##NO_TEXT. ENDIF. ENDMETHOD. METHOD set_functions. DATA: lr_functions TYPE REF TO cl_salv_functions_tree, lr_function TYPE REF TO cl_salv_function, lt_functions TYPE salv_t_ui_func. lr_functions = mr_tree->get_functions( ). lr_functions->set_all( abap_true ). TRY. lr_functions->add_function( name = 'REF_TREE' icon = '@42@' text = 'Refresh' tooltip = 'Refresh the whole tree view' position = if_salv_c_function_position=>left_of_salv_functions ) ##NO_TEXT. lr_functions->add_function( name = 'EXE_FGND' icon = '@15@' text = 'Execute all' tooltip = 'Start operations in dialog processing' position = if_salv_c_function_position=>left_of_salv_functions ) ##NO_TEXT. lr_functions->add_function( name = 'EXE_BGND' icon = '@15@' text = 'Execute all (batch)' tooltip = 'Start operations in batch processing' position = if_salv_c_function_position=>left_of_salv_functions ) ##NO_TEXT. lr_functions->add_function( name = 'INS_FGND' icon = '@KA@' text = 'Install only' tooltip = 'Install only in dialog processing' position = if_salv_c_function_position=>left_of_salv_functions ) ##NO_TEXT. lr_functions->add_function( name = 'INS_BGND' icon = '@KA@' text = 'Install only (batch)' tooltip = 'Install only in batch processing' position = if_salv_c_function_position=>left_of_salv_functions ) ##NO_TEXT. lr_functions->add_function( name = 'DEL_FGND' icon = '@11@' text = 'Delete only' tooltip = 'Delete only in dialog processing' position = if_salv_c_function_position=>left_of_salv_functions ) ##NO_TEXT. lr_functions->add_function( name = 'DEL_BGND' icon = '@11@' text = 'Delete only (batch)' tooltip = 'Delete only in batch processing' position = if_salv_c_function_position=>left_of_salv_functions ) ##NO_TEXT. lr_functions->add_function( name = 'BTC_DTLS' icon = '@M5@' text = 'Job info' tooltip = 'Details on a running background job (if any)' position = if_salv_c_function_position=>left_of_salv_functions ) ##NO_TEXT. lr_functions->add_function( name = 'UPD_INST' icon = '@B1@' text = 'Select installed modules' tooltip = 'Mark all installed modules for update if applicable' position = if_salv_c_function_position=>left_of_salv_functions ) ##NO_TEXT. lr_functions->add_function( name = 'DES_INST' icon = '@B2@' text = 'Deselect installed modules' tooltip = 'Mark all installed modules for deletion' position = if_salv_c_function_position=>left_of_salv_functions ) ##NO_TEXT. lr_functions->add_function( name = 'DOW_CERT' icon = '@XL@' text = 'Install SSL Certificates' tooltip = 'Install Amazon Root Certificates' position = if_salv_c_function_position=>left_of_salv_functions ) ##NO_TEXT. lr_functions->add_function( name = 'DOW_TRAK' icon = '@X1@' text = 'Download current SDK' tooltip = 'Download current ABAP SDK Transport Kits' position = if_salv_c_function_position=>left_of_salv_functions ) ##NO_TEXT. lr_functions->add_function( name = 'INS_ALL' icon = '@6N@' text = 'Install all modules' tooltip = 'Install all available modules' position = if_salv_c_function_position=>left_of_salv_functions ) ##NO_TEXT. refresh_buttons( ). CATCH cx_salv_existing. CATCH cx_salv_wrong_call. ENDTRY. ENDMETHOD. METHOD fill_fullscreen_content. TRY. cl_salv_tree=>factory( EXPORTING hide_header = abap_false IMPORTING r_salv_tree = mr_tree CHANGING t_table = mt_treetab ). CATCH cx_salv_error. ENDTRY. draw_tree( ). ENDMETHOD. METHOD fill_container_content. TRY. cl_salv_tree=>factory( EXPORTING r_container = r_container hide_header = abap_false IMPORTING r_salv_tree = mr_tree CHANGING t_table = mt_treetab ). CATCH cx_salv_error. ENDTRY. mr_container = r_container. draw_tree( ). ENDMETHOD. METHOD create_fullscreen. fill_fullscreen_content( ). ENDMETHOD. METHOD create_container. CALL FUNCTION 'SALV_CSQT_CREATE_CONTAINER' EXPORTING r_content_manager = me title = 'ABAP SDK Package Manager' ##NO_TEXT. ENDMETHOD. METHOD get_modules_to_be_installed. DATA lr_nodes TYPE REF TO cl_salv_nodes. DATA lt_nodes TYPE salv_t_nodes. TRY. lr_nodes = mr_tree->get_nodes( ). CATCH cx_salv_msg. ENDTRY. TRY. lt_nodes = lr_nodes->get_all_nodes( ). CATCH cx_salv_msg. ENDTRY. LOOP AT lt_nodes ASSIGNING FIELD-SYMBOL(). TRY. IF -node->get_hierarchy_item( )->is_checked( ) AND NOT -node->is_folder( ) AND CAST string( -node->get_item( 'OP_CODE' )->get_value( ) )->* = lif_ui_constants=>c_operation_install. DATA(tla) = -node->get_text( ). IF sdk_package_manager->is_module_core( CONV #( tla ) ). tla = 'core'. ENDIF. CHECK NOT line_exists( rt_modules_to_be_installed[ tla = tla ] ). INSERT VALUE ts_sdk_tla( tla = tla version = i_target_version ) INTO TABLE rt_modules_to_be_installed. ENDIF. CATCH cx_salv_msg. ENDTRY. ENDLOOP. ENDMETHOD. METHOD get_modules_to_be_deleted. DATA lr_nodes TYPE REF TO cl_salv_nodes. DATA lt_nodes TYPE salv_t_nodes. TRY. lr_nodes = mr_tree->get_nodes( ). CATCH cx_salv_msg. ENDTRY. TRY. lt_nodes = lr_nodes->get_all_nodes( ). CATCH cx_salv_msg. ENDTRY. LOOP AT lt_nodes ASSIGNING FIELD-SYMBOL(). TRY. IF NOT -node->get_hierarchy_item( )->is_checked( ) AND NOT -node->is_folder( ) AND CAST string( -node->get_item( 'OP_CODE' )->get_value( ) )->* = lif_ui_constants=>c_operation_delete. DATA(tla) = -node->get_text( ). IF sdk_package_manager->is_module_core( CONV #( tla ) ). tla = 'core'. ENDIF. CHECK NOT line_exists( rt_modules_to_be_deleted[ tla = tla ] ). INSERT VALUE ts_sdk_tla( tla = tla version = i_target_version ) INTO TABLE rt_modules_to_be_deleted. ENDIF. CATCH cx_salv_msg. ENDTRY. ENDLOOP. ENDMETHOD. METHOD get_modules_to_be_updated. DATA lr_nodes TYPE REF TO cl_salv_nodes. DATA lt_nodes TYPE salv_t_nodes. TRY. lr_nodes = mr_tree->get_nodes( ). CATCH cx_salv_msg. ENDTRY. TRY. lt_nodes = lr_nodes->get_all_nodes( ). CATCH cx_salv_msg. ENDTRY. LOOP AT lt_nodes ASSIGNING FIELD-SYMBOL(). TRY. IF -node->get_hierarchy_item( )->is_checked( ) AND NOT -node->is_folder( ) AND CAST string( -node->get_item( 'OP_CODE' )->get_value( ) )->* = lif_ui_constants=>c_operation_update. DATA(tla) = -node->get_text( ). IF sdk_package_manager->is_module_core( CONV #( tla ) ). tla = 'core'. ENDIF. INSERT VALUE ts_sdk_tla( tla = tla version = i_target_version ) INTO TABLE rt_modules_to_be_updated. ENDIF. CATCH cx_salv_msg. ENDTRY. ENDLOOP. ENDMETHOD. METHOD handle_user_command. DATA(lv_ucomm) = sy-ucomm. DATA(lv_selection) = mr_tree->get_selections( ). TRY. CASE lv_ucomm. WHEN 'BACK' OR 'LEAR' OR 'CANC'. LEAVE PROGRAM. ENDCASE. DATA(command) = lcl_ui_command_factory=>create_command( i_function_code = e_salv_function i_tree_controller = me ). IF command->can_execute( i_tree_controller = me ). command->execute( i_tree_controller = me ). ENDIF. CATCH lcx_error INTO DATA(lo_ex). lo_ex->show( ). ENDTRY. ENDMETHOD. METHOD handle_checkbox_changed. TRY. DATA(l_node) = mr_tree->get_nodes( )->get_node( node_key = node_key ). CATCH cx_salv_msg. ENDTRY. DATA(l_tla) = l_node->get_text( ). DATA(wa_row) = CAST ts_sdk_module( l_node->get_data_row( ) )->*. IF l_tla = 'core'. CASE checked. WHEN abap_true. IF sdk_package_manager->is_core_installed( ) = abap_false. wa_row-op_text = 'Will be installed.' ##NO_TEXT. wa_row-op_icon = '@08@'. wa_row-op_code = lif_ui_constants=>c_operation_install. l_node->set_data_row( wa_row ). ELSE. IF lcl_sdk_utils=>cmp_version_string( i_string1 = sdk_package_manager->mt_installed_modules[ tla = 'sts' ]-avers i_string2 = sdk_package_manager->mt_installed_modules[ tla = 'sts' ]-cvers ) = 1. wa_row-op_text = 'Module will be updated.' ##NO_TEXT. wa_row-op_icon = '@09@'. wa_row-op_code = lif_ui_constants=>c_operation_update. l_node->set_data_row( wa_row ). ELSE. wa_row-op_text = 'Module up to date, no operation planned.' ##NO_TEXT. wa_row-op_icon = '@08@'. wa_row-op_code = lif_ui_constants=>c_operation_none. l_node->set_data_row( wa_row ). ENDIF. ENDIF. WHEN abap_false. IF sdk_package_manager->is_core_installed( ) = abap_true. wa_row-op_text = 'Will be deleted.' ##NO_TEXT. wa_row-op_icon = '@0A@'. wa_row-op_code = lif_ui_constants=>c_operation_delete. l_node->set_data_row( wa_row ). ELSE. wa_row-op_text = 'Will NOT be installed.' ##NO_TEXT. wa_row-op_icon = '@EB@'. wa_row-op_code = lif_ui_constants=>c_operation_none. l_node->set_data_row( wa_row ). ENDIF. ENDCASE. ELSE. CASE checked. WHEN abap_true. IF VALUE #( sdk_package_manager->mt_installed_modules[ tla = l_tla ] OPTIONAL ) IS INITIAL . wa_row-op_text = 'Will be installed.' ##NO_TEXT. wa_row-op_icon = '@08@'. wa_row-op_code = lif_ui_constants=>c_operation_install. l_node->set_data_row( wa_row ). ELSE. IF lcl_sdk_utils=>cmp_version_string( i_string1 = sdk_package_manager->mt_installed_modules[ tla = l_tla ]-avers i_string2 = sdk_package_manager->mt_installed_modules[ tla = l_tla ]-cvers ) = 1. wa_row-op_text = 'Module will be updated.' ##NO_TEXT. wa_row-op_icon = '@09@' ##NO_TEXT. wa_row-op_code = lif_ui_constants=>c_operation_update. l_node->set_data_row( wa_row ). ELSEIF lcl_sdk_utils=>cmp_version_string( i_string1 = sdk_package_manager->mt_installed_modules[ tla = l_tla ]-avers i_string2 = sdk_package_manager->mt_installed_modules[ tla = l_tla ]-cvers ) = 0. wa_row-op_text = 'Module up to date, no operation planned.' ##NO_TEXT. wa_row-op_icon = '@08@' ##NO_TEXT. wa_row-op_code = lif_ui_constants=>c_operation_none. l_node->set_data_row( wa_row ). ELSE. wa_row-op_text = 'Current version higher than available version. Module may be deprecated.' ##NO_TEXT. wa_row-op_icon = '@0A@' ##NO_TEXT. wa_row-op_code = lif_ui_constants=>c_operation_none. l_node->set_data_row( wa_row ). ENDIF. ENDIF. WHEN abap_false. IF VALUE #( sdk_package_manager->mt_installed_modules[ tla = l_tla ] OPTIONAL ) IS NOT INITIAL. wa_row-op_text = 'Will be deleted.' ##NO_TEXT. wa_row-op_icon = '@0A@'. wa_row-op_code = lif_ui_constants=>c_operation_delete. l_node->set_data_row( wa_row ). ELSE. wa_row-op_text = 'Will NOT be installed.' ##NO_TEXT. wa_row-op_icon = '@EB@'. wa_row-op_code = lif_ui_constants=>c_operation_none. l_node->set_data_row( wa_row ). ENDIF. ENDCASE. ENDIF. ENDMETHOD. METHOD handle_double_click. TRY. DATA(l_node) = mr_tree->get_nodes( )->get_node( node_key = node_key ). CATCH cx_salv_msg. ENDTRY. DATA(l_tla) = l_node->get_text( ). DATA(wa_row) = CAST ts_sdk_module( l_node->get_data_row( ) )->*. IF ( columnname = 'TP_RC' OR columnname = 'TP_ICON' OR columnname = 'TP_TEXT' ) AND ( wa_row-ctransport IS NOT INITIAL ). CALL FUNCTION 'TMS_UI_SHOW_TRANSPORT_LOGS' EXPORTING iv_request = CONV tmsbuffer-trkorr( wa_row-ctransport ) iv_system = CONV tmscsys-sysnam( lcl_sdk_utils=>get_system_name( ) ) iv_verbose = abap_true EXCEPTIONS show_transport_logs_failed = 1 OTHERS = 2. IF sy-subrc <> 0. ENDIF. ENDIF. IF ( columnname = 'CVERS' OR columnname = 'CTRANSPORT' ) AND ( wa_row-ctransport IS NOT INITIAL ). CALL FUNCTION 'TMS_UI_SHOW_TRANSPORT_REQUEST' EXPORTING iv_request = CONV tmsbuffer-trkorr( wa_row-ctransport ) iv_target_system = CONV tmscsys-sysnam( lcl_sdk_utils=>get_system_name( ) ) iv_verbose = abap_true EXCEPTIONS show_transport_request_failed = 1 OTHERS = 2. IF sy-subrc <> 0. ENDIF. ENDIF. IF ( columnname = 'NAME' OR columnname = 'AVERS' OR columnname = 'ATRANSPORT' ). * DATA: lr_dbox_container TYPE REF TO cl_gui_dialogbox_container. * DATA(lv_style) = cl_gui_control=>ws_thickframe + cl_gui_control=>ws_minimizebox + cl_gui_control=>ws_maximizebox + cl_gui_control=>ws_sysmenu. * * lr_dbox_container = NEW cl_gui_dialogbox_container( caption = 'AWS SDK for SAP ABAP - API Documentation' * top = 100 * left = 100 * width = 1750 * height = 1080 * metric = cl_gui_dialogbox_container=>metric_pixel ). * * set handler handle_on_close for lr_dbox_container. * * DATA: lr_html TYPE REF TO cl_gui_html_viewer. * lr_html = NEW cl_gui_html_viewer( parent = lr_dbox_container ). * lr_html->show_url( url = |https://docs.aws.amazon.com/sdk-for-sap-abap/v1/api/latest/{ l_tla }/index.html| * in_place = abap_true ). IF l_tla <> 'core'. cl_gui_frontend_services=>execute( EXPORTING document = |https://docs.aws.amazon.com/sdk-for-sap-abap/v1/api/latest/{ l_tla }/index.html| EXCEPTIONS cntl_error = 1 error_no_gui = 2 bad_parameter = 3 file_not_found = 4 path_not_found = 5 file_extension_unknown = 6 error_execute_failed = 7 OTHERS = 8 ). ELSE. " breakdown the line displaying 'core' into 4 distinct transports in a future commit cl_gui_frontend_services=>execute( EXPORTING document = |https://docs.aws.amazon.com/sdk-for-sap-abap/v1/api/latest/s3/index.html| EXCEPTIONS cntl_error = 1 error_no_gui = 2 bad_parameter = 3 file_not_found = 4 path_not_found = 5 file_extension_unknown = 6 error_execute_failed = 7 OTHERS = 8 ). ENDIF. ENDIF. ENDMETHOD. METHOD handle_on_close. IF sender IS NOT INITIAL. sender->free( ). ENDIF. ENDMETHOD. METHOD toggle_inst_modules. IF lines( sdk_package_manager->mt_installed_modules ) > 0. TRY. DATA(lr_inst_mods_nodes) = mr_tree->get_nodes( )->get_node( node_key = mt_folder_node_keys[ node_name = 'installed_modules' ]-key )->get_children( ). LOOP AT lr_inst_mods_nodes INTO DATA(wa_inst_mod_node). DATA(lr_inst_mod_item) = wa_inst_mod_node-node->get_hierarchy_item( ). lr_inst_mod_item->set_checked( i_checked ). handle_checkbox_changed( node_key = wa_inst_mod_node-node->get_key( ) checked = i_checked columnname = lr_inst_mod_item->get_columnname( ) ). ENDLOOP. CATCH cx_salv_msg. ENDTRY. ELSE. MESSAGE 'No modules to select!' TYPE 'E' DISPLAY LIKE 'E' ##NO_TEXT. ENDIF. ENDMETHOD. ENDCLASS. CLASS lcl_main DEFINITION FINAL. PUBLIC SECTION. METHODS main RAISING lcx_error. ENDCLASS. CLASS lcl_main IMPLEMENTATION. METHOD main. IF sy-batch = abap_true. DATA(sdk_pm_batch) = NEW lcl_sdk_package_manager( i_batch_mode = sy-batch ). ELSE. DATA(sdk_pm) = NEW lcl_sdk_package_manager( ). DATA(sdk_pm_tc) = NEW lcl_ui_tree_controller( i_sdk_package_manager = sdk_pm ). ENDIF. ENDMETHOD. ENDCLASS. START-OF-SELECTION. TRY. DATA(lr_main) = NEW lcl_main( ). lr_main->main( ). CATCH lcx_error INTO DATA(lo_ex). lo_ex->show( ). ENDTRY.