otgr: initial object support (#3777)

* otgr: initial object support

This commit replaces the generic SOBJ support with native support for
the object type OTGR and the format is not backward compatible,
so repos containing SOBJ serialized objects could not be pulled anymore
(it's necessary to pull them with previous version of abapGit and push
them with the new version of abapGit).

The new OTGR handler supports only master language description because
there is no API which would allow us to maintain other languages and
I am not willing to re-implement parts of ABAP platform just to version
texts which nobody cares about. Also, the texts dealing part is not
that straightforward - one has to think about keeping the texts
in sync which requires lot of code.

I did the following optimizations to the XML format:
- removed the activation state from all elements because we
  always serialize only Active and deserialize as Inactive
- removed the foreign key name from texts and other details
  because we know which object type group is currently being handled
- used short names for root elements of details to avoid redundancy
  because the detail's table name is used for child XML elements -
  e.g. TEXTS vs. CLS_TYPE_GROUPT.

Closes #1515

* Update ref-supported.md

Co-authored-by: Lars Hvam <larshp@hotmail.com>
This commit is contained in:
Jakub Filak 2020-08-24 11:23:36 +02:00 committed by GitHub
parent e4bafbe715
commit 65e8522bd1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 324 additions and 1 deletions

View File

@ -76,7 +76,7 @@ MSAG | Message Class | Yes
NROB | Number Range Objects | Yes NROB | Number Range Objects | Yes
OA2P | OAuth2 Profile | Yes OA2P | OAuth2 Profile | Yes
ODSO | DataStore Object | Yes ODSO | DataStore Object | Yes
OTGR | Object type group | [#1515](https://github.com/larshp/abapGit/issues/1515) OTGR | Object type group | Yes
PARA | SPA/GPA Parameters | Yes PARA | SPA/GPA Parameters | Yes
PDTS | Standard Task | [#153](https://github.com/larshp/abapGit/issues/153) PDTS | Standard Task | [#153](https://github.com/larshp/abapGit/issues/153)
PDWS | Workflow templates | [#154](https://github.com/larshp/abapGit/issues/154) PDWS | Workflow templates | [#154](https://github.com/larshp/abapGit/issues/154)

View File

@ -0,0 +1,307 @@
CLASS zcl_abapgit_object_otgr DEFINITION
PUBLIC
INHERITING FROM zcl_abapgit_objects_super
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES zif_abapgit_object .
PROTECTED SECTION.
PRIVATE SECTION.
TYPES:
BEGIN OF ty_otgr,
cls_type_group TYPE cls_type_group,
texts TYPE STANDARD TABLE OF cls_type_groupt WITH DEFAULT KEY,
elements TYPE STANDARD TABLE OF cls_tygr_element WITH DEFAULT KEY,
parents TYPE STANDARD TABLE OF cls_tygr_parent WITH DEFAULT KEY,
END OF ty_otgr .
METHODS instantiate_and_lock_otgr
RETURNING
VALUE(ro_otgr) TYPE REF TO cl_cls_object_type_group
RAISING
zcx_abapgit_exception .
ENDCLASS.
CLASS zcl_abapgit_object_otgr IMPLEMENTATION.
METHOD instantiate_and_lock_otgr.
DATA: lv_new TYPE abap_bool,
lv_name TYPE cls_attribute_name.
SELECT SINGLE name FROM cls_type_group INTO lv_name WHERE name = ms_item-obj_name.
lv_new = boolc( sy-subrc <> 0 ).
lv_name = ms_item-obj_name.
TRY.
CREATE OBJECT ro_otgr
EXPORTING
im_name = lv_name
im_new = lv_new
im_activation_state = cl_pak_wb_domains=>co_activation_state-active.
CATCH cx_pak_invalid_data
cx_pak_not_authorized
cx_pak_invalid_state
cx_pak_wb_object_locked.
zcx_abapgit_exception=>raise( |OTGR { lv_name }: error while instantiating CL_CLS_OBJECT_TYPE_GROUP| ).
ENDTRY.
IF lv_new = abap_false.
TRY.
ro_otgr->if_pak_wb_object~lock_and_refresh( ).
CATCH cx_pak_invalid_data
cx_pak_not_authorized
cx_pak_invalid_state
cx_pak_wb_object_locked.
zcx_abapgit_exception=>raise( |OTGR { lv_name }: could not aquire lock| ).
ENDTRY.
ENDIF.
ENDMETHOD.
METHOD zif_abapgit_object~changed_by.
SELECT SINGLE changed_by FROM cls_type_group INTO rv_user
WHERE name = ms_item-obj_name
AND activation_state = cl_pak_wb_domains=>co_activation_state-active.
IF rv_user IS INITIAL.
SELECT SINGLE created_by FROM cls_type_group INTO rv_user
WHERE name = ms_item-obj_name
AND activation_state = cl_pak_wb_domains=>co_activation_state-active.
ENDIF.
IF rv_user IS INITIAL.
rv_user = c_user_unknown.
ENDIF.
ENDMETHOD.
METHOD zif_abapgit_object~delete.
DATA: lo_otgr TYPE REF TO cl_cls_object_type_group,
lx_pak_error TYPE REF TO cx_root,
lv_text TYPE string.
lo_otgr = instantiate_and_lock_otgr( ).
TRY.
lo_otgr->if_pak_wb_object~delete( ).
lo_otgr->if_pak_wb_object~save( ).
lo_otgr->unlock( ).
CATCH cx_pak_invalid_state cx_pak_invalid_data cx_pak_not_authorized INTO lx_pak_error.
lo_otgr->unlock( ).
lv_text = lx_pak_error->get_text( ).
zcx_abapgit_exception=>raise( |OTGR { ms_item-obj_name }: delete: { lv_text }| ).
ENDTRY.
ENDMETHOD.
METHOD zif_abapgit_object~deserialize.
DATA: ls_otgr TYPE ty_otgr,
lo_otgr TYPE REF TO cl_cls_object_type_group,
lx_pak_error TYPE REF TO cx_root,
lv_text TYPE string,
lv_masterlang TYPE sylangu.
FIELD-SYMBOLS: <ls_groupt> LIKE LINE OF ls_otgr-texts,
<ls_element> LIKE LINE OF ls_otgr-elements,
<ls_parent> LIKE LINE OF ls_otgr-parents.
io_xml->read( EXPORTING iv_name = 'OTGR'
CHANGING cg_data = ls_otgr ).
LOOP AT ls_otgr-texts ASSIGNING <ls_groupt>.
<ls_groupt>-activation_state = cl_pak_wb_domains=>co_activation_state-inactive.
" Removed in the method serialize.
<ls_groupt>-name = ms_item-obj_name.
ENDLOOP.
LOOP AT ls_otgr-parents ASSIGNING <ls_parent>.
<ls_parent>-activation_state = cl_pak_wb_domains=>co_activation_state-inactive.
" Removed in the method serialize.
<ls_parent>-obj_type_group = ms_item-obj_name.
ENDLOOP.
LOOP AT ls_otgr-elements ASSIGNING <ls_element>.
<ls_element>-activation_state = cl_pak_wb_domains=>co_activation_state-inactive.
" Removed in the method serialize.
<ls_element>-obj_type_group = ms_item-obj_name.
ENDLOOP.
tadir_insert( iv_package ).
lo_otgr = instantiate_and_lock_otgr( ).
TRY.
lo_otgr->if_cls_object_type_group~set_proxy_filter( ls_otgr-cls_type_group-proxy_flag ).
lo_otgr->if_cls_object_type_group~set_elements( ls_otgr-elements ).
lo_otgr->if_cls_object_type_group~set_parent_groups( ls_otgr-parents ).
lv_masterlang = lo_otgr->if_pak_wb_object~get_master_language( ).
READ TABLE ls_otgr-texts WITH KEY langu = lv_masterlang ASSIGNING <ls_groupt>.
IF sy-subrc = 0.
lo_otgr->set_description( <ls_groupt>-text ).
" ELSE.
" Do we want to clear the master language description if not present in the XML conent?
" Master Language is non-deterministic - it depends on sy-langu, so rather don't touch
" description if the master language is not present
" Perhaps, we can display some sort of a message but how?
ENDIF.
set_default_package( iv_package ).
lo_otgr->if_pak_wb_object~save( ).
lo_otgr->if_pak_wb_object~activate( ).
lo_otgr->unlock( ).
CATCH cx_pak_invalid_state cx_pak_invalid_data cx_pak_not_authorized INTO lx_pak_error.
lo_otgr->unlock( ).
lv_text = lx_pak_error->get_text( ).
zcx_abapgit_exception=>raise( |OTGR { ms_item-obj_name }: deserialize: { lv_text }| ).
ENDTRY.
ENDMETHOD.
METHOD zif_abapgit_object~exists.
rv_bool = cl_cls_object_type_group=>exists_object_type_group( ms_item-obj_name ).
ENDMETHOD.
METHOD zif_abapgit_object~get_comparator.
RETURN.
ENDMETHOD.
METHOD zif_abapgit_object~get_deserialize_steps.
APPEND zif_abapgit_object=>gc_step_id-abap TO rt_steps.
ENDMETHOD.
METHOD zif_abapgit_object~get_metadata.
rs_metadata = get_metadata( ).
ENDMETHOD.
METHOD zif_abapgit_object~is_active.
rv_active = is_active( ).
ENDMETHOD.
METHOD zif_abapgit_object~is_locked.
rv_is_locked = exists_a_lock_entry_for( iv_lock_object = 'ECLS_ATTRIBUTE'
iv_argument = |{ ms_item-obj_name }*| ).
ENDMETHOD.
METHOD zif_abapgit_object~jump.
CALL FUNCTION 'RS_TOOL_ACCESS'
EXPORTING
operation = 'SHOW'
object_name = ms_item-obj_name
object_type = ms_item-obj_type
EXCEPTIONS
not_executed = 1
invalid_object_type = 2
OTHERS = 3.
IF sy-subrc <> 0.
zcx_abapgit_exception=>raise( |Error from RS_TOOL_ACCESS, CHAR| ).
ENDIF.
ENDMETHOD.
METHOD zif_abapgit_object~serialize.
DATA: lv_text TYPE string,
ls_otgr TYPE ty_otgr,
lo_otgr TYPE REF TO cl_cls_object_type_group,
lt_lang_sel TYPE RANGE OF langu,
ls_lang_sel LIKE LINE OF lt_lang_sel,
lx_pak_error TYPE REF TO cx_root.
FIELD-SYMBOLS: <ls_groupt> LIKE LINE OF ls_otgr-texts,
<ls_element> LIKE LINE OF ls_otgr-elements,
<ls_parent> LIKE LINE OF ls_otgr-parents.
lo_otgr = instantiate_and_lock_otgr( ).
* Description part 1:
* Dealing with Description of OTGR objects is problematic.
* The API supports setting of Master Language only and
* if we want to save also translations we would have to implement
* our own logic for merging and activation. To keep it simple stupid
* the current version focuses on the Master language only.
* If anybody ever runs into the need to version also translation,
* ask the maintainers of CL_CLS_OBJECT_TYPE_GROUP to add a method for it.
*
* However, the XML content will pretend we support also translations,
* so if someone adds support for them in future, there will be no format change.
APPEND INITIAL LINE TO ls_otgr-texts ASSIGNING <ls_groupt>.
TRY.
ls_otgr-cls_type_group-name = lo_otgr->if_cls_object_type_group~get_name( ).
ls_otgr-cls_type_group-proxy_flag = lo_otgr->if_cls_object_type_group~get_proxy_filter( ).
lo_otgr->get_elements( IMPORTING ex_elements = ls_otgr-elements ).
lo_otgr->if_cls_object_type_group~get_parent_groups(
EXPORTING
im_explicit_parents_only = abap_true
IMPORTING
ex_parent_groups = ls_otgr-parents ).
" Beware: the following method returns the Master Language description only if the object is Locked!
<ls_groupt>-text = lo_otgr->if_cls_object_type_group~get_description( ).
<ls_groupt>-langu = lo_otgr->if_pak_wb_object~get_master_language( ).
lo_otgr->unlock( ).
CATCH cx_pak_invalid_state cx_pak_invalid_data cx_pak_not_authorized INTO lx_pak_error.
lo_otgr->unlock( ).
lv_text = lx_pak_error->get_text( ).
zcx_abapgit_exception=>raise( |OTGR { ms_item-obj_name }: serialize: { lv_text }| ).
ENDTRY.
CLEAR: ls_otgr-cls_type_group-created_by,
ls_otgr-cls_type_group-created_on,
ls_otgr-cls_type_group-changed_by,
ls_otgr-cls_type_group-changed_on.
* Description part 2:
*
* IF io_xml->i18n_params( )-serialize_master_lang_only = abap_true.
* ls_lang_sel-low = mv_language.
* ls_lang_sel-sign = 'I'.
* ls_lang_sel-option = 'EQ'.
* ENDIF.
*
* SELECT * FROM cls_type_groupt INTO TABLE ls_otgr-texts
* WHERE name = ms_item-obj_name
* AND activation_state = 'A'
* AND langu in lt_lang_sel.
*
* Description ideas end
LOOP AT ls_otgr-texts ASSIGNING <ls_groupt>.
" Not necessary as we serialize only Active
CLEAR <ls_groupt>-activation_state.
" Not necessary as we have it in the root XML node
CLEAR <ls_groupt>-name.
ENDLOOP.
LOOP AT ls_otgr-elements ASSIGNING <ls_element>.
" Not necessary as we serialize only Active
CLEAR <ls_element>-activation_state.
" Not necessary as we have it in the root XML node
CLEAR <ls_element>-obj_type_group.
ENDLOOP.
LOOP AT ls_otgr-parents ASSIGNING <ls_parent>.
" Not necessary as we serialize only Active
CLEAR <ls_parent>-activation_state.
" Not necessary as we have it in the root XML node
CLEAR <ls_parent>-obj_type_group.
ENDLOOP.
io_xml->add( iv_name = 'OTGR'
ig_data = ls_otgr ).
ENDMETHOD.
ENDCLASS.

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<abapGit version="v1.0.0" serializer="LCL_OBJECT_CLAS" serializer_version="v1.0.0">
<asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
<asx:values>
<VSEOCLASS>
<CLSNAME>ZCL_ABAPGIT_OBJECT_OTGR</CLSNAME>
<LANGU>E</LANGU>
<DESCRIPT>OTGR</DESCRIPT>
<STATE>1</STATE>
<CLSCCINCL>X</CLSCCINCL>
<FIXPT>X</FIXPT>
<UNICODE>X</UNICODE>
</VSEOCLASS>
</asx:values>
</asx:abap>
</abapGit>