From cd2493cb7bd1293f434fcf2bc6867214b828ccfa Mon Sep 17 00:00:00 2001 From: larshp Date: Tue, 3 May 2016 12:50:14 +0000 Subject: [PATCH] new persistency framework, close #129 --- zabapgit.prog.abap | 1340 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 1315 insertions(+), 25 deletions(-) diff --git a/zabapgit.prog.abap b/zabapgit.prog.abap index 41ec35880..044ff1746 100644 --- a/zabapgit.prog.abap +++ b/zabapgit.prog.abap @@ -3,7 +3,7 @@ REPORT zabapgit. * See http://www.abapgit.org CONSTANTS: gc_xml_version TYPE string VALUE 'v1.0.0', "#EC NOTEXT - gc_abap_version TYPE string VALUE 'v1.3.4'. "#EC NOTEXT + gc_abap_version TYPE string VALUE 'v1.4.0'. "#EC NOTEXT ******************************************************************************** * The MIT License (MIT) @@ -896,14 +896,37 @@ CLASS lcl_tadir DEFINITION FINAL. ENDCLASS. "lcl_tadir DEFINITION +CLASS lcl_persistence_migrate DEFINITION FINAL. + + PUBLIC SECTION. + CLASS-METHODS: run RAISING lcx_exception. + + PRIVATE SECTION. + CONSTANTS: + c_text TYPE string VALUE 'Generated by abapGit' ##NO_TEXT. + + CLASS-METHODS: + migrate_repo RAISING lcx_exception, + migrate_user RAISING lcx_exception, + table_create RAISING lcx_exception, + table_exists + RETURNING VALUE(rv_exists) TYPE abap_bool, + lock_create RAISING lcx_exception, + lock_exists + RETURNING VALUE(rv_exists) TYPE abap_bool. + +ENDCLASS. + *----------------------------------------------------------------------* * CLASS lcl_user DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* -CLASS lcl_user DEFINITION FINAL. +CLASS lcl_user DEFINITION FINAL FRIENDS lcl_persistence_migrate. - PUBLIC SECTION. +* this class is obsolete, use LCL_PERSISTENCE_USER instead + + PROTECTED SECTION. TYPES: BEGIN OF ty_user, user LIKE sy-uname, username TYPE string, @@ -14036,11 +14059,9 @@ ENDCLASS. "lcl_pack IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* -CLASS lcl_persistence DEFINITION FINAL. +CLASS lcl_persistence DEFINITION FINAL FRIENDS lcl_persistence_migrate. -* there is currently no locking, so it is theoretically possible -* for a user to overwrite another users changes. -* the risk is minimized by always reading before updating +* this class is obsolete, use LCL_PERSISTENCE_REPO instead PUBLIC SECTION. TYPES: BEGIN OF ty_repo_persi, @@ -14052,6 +14073,7 @@ CLASS lcl_persistence DEFINITION FINAL. END OF ty_repo_persi. TYPES: ty_repos_persi_tt TYPE STANDARD TABLE OF ty_repo_persi WITH DEFAULT KEY. + PROTECTED SECTION. METHODS list RETURNING VALUE(rt_repos) TYPE ty_repos_persi_tt RAISING lcx_exception. @@ -14614,6 +14636,141 @@ CLASS lcl_repo_offline IMPLEMENTATION. ENDCLASS. "lcl_repo_offline IMPLEMENTATION +CLASS lcl_persistence_db DEFINITION FINAL. + + PUBLIC SECTION. + CONSTANTS: + c_tabname TYPE tabname VALUE 'ZABAPGIT', + c_lock TYPE viewname VALUE 'EZABAPGIT'. + + TYPES: ty_type TYPE c LENGTH 12. + TYPES: ty_value TYPE c LENGTH 12. + + TYPES: BEGIN OF ty_content, + type TYPE ty_type, + value TYPE ty_value, + data TYPE string, + END OF ty_content, + tt_content TYPE SORTED TABLE OF ty_content WITH UNIQUE KEY value. + + METHODS list_by_type + IMPORTING iv_type TYPE ty_type + RETURNING VALUE(rt_content) TYPE tt_content. + + METHODS list + RETURNING VALUE(rt_content) TYPE tt_content. + + METHODS add + IMPORTING iv_type TYPE ty_type + iv_value TYPE ty_content-value + iv_data TYPE ty_content-data + RAISING lcx_exception. + + METHODS delete + IMPORTING iv_type TYPE ty_type + iv_value TYPE ty_content-value + RAISING lcx_exception. + + METHODS update + IMPORTING iv_type TYPE ty_type + iv_value TYPE ty_content-value + iv_data TYPE ty_content-data + RAISING lcx_exception. + + METHODS modify + IMPORTING iv_type TYPE ty_type + iv_value TYPE ty_content-value + iv_data TYPE ty_content-data + RAISING lcx_exception. + + METHODS read + IMPORTING iv_type TYPE ty_type + iv_value TYPE ty_content-value + RETURNING VALUE(rv_data) TYPE ty_content-data + RAISING lcx_not_found. + + METHODS lock + IMPORTING iv_mode TYPE enqmode DEFAULT 'E' + iv_type TYPE ty_type + iv_value TYPE ty_content-value + RAISING lcx_exception. + +ENDCLASS. + +CLASS lcl_persistence_repo DEFINITION FINAL. + + PUBLIC SECTION. + TYPES: BEGIN OF ty_repo, + url TYPE string, + branch_name TYPE string, + sha1 TYPE ty_sha1, + package TYPE devclass, + offline TYPE sap_bool, + END OF ty_repo. + TYPES: tt_repo TYPE STANDARD TABLE OF ty_repo WITH DEFAULT KEY. + + TYPES: ty_repo_id TYPE c LENGTH 12. + + METHODS constructor. + + METHODS list + RETURNING VALUE(rt_repos) TYPE tt_repo + RAISING lcx_exception. + + METHODS update + IMPORTING iv_url TYPE ty_repo-url + iv_branch_sha1 TYPE ty_sha1 + RAISING lcx_exception. + + METHODS add + IMPORTING iv_url TYPE string + iv_branch_name TYPE string + iv_branch TYPE ty_sha1 OPTIONAL + iv_package TYPE devclass + iv_offline TYPE sap_bool DEFAULT abap_false + RAISING lcx_exception. + + METHODS delete + IMPORTING iv_url TYPE ty_repo-url + RAISING lcx_exception. + + METHODS read + IMPORTING iv_url TYPE ty_repo-url + RETURNING VALUE(rs_repo) TYPE ty_repo + RAISING lcx_exception + lcx_not_found. + + METHODS lock + IMPORTING iv_mode TYPE enqmode + iv_url TYPE ty_repo-url + RAISING lcx_exception. + + PRIVATE SECTION. + + CONSTANTS c_type_repo TYPE lcl_persistence_db=>ty_type VALUE 'REPO'. + + DATA: mo_db TYPE REF TO lcl_persistence_db. + + METHODS from_xml + IMPORTING iv_repo_xml_string TYPE string + RETURNING VALUE(rs_repo) TYPE ty_repo + RAISING lcx_exception. + + METHODS to_xml + IMPORTING is_repo TYPE ty_repo + RETURNING VALUE(rv_repo_xml_string) TYPE string. + + METHODS get_next_id + RETURNING VALUE(rv_next_repo_id) TYPE lcl_persistence_db=>ty_content-value + RAISING lcx_exception. + + METHODS url_to_id + IMPORTING iv_url TYPE ty_repo-url + RETURNING VALUE(rv_id) TYPE lcl_persistence_db=>ty_content-value + RAISING lcx_exception. + +ENDCLASS. + *----------------------------------------------------------------------* * CLASS lcl_repo_srv DEFINITION *----------------------------------------------------------------------* @@ -14663,7 +14820,7 @@ CLASS lcl_repo_srv DEFINITION FINAL. PRIVATE SECTION. CLASS-DATA: gv_init TYPE abap_bool VALUE abap_false, - go_persistence TYPE REF TO lcl_persistence, + go_persistence TYPE REF TO lcl_persistence_repo, gt_list TYPE ty_repo_tt. CLASS-METHODS: @@ -14680,6 +14837,8 @@ CLASS lcl_repo_srv DEFINITION FINAL. ENDCLASS. "lcl_repo_srv DEFINITION + + *----------------------------------------------------------------------* * CLASS lcl_repo_online IMPLEMENTATION *----------------------------------------------------------------------* @@ -14763,14 +14922,13 @@ CLASS lcl_repo_online IMPLEMENTATION. METHOD set_sha1. - DATA: lo_persistence TYPE REF TO lcl_persistence. + DATA: lo_persistence TYPE REF TO lcl_persistence_repo. CREATE OBJECT lo_persistence. lo_persistence->update( iv_url = ms_data-url - iv_branch_name = ms_data-branch_name - iv_branch = iv_sha1 ). + iv_branch_sha1 = iv_sha1 ). ms_data-sha1 = iv_sha1. @@ -14792,14 +14950,12 @@ CLASS lcl_repo IMPLEMENTATION. METHOD delete. - DATA: lo_persistence TYPE REF TO lcl_persistence. + DATA: lo_persistence TYPE REF TO lcl_persistence_repo. CREATE OBJECT lo_persistence. - lo_persistence->delete( - iv_url = ms_data-url - iv_branch_name = ms_data-branch_name ). + lo_persistence->delete( ms_data-url ). ENDMETHOD. "delete @@ -14816,7 +14972,7 @@ CLASS lcl_repo IMPLEMENTATION. METHOD add. - DATA: lo_persistence TYPE REF TO lcl_persistence. + DATA: lo_persistence TYPE REF TO lcl_persistence_repo. CREATE OBJECT lo_persistence. @@ -16440,7 +16596,6 @@ CLASS lcl_gui IMPLEMENTATION. rv_html = rv_html && '


abapGit Version: ' && gc_abap_version && - ' e' && '

'. "#EC NOTEXT rv_html = rv_html && @@ -16852,6 +17007,82 @@ CLASS lcl_gui_page_diff IMPLEMENTATION. ENDCLASS. +CLASS lcl_persistence_user DEFINITION FINAL. +* todo, refactor this class later? add constructor with +* iv_user as importing optional parameter + + PUBLIC SECTION. + CLASS-METHODS set_username + IMPORTING iv_user TYPE xubname DEFAULT sy-uname + iv_username TYPE string + RAISING lcx_exception. + + CLASS-METHODS get_username + IMPORTING iv_user TYPE xubname DEFAULT sy-uname + RETURNING VALUE(rv_username) TYPE string + RAISING lcx_exception. + + CLASS-METHODS set_email + IMPORTING iv_user TYPE xubname DEFAULT sy-uname + iv_email TYPE string + RAISING lcx_exception. + + CLASS-METHODS get_email + IMPORTING iv_user TYPE xubname DEFAULT sy-uname + RETURNING VALUE(rv_email) TYPE string + RAISING lcx_exception. + + PRIVATE SECTION. + CONSTANTS c_type_user TYPE lcl_persistence_db=>ty_type VALUE 'USER'. + + TYPES: BEGIN OF ty_user, + username TYPE string, + email TYPE string, + END OF ty_user. + + CLASS-METHODS from_xml + IMPORTING iv_xml TYPE string + RETURNING VALUE(rs_user) TYPE ty_user + RAISING lcx_exception. + + CLASS-METHODS to_xml + IMPORTING is_user TYPE ty_user + RETURNING VALUE(rv_xml) TYPE string. + + CLASS-METHODS read + IMPORTING iv_user TYPE xubname + RETURNING VALUE(rs_user) TYPE ty_user + RAISING lcx_exception. + + CLASS-METHODS update + IMPORTING iv_user TYPE xubname + is_user TYPE ty_user + RAISING lcx_exception. + +ENDCLASS. + +CLASS lcl_gui_page_db DEFINITION. + + PUBLIC SECTION. + INTERFACES lif_gui_page. + + PRIVATE SECTION. + METHODS: + delete + IMPORTING is_key TYPE lcl_persistence_db=>ty_content + RAISING lcx_exception, + delete_popup + RETURNING VALUE(rv_continue) TYPE abap_bool + RAISING lcx_exception, + key_encode + IMPORTING is_key TYPE lcl_persistence_db=>ty_content + RETURNING VALUE(rv_string) TYPE string, + key_decode + IMPORTING iv_string TYPE clike + RETURNING VALUE(rs_key) TYPE lcl_persistence_db=>ty_content. + +ENDCLASS. + CLASS lcl_gui_page_main IMPLEMENTATION. METHOD zipexport. @@ -16955,14 +17186,14 @@ CLASS lcl_gui_page_main IMPLEMENTATION. -fieldname = 'TEXT'. -fieldtext = 'Username'. "#EC NOTEXT -field_obl = abap_true. - -value = lcl_user=>get_username( ). + -value = lcl_persistence_user=>get_username( ). APPEND INITIAL LINE TO lt_fields ASSIGNING . -tabname = 'BAPIRTEXT1'. -fieldname = 'TEXT'. -fieldtext = 'E-Mail'. "#EC NOTEXT -field_obl = abap_true. - -value = lcl_user=>get_email( ). + -value = lcl_persistence_user=>get_email( ). APPEND INITIAL LINE TO lt_fields ASSIGNING . -tabname = 'ABAPTXT255'. @@ -16992,12 +17223,12 @@ CLASS lcl_gui_page_main IMPLEMENTATION. READ TABLE lt_fields INDEX 1 ASSIGNING . ASSERT sy-subrc = 0. rs_comment-username = -value. - lcl_user=>set_username( rs_comment-username ). + lcl_persistence_user=>set_username( rs_comment-username ). READ TABLE lt_fields INDEX 2 ASSIGNING . ASSERT sy-subrc = 0. rs_comment-email = -value. - lcl_user=>set_email( rs_comment-email ). + lcl_persistence_user=>set_email( rs_comment-email ). READ TABLE lt_fields INDEX 3 ASSIGNING . ASSERT sy-subrc = 0. @@ -17016,6 +17247,8 @@ CLASS lcl_gui_page_main IMPLEMENTATION. lo_repo->deserialize( ). + COMMIT WORK. + lcl_gui=>render( ). ENDMETHOD. "pull @@ -17058,6 +17291,8 @@ CLASS lcl_gui_page_main IMPLEMENTATION. lo_repo->push( is_comment = ls_comment it_files = lt_push ). + COMMIT WORK. + lcl_gui=>render( ). ENDMETHOD. "commit @@ -17177,6 +17412,8 @@ CLASS lcl_gui_page_main IMPLEMENTATION. lcl_repo_srv=>delete( lo_repo ). + COMMIT WORK. + lcl_gui=>render( ). ENDMETHOD. "uninstall @@ -17222,6 +17459,8 @@ CLASS lcl_gui_page_main IMPLEMENTATION. lcl_repo_srv=>delete( lo_repo ). + COMMIT WORK. + lcl_gui=>render( ). ENDMETHOD. "remove @@ -17264,6 +17503,8 @@ CLASS lcl_gui_page_main IMPLEMENTATION. lo_repo->push( is_comment = ls_comment it_files = lt_files ). + COMMIT WORK. + lcl_gui=>render( ). ENDMETHOD. "add @@ -17319,6 +17560,8 @@ CLASS lcl_gui_page_main IMPLEMENTATION. iv_url = lv_url iv_package = lv_package ). + COMMIT WORK. + lcl_gui=>render( ). ENDMETHOD. "newoffline @@ -17402,6 +17645,8 @@ CLASS lcl_gui_page_main IMPLEMENTATION. lo_repo->status( ). " check for errors lo_repo->deserialize( ). + COMMIT WORK. + lcl_gui=>render( ). ENDMETHOD. "install @@ -17679,6 +17924,8 @@ CLASS lcl_gui_page_main IMPLEMENTATION. ENDIF. ENDDO. + COMMIT WORK. + lcl_gui=>render( ). ENDMETHOD. "abapgit_installation @@ -17735,7 +17982,8 @@ CLASS lcl_gui_page_main IMPLEMENTATION. DATA: ls_result TYPE lcl_file_status=>ty_result, lv_url TYPE string, lv_key TYPE lcl_repo=>ty_key, - ls_item TYPE ty_item. + ls_item TYPE ty_item, + lo_db TYPE REF TO lcl_gui_page_db. CASE iv_action. @@ -17785,8 +18033,9 @@ CLASS lcl_gui_page_main IMPLEMENTATION. pull( lv_key ). WHEN 'newoffline'. newoffline( ). - WHEN 'render'. - lcl_gui=>render( ). + WHEN 'db'. + CREATE OBJECT lo_db. + lcl_gui=>call_page( lo_db ). WHEN 'zipimport'. lv_key = iv_getdata. lcl_zip=>import( lv_key ). @@ -17842,6 +18091,10 @@ CLASS lcl_gui_page_main IMPLEMENTATION. ENDLOOP. ENDIF. + rv_html = rv_html && + '

e

' && gc_newline && + '

d

' && gc_newline. + rv_html = rv_html && lcl_gui=>footer( ). ENDMETHOD. @@ -17875,6 +18128,8 @@ FORM run. ENDIF. TRY. + lcl_persistence_migrate=>run( ). + CREATE OBJECT lo_main. lcl_gui=>call_page( lo_main ). CATCH lcx_exception INTO lx_exception. @@ -18869,4 +19124,1039 @@ CLASS ltcl_dangerous IMPLEMENTATION. ENDMETHOD. "run -ENDCLASS. "ltcl_dangerous IMPLEMENTATION \ No newline at end of file +ENDCLASS. "ltcl_dangerous IMPLEMENTATION + +CLASS lcl_persistence_user IMPLEMENTATION. + + METHOD from_xml. + CALL TRANSFORMATION id + OPTIONS value_handling = 'accept_data_loss' + SOURCE XML iv_xml + RESULT (c_type_user) = rs_user ##NO_TEXT. + ENDMETHOD. + + METHOD to_xml. + CALL TRANSFORMATION id + SOURCE (c_type_user) = is_user + RESULT XML rv_xml. + ENDMETHOD. + + METHOD read. + + DATA: lv_xml TYPE string, + lo_db TYPE REF TO lcl_persistence_db. + + + CREATE OBJECT lo_db. + + TRY. + lv_xml = lo_db->read( + iv_type = c_type_user + iv_value = iv_user ). + CATCH lcx_not_found. + RETURN. + ENDTRY. + + rs_user = from_xml( lv_xml ). + + ENDMETHOD. + + METHOD update. + + DATA: lv_xml TYPE string, + lo_db TYPE REF TO lcl_persistence_db. + + + lv_xml = to_xml( is_user ). + + CREATE OBJECT lo_db. + + lo_db->modify( + iv_type = c_type_user + iv_value = iv_user + iv_data = lv_xml ). + + ENDMETHOD. + + METHOD set_username. + + DATA: ls_user TYPE ty_user. + + + ls_user = read( iv_user ). + + ls_user-username = iv_username. + + update( iv_user = iv_user + is_user = ls_user ). + + ENDMETHOD. + + METHOD get_username. + + rv_username = read( iv_user )-username. + + ENDMETHOD. + + METHOD set_email. + + DATA: ls_user TYPE ty_user. + + + ls_user = read( iv_user ). + + ls_user-email = iv_email. + + update( iv_user = iv_user + is_user = ls_user ). + + ENDMETHOD. + + METHOD get_email. + + rv_email = read( iv_user )-email. + + ENDMETHOD. + +ENDCLASS. + +CLASS lcl_persistence_db IMPLEMENTATION. + + METHOD list_by_type. + SELECT * FROM (c_tabname) + INTO TABLE rt_content + WHERE type = iv_type. "#EC CI_SUBRC + ENDMETHOD. + + METHOD list. + SELECT * FROM (c_tabname) + INTO TABLE rt_content. "#EC CI_SUBRC + ENDMETHOD. + + METHOD lock. + + CALL FUNCTION 'ENQUEUE_EZABAPGIT' + EXPORTING + mode_zabapgit = iv_mode + type = iv_type + value = iv_value + EXCEPTIONS + foreign_lock = 1 + system_failure = 2 + OTHERS = 3. + IF sy-subrc <> 0. + _raise 'Could not aquire lock'. + ENDIF. + +* trigger dummy update task to automatically release locks at commit + CALL FUNCTION 'BANK_OBJ_WORKL_RELEASE_LOCKS' + IN UPDATE TASK. + + ENDMETHOD. + + METHOD add. + + DATA ls_table TYPE ty_content. + + ls_table-type = iv_type. + ls_table-value = iv_value. + ls_table-data = iv_data. + + INSERT (c_tabname) FROM ls_table. "#EC CI_SUBRC + ASSERT sy-subrc = 0. + + ENDMETHOD. + + METHOD delete. + + lock( iv_type = iv_type + iv_value = iv_value ). + + DELETE FROM (c_tabname) + WHERE type = iv_type + AND value = iv_value. + IF sy-subrc <> 0. + _raise 'DB Delete failed'. + ENDIF. + + ENDMETHOD. + + METHOD update. + + lock( iv_type = iv_type + iv_value = iv_value ). + + UPDATE (c_tabname) SET data = iv_data + WHERE type = iv_type + AND value = iv_value. + IF sy-subrc <> 0. + _raise 'DB update failed'. + ENDIF. + + ENDMETHOD. + + METHOD modify. + + DATA: ls_content TYPE ty_content. + + lock( iv_type = iv_type + iv_value = iv_value ). + + ls_content-type = iv_type. + ls_content-value = iv_value. + ls_content-data = iv_data. + + MODIFY (c_tabname) FROM ls_content. + IF sy-subrc <> 0. + _raise 'DB modify failed'. + ENDIF. + + ENDMETHOD. + + METHOD read. + + SELECT SINGLE data FROM (c_tabname) INTO rv_data + WHERE type = iv_type + AND value = iv_value. "#EC CI_SUBRC + IF sy-subrc <> 0. + RAISE EXCEPTION TYPE lcx_not_found. + ENDIF. + + ENDMETHOD. + +ENDCLASS. + +CLASS lcl_persistence_repo IMPLEMENTATION. + + METHOD add. + + DATA: ls_repo TYPE ty_repo, + lv_repo_as_xml TYPE string. + + + ls_repo-url = iv_url. + ls_repo-branch_name = iv_branch_name. + ls_repo-sha1 = iv_branch. + ls_repo-package = iv_package. + ls_repo-offline = iv_offline. + +* prevent duplicates + TRY. + read( iv_url ). + _raise 'Repository already exists'. + CATCH lcx_not_found ##NO_HANDLER. + ENDTRY. + + lv_repo_as_xml = to_xml( ls_repo ). + + mo_db->add( iv_type = c_type_repo + iv_value = get_next_id( ) + iv_data = lv_repo_as_xml ). + + ENDMETHOD. + + METHOD delete. + + mo_db->delete( iv_type = c_type_repo + iv_value = url_to_id( iv_url ) ). + + ENDMETHOD. + + METHOD update. + + DATA: lt_content TYPE lcl_persistence_db=>tt_content, + ls_content LIKE LINE OF lt_content, + ls_repo TYPE ty_repo. + + + IF iv_branch_sha1 IS INITIAL. + _raise 'update, sha empty'. + ENDIF. + + TRY. + ls_repo = read( iv_url ). + CATCH lcx_not_found. + _raise 'update repo not found'. + ENDTRY. + + ls_repo-sha1 = iv_branch_sha1. + ls_content-data = to_xml( ls_repo ). + + mo_db->update( iv_type = c_type_repo + iv_value = url_to_id( iv_url ) + iv_data = ls_content-data ). + + ENDMETHOD. + + METHOD read. + + DATA lt_repo TYPE tt_repo. + + lt_repo = list( ). + + READ TABLE lt_repo INTO rs_repo WITH KEY url = iv_url. + IF sy-subrc <> 0. + RAISE EXCEPTION TYPE lcx_not_found. + ENDIF. + + ENDMETHOD. + + METHOD get_next_id. + +* todo: Lock the complete persistence in order to prevent concurrent repo-creation +* however the current approach will most likely work in almost all cases + + DATA: lt_content TYPE lcl_persistence_db=>tt_content. + + FIELD-SYMBOLS: LIKE LINE OF lt_content. + + + rv_next_repo_id = 1. + + lt_content = mo_db->list_by_type( c_type_repo ). + LOOP AT lt_content ASSIGNING . + IF -value >= rv_next_repo_id. + rv_next_repo_id = -value + 1. + ENDIF. + ENDLOOP. + + CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT' + EXPORTING + input = rv_next_repo_id + IMPORTING + output = rv_next_repo_id. + + ENDMETHOD. + + METHOD list. + + DATA: lt_content TYPE lcl_persistence_db=>tt_content, + ls_content LIKE LINE OF lt_content, + ls_repo LIKE LINE OF rt_repos. + + + lt_content = mo_db->list_by_type( c_type_repo ). + + LOOP AT lt_content INTO ls_content. + ls_repo = from_xml( ls_content-data ). + INSERT ls_repo INTO TABLE rt_repos. + ENDLOOP. + + ENDMETHOD. + + METHOD from_xml. + CALL TRANSFORMATION id + OPTIONS value_handling = 'accept_data_loss' + SOURCE XML iv_repo_xml_string + RESULT (c_type_repo) = rs_repo ##NO_TEXT. + + IF rs_repo IS INITIAL. + _raise 'Inconsistent repo metadata'. + ENDIF. + ENDMETHOD. + + METHOD to_xml. + CALL TRANSFORMATION id + SOURCE (c_type_repo) = is_repo + RESULT XML rv_repo_xml_string. + ENDMETHOD. + + METHOD url_to_id. + + DATA: lt_content TYPE lcl_persistence_db=>tt_content, + ls_content LIKE LINE OF lt_content, + ls_repo TYPE ty_repo. + + + lt_content = mo_db->list_by_type( c_type_repo ). + + LOOP AT lt_content INTO ls_content. + ls_repo = from_xml( ls_content-data ). + IF ls_repo-url = iv_url. + rv_id = ls_content-value. + RETURN. + ENDIF. + ENDLOOP. + + _raise 'Repo, error finding id for url'. + + ENDMETHOD. + + METHOD constructor. + CREATE OBJECT mo_db. + ENDMETHOD. + + METHOD lock. + + mo_db->lock( iv_mode = iv_mode + iv_type = c_type_repo + iv_value = url_to_id( iv_url ) ). + + ENDMETHOD. + +ENDCLASS. + +CLASS lcl_persistence_migrate IMPLEMENTATION. + + METHOD run. + + IF table_exists( ) = abap_false. + table_create( ). + ENDIF. + + IF lock_exists( ) = abap_false. + lock_create( ). + + migrate_repo( ). + migrate_user( ). + ENDIF. + + ENDMETHOD. + + METHOD migrate_repo. + + DATA: lt_repo TYPE lcl_persistence=>ty_repos_persi_tt, + lo_repo TYPE REF TO lcl_persistence, + lo_new TYPE REF TO lcl_persistence_repo, + ls_repo LIKE LINE OF lt_repo. + + + CREATE OBJECT lo_repo. + CREATE OBJECT lo_new. + + lt_repo = lo_repo->list( ). + + LOOP AT lt_repo INTO ls_repo. + lo_new->add( iv_url = ls_repo-url + iv_branch_name = ls_repo-branch_name + iv_branch = ls_repo-sha1 + iv_package = ls_repo-package + iv_offline = ls_repo-offline ). + ENDLOOP. + ENDMETHOD. + + METHOD migrate_user. + + DATA: lt_users TYPE lcl_user=>ty_user_tt. + + FIELD-SYMBOLS: LIKE LINE OF lt_users. + + + lt_users = lcl_user=>list( ). + LOOP AT lt_users ASSIGNING . + lcl_persistence_user=>set_username( + iv_user = -user + iv_username = -username ). + lcl_persistence_user=>set_email( + iv_user = -user + iv_email = -email ). + ENDLOOP. + + ENDMETHOD. + + METHOD lock_exists. + + DATA: lv_viewname TYPE dd25l-viewname. + + + SELECT SINGLE viewname FROM dd25l INTO lv_viewname + WHERE viewname = lcl_persistence_db=>c_lock. + rv_exists = boolc( sy-subrc = 0 ). + + ENDMETHOD. + + METHOD lock_create. + + DATA: lv_obj_name TYPE tadir-obj_name, + ls_dd25v TYPE dd25v, + lt_dd26e TYPE STANDARD TABLE OF dd26e WITH DEFAULT KEY, + lt_dd27p TYPE STANDARD TABLE OF dd27p WITH DEFAULT KEY. + + FIELD-SYMBOLS: LIKE LINE OF lt_dd26e, + LIKE LINE OF lt_dd27p. + + + ls_dd25v-viewname = lcl_persistence_db=>c_lock. + ls_dd25v-aggtype = 'E'. + ls_dd25v-roottab = lcl_persistence_db=>c_tabname. + ls_dd25v-ddlanguage = gc_english. + ls_dd25v-ddtext = c_text. + + APPEND INITIAL LINE TO lt_dd26e ASSIGNING . + -viewname = lcl_persistence_db=>c_lock. + -tabname = lcl_persistence_db=>c_tabname. + -tabpos = '0001'. + -fortabname = lcl_persistence_db=>c_tabname. + -enqmode = 'E'. + + APPEND INITIAL LINE TO lt_dd27p ASSIGNING . + -viewname = lcl_persistence_db=>c_lock. + -objpos = '0001'. + -viewfield = 'TYPE'. + -tabname = lcl_persistence_db=>c_tabname. + -fieldname = 'TYPE'. + -keyflag = abap_true. + + APPEND INITIAL LINE TO lt_dd27p ASSIGNING . + -viewname = lcl_persistence_db=>c_lock. + -objpos = '0002'. + -viewfield = 'VALUE'. + -tabname = lcl_persistence_db=>c_tabname. + -fieldname = 'VALUE'. + -keyflag = abap_true. + + CALL FUNCTION 'DDIF_ENQU_PUT' + EXPORTING + name = lcl_persistence_db=>c_lock + dd25v_wa = ls_dd25v + TABLES + dd26e_tab = lt_dd26e + dd27p_tab = lt_dd27p + EXCEPTIONS + enqu_not_found = 1 + name_inconsistent = 2 + enqu_inconsistent = 3 + put_failure = 4 + put_refused = 5 + OTHERS = 6. + IF sy-subrc <> 0. + _raise 'migrate, error from DDIF_ENQU_PUT'. + ENDIF. + + lv_obj_name = lcl_persistence_db=>c_lock. + CALL FUNCTION 'TR_TADIR_INTERFACE' + EXPORTING + wi_tadir_pgmid = 'R3TR' + wi_tadir_object = 'ENQU' + wi_tadir_obj_name = lv_obj_name + wi_set_genflag = abap_true + wi_test_modus = abap_false + wi_tadir_devclass = '$TMP' + EXCEPTIONS + OTHERS = 1. + IF sy-subrc <> 0. + _raise 'migrate, error from TR_TADIR_INTERFACE'. + ENDIF. + + CALL FUNCTION 'DDIF_ENQU_ACTIVATE' + EXPORTING + name = lcl_persistence_db=>c_lock + EXCEPTIONS + not_found = 1 + put_failure = 2 + OTHERS = 3. + IF sy-subrc <> 0. + _raise 'migrate, error from DDIF_ENQU_ACTIVATE'. + ENDIF. + + ENDMETHOD. + + METHOD table_exists. + + DATA: lv_tabname TYPE dd02l-tabname. + + SELECT SINGLE tabname FROM dd02l INTO lv_tabname + WHERE tabname = lcl_persistence_db=>c_tabname. + rv_exists = boolc( sy-subrc = 0 ). + + ENDMETHOD. + + METHOD table_create. + + DATA: lv_obj_name TYPE tadir-obj_name, + ls_dd02v TYPE dd02v, + ls_dd09l TYPE dd09l, + lt_dd03p TYPE STANDARD TABLE OF dd03p WITH DEFAULT KEY. + + FIELD-SYMBOLS: LIKE LINE OF lt_dd03p. + + ls_dd02v-tabname = lcl_persistence_db=>c_tabname. + ls_dd02v-ddlanguage = gc_english. + ls_dd02v-tabclass = 'TRANSP'. + ls_dd02v-ddtext = c_text. + ls_dd02v-contflag = 'A'. + ls_dd02v-exclass = '1'. + + ls_dd09l-tabname = lcl_persistence_db=>c_tabname. + ls_dd09l-as4local = 'A'. + ls_dd09l-tabkat = '1'. + ls_dd09l-tabart = 'APPL1'. + ls_dd09l-bufallow = 'N'. + + APPEND INITIAL LINE TO lt_dd03p ASSIGNING . + -tabname = lcl_persistence_db=>c_tabname. + -fieldname = 'TYPE'. + -position = '0001'. + -keyflag = 'X'. + -datatype = 'CHAR'. + -leng = '000012'. + + APPEND INITIAL LINE TO lt_dd03p ASSIGNING . + -tabname = lcl_persistence_db=>c_tabname. + -fieldname = 'VALUE'. + -position = '0002'. + -keyflag = 'X'. + -datatype = 'CHAR'. + -leng = '000012'. + + APPEND INITIAL LINE TO lt_dd03p ASSIGNING . + -tabname = lcl_persistence_db=>c_tabname. + -fieldname = 'DATA'. + -position = '0003'. + -datatype = 'STRG'. + + CALL FUNCTION 'DDIF_TABL_PUT' + EXPORTING + name = lcl_persistence_db=>c_tabname + dd02v_wa = ls_dd02v + dd09l_wa = ls_dd09l + TABLES + dd03p_tab = lt_dd03p + EXCEPTIONS + tabl_not_found = 1 + name_inconsistent = 2 + tabl_inconsistent = 3 + put_failure = 4 + put_refused = 5 + OTHERS = 6. + IF sy-subrc <> 0. + _raise 'migrate, error from DDIF_TABL_PUT'. + ENDIF. + + lv_obj_name = lcl_persistence_db=>c_tabname. + CALL FUNCTION 'TR_TADIR_INTERFACE' + EXPORTING + wi_tadir_pgmid = 'R3TR' + wi_tadir_object = 'TABL' + wi_tadir_obj_name = lv_obj_name + wi_set_genflag = abap_true + wi_test_modus = abap_false + wi_tadir_devclass = '$TMP' + EXCEPTIONS + OTHERS = 1. + IF sy-subrc <> 0. + _raise 'migrate, error from TR_TADIR_INTERFACE'. + ENDIF. + + CALL FUNCTION 'DDIF_TABL_ACTIVATE' + EXPORTING + name = lcl_persistence_db=>c_tabname + EXCEPTIONS + not_found = 1 + put_failure = 2 + OTHERS = 3. + IF sy-subrc <> 0. + _raise 'migrate, error from DDIF_TABL_ACTIVATE'. + ENDIF. + + ENDMETHOD. + +ENDCLASS. + +CLASS lcl_xml_pretty DEFINITION. + + PUBLIC SECTION. + CLASS-METHODS: print + IMPORTING iv_xml TYPE string + RETURNING VALUE(rv_xml) TYPE string. + +ENDCLASS. + +CLASS lcl_xml_pretty IMPLEMENTATION. + + METHOD print. + + DATA: li_ixml TYPE REF TO if_ixml, + li_xml_doc TYPE REF TO if_ixml_document, + li_stream_factory TYPE REF TO if_ixml_stream_factory, + li_istream TYPE REF TO if_ixml_istream, + li_parser TYPE REF TO if_ixml_parser, + li_ostream TYPE REF TO if_ixml_ostream, + li_renderer TYPE REF TO if_ixml_renderer. + + + ASSERT NOT iv_xml IS INITIAL. + + li_ixml = cl_ixml=>create( ). + li_xml_doc = li_ixml->create_document( ). + + li_stream_factory = li_ixml->create_stream_factory( ). + li_istream = li_stream_factory->create_istream_string( iv_xml ). + li_parser = li_ixml->create_parser( stream_factory = li_stream_factory + istream = li_istream + document = li_xml_doc ). + li_parser->set_normalizing( abap_true ). + IF li_parser->parse( ) <> 0. +* ignore errors + rv_xml = iv_xml. + RETURN. + ENDIF. + li_istream->close( ). + + + li_ostream = li_stream_factory->create_ostream_cstring( rv_xml ). + + li_renderer = li_ixml->create_renderer( ostream = li_ostream + document = li_xml_doc ). + + li_renderer->set_normalizing( abap_true ). + + li_renderer->render( ). + + ENDMETHOD. + +ENDCLASS. + +CLASS lcl_gui_page_display DEFINITION. + + PUBLIC SECTION. + INTERFACES lif_gui_page. + + METHODS: constructor + IMPORTING is_key TYPE lcl_persistence_db=>ty_content. + + PRIVATE SECTION. + DATA: ms_key TYPE lcl_persistence_db=>ty_content. + +ENDCLASS. + +CLASS lcl_gui_page_display IMPLEMENTATION. + + METHOD constructor. + ms_key = is_key. + ENDMETHOD. + + METHOD lif_gui_page~on_event. + + CASE iv_action. + WHEN 'back'. + lcl_gui=>back( ). + WHEN OTHERS. + _raise 'Unknown action'. + ENDCASE. + + ENDMETHOD. + + METHOD lif_gui_page~render. + + DATA: lv_data TYPE lcl_persistence_db=>ty_content-data, + lo_db TYPE REF TO lcl_persistence_db. + + + CREATE OBJECT lo_db. + TRY. + lv_data = lo_db->read( + iv_type = ms_key-type + iv_value = ms_key-value ). + CATCH lcx_not_found. + ENDTRY. + + lv_data = lcl_xml_pretty=>print( lv_data ). + + lv_data = escape( val = lv_data + format = cl_abap_format=>e_html_attr ). + + rv_html = lcl_gui=>header( ) && gc_newline && + '

Display

' && gc_newline && + 'Back

' && gc_newline && + 'Type:
' && gc_newline && + ms_key-type && '

' && gc_newline && + 'Value:
' && gc_newline && + ms_key-value && '

' && gc_newline && + 'Data:
' && gc_newline && + '
' && lv_data && '

' && gc_newline && + lcl_gui=>footer( ). + + ENDMETHOD. + +ENDCLASS. + +CLASS lcl_gui_page_edit DEFINITION. + + PUBLIC SECTION. + INTERFACES lif_gui_page. + + METHODS: constructor + IMPORTING is_key TYPE lcl_persistence_db=>ty_content. + + PRIVATE SECTION. + DATA: ms_key TYPE lcl_persistence_db=>ty_content. + + METHODS: save + IMPORTING it_postdata TYPE cnht_post_data_tab + RAISING lcx_exception. + +ENDCLASS. + +CLASS lcl_gui_page_edit IMPLEMENTATION. + + METHOD constructor. + ms_key = is_key. + ENDMETHOD. + + METHOD save. + + DATA: lv_string TYPE string, + ls_content TYPE lcl_persistence_db=>ty_content, + lo_db TYPE REF TO lcl_persistence_db, + lt_fields TYPE tihttpnvp. + + FIELD-SYMBOLS: LIKE LINE OF lt_fields. + + + CONCATENATE LINES OF it_postdata INTO lv_string. + + lt_fields = cl_http_utility=>if_http_utility~string_to_fields( lv_string ). + + READ TABLE lt_fields ASSIGNING WITH KEY name = 'type'. + ASSERT sy-subrc = 0. + ls_content-type = -value. + + READ TABLE lt_fields ASSIGNING WITH KEY name = 'value'. + ASSERT sy-subrc = 0. + ls_content-value = -value. + + READ TABLE lt_fields ASSIGNING WITH KEY name = 'xmldata'. + ASSERT sy-subrc = 0. + ls_content-data = -value+1. " hmm + + CREATE OBJECT lo_db. + + lo_db->update( + iv_type = ls_content-type + iv_value = ls_content-value + iv_data = ls_content-data ). + + COMMIT WORK. + + lcl_gui=>back( ). + + ENDMETHOD. + + METHOD lif_gui_page~on_event. + + CASE iv_action. + WHEN 'back'. + COMMIT WORK. " release lock + lcl_gui=>back( ). + WHEN 'post'. + save( it_postdata ). + WHEN OTHERS. + _raise 'Unknown action'. + ENDCASE. + + ENDMETHOD. + + METHOD lif_gui_page~render. + + DATA: lv_data TYPE lcl_persistence_db=>ty_content-data, + lo_db TYPE REF TO lcl_persistence_db. + + + CREATE OBJECT lo_db. + TRY. + lv_data = lo_db->read( + iv_type = ms_key-type + iv_value = ms_key-value ). + CATCH lcx_not_found. + ENDTRY. + + lo_db->lock( + iv_type = ms_key-type + iv_value = ms_key-value ). + + lv_data = lcl_xml_pretty=>print( lv_data ). + + lv_data = escape( val = lv_data + format = cl_abap_format=>e_html_attr ). + + rv_html = lcl_gui=>header( ) && gc_newline && + '

Edit

' && gc_newline && + 'Back

' && gc_newline && + 'Type:
' && gc_newline && + ms_key-type && '

' && gc_newline && + 'Value:
' && gc_newline && + ms_key-value && '

' && gc_newline && + 'Data:
' && gc_newline && + '
' && gc_newline && + '' && gc_newline && + '' && gc_newline && + '
' && gc_newline && + lcl_gui=>footer( ). + + ENDMETHOD. + +ENDCLASS. + +CLASS lcl_gui_page_db IMPLEMENTATION. + + METHOD delete. + + DATA: lo_db TYPE REF TO lcl_persistence_db, + lv_continue TYPE abap_bool. + + + lv_continue = delete_popup( ). + IF lv_continue = abap_false. + RETURN. + ENDIF. + + CREATE OBJECT lo_db. + + lo_db->delete( iv_type = is_key-type + iv_value = is_key-value ). + + COMMIT WORK. + + lcl_gui=>render( ). + + ENDMETHOD. + + METHOD delete_popup. + + DATA: lv_answer TYPE c LENGTH 1. + + + CALL FUNCTION 'POPUP_TO_CONFIRM' + EXPORTING + titlebar = 'Warning' + text_question = 'Delete?' + text_button_1 = 'Ok' + icon_button_1 = 'ICON_DELETE' + text_button_2 = 'Cancel' + icon_button_2 = 'ICON_CANCEL' + default_button = '2' + display_cancel_button = abap_false + IMPORTING + answer = lv_answer + EXCEPTIONS + text_not_found = 1 + OTHERS = 2. "#EC NOTEXT + IF sy-subrc <> 0. + _raise 'error from POPUP_TO_CONFIRM'. + ENDIF. + + IF lv_answer <> '2'. + rv_continue = abap_true. + ELSE. + rv_continue = abap_false. + ENDIF. + + ENDMETHOD. + + METHOD key_encode. + + DATA: lt_fields TYPE tihttpnvp, + ls_field LIKE LINE OF lt_fields. + + + ls_field-name = 'TYPE'. + ls_field-value = is_key-type. + APPEND ls_field TO lt_fields. + + ls_field-name = 'VALUE'. + ls_field-value = is_key-value. + APPEND ls_field TO lt_fields. + + rv_string = cl_http_utility=>if_http_utility~fields_to_string( lt_fields ). + + ENDMETHOD. + + METHOD key_decode. + + DATA: lt_fields TYPE tihttpnvp, + lv_string TYPE string. + + FIELD-SYMBOLS: LIKE LINE OF lt_fields. + + + lv_string = iv_string. " type conversion + lt_fields = cl_http_utility=>if_http_utility~string_to_fields( lv_string ). + + READ TABLE lt_fields ASSIGNING WITH KEY name = 'TYPE'. + IF sy-subrc = 0. + rs_key-type = -value. + ENDIF. + + READ TABLE lt_fields ASSIGNING WITH KEY name = 'VALUE'. + IF sy-subrc = 0. + rs_key-value = -value. + ENDIF. + + ENDMETHOD. + + METHOD lif_gui_page~on_event. + + DATA: lo_display TYPE REF TO lcl_gui_page_display, + lo_edit TYPE REF TO lcl_gui_page_edit, + ls_key TYPE lcl_persistence_db=>ty_content. + + + ls_key = key_decode( iv_getdata ). + + CASE iv_action. + WHEN 'display'. + CREATE OBJECT lo_display + EXPORTING + is_key = ls_key. + lcl_gui=>call_page( lo_display ). + WHEN 'edit'. + CREATE OBJECT lo_edit + EXPORTING + is_key = ls_key. + lcl_gui=>call_page( lo_edit ). + WHEN 'delete'. + delete( ls_key ). + WHEN OTHERS. + _raise 'Unknown action'. + ENDCASE. + + ENDMETHOD. + + METHOD lif_gui_page~render. + + DATA: lt_data TYPE lcl_persistence_db=>tt_content, + lv_escaped TYPE string, + lv_encode TYPE string, + lo_db TYPE REF TO lcl_persistence_db. + + FIELD-SYMBOLS: LIKE LINE OF lt_data. + + + CREATE OBJECT lo_db. + lt_data = lo_db->list( ). + + rv_html = lcl_gui=>header( ) && gc_newline && + '

Database persistency

' && gc_newline && + '

' && gc_newline && + '' && gc_newline && + '' && gc_newline && + '' && gc_newline && + '' && gc_newline && + '' && gc_newline && + '' && gc_newline. + + LOOP AT lt_data ASSIGNING . + lv_escaped = escape( val = -data(150) + format = cl_abap_format=>e_html_attr ). + + lv_encode = key_encode( ). + + rv_html = rv_html && '' && gc_newline && + '' && gc_newline && + '' && gc_newline && + '' && gc_newline && + '' && gc_newline. + ENDLOOP. + + rv_html = rv_html && '
TypeValueData
' && -type && '' && -value && '
' && lv_escaped && '
' && gc_newline && + '

' && gc_newline && + 'Display' && gc_newline && + 'Edit' && gc_newline && + 'Delete
' && lcl_gui=>footer( ). + + ENDMETHOD. + +ENDCLASS. \ No newline at end of file