* This class is intended to provide generic serialization based on SOBJ-definitions. * For developers inheriting from this class: BE AWARE: This class will directly insert into * and delete dynamically from the object's metadata-tables. * Though this has been tested and is based upon code developed by SAP for a similar purpose, * this is a risky operation. Please do verify the where-statements generated by the XML-bridge * for correctness of your dedicated object-type! * No risk, no fun. CLASS zsaplink_generic_obj DEFINITION PUBLIC INHERITING FROM zsaplink ABSTRACT CREATE PUBLIC . PUBLIC SECTION. METHODS constructor IMPORTING !name TYPE string include_last_changed type abap_bool OPTIONAL. METHODS checkexists REDEFINITION . METHODS createixmldocfromobject REDEFINITION . METHODS createobjectfromixmldoc REDEFINITION . PROTECTED SECTION. TYPES: BEGIN OF ty_s_tlogo_tables, tabname TYPE ddobjname, where_clause TYPE string, data TYPE REF TO data, END OF ty_s_tlogo_tables . TYPES: ty_t_tlogo_tables TYPE SORTED TABLE OF ty_s_tlogo_tables WITH UNIQUE KEY tabname . METHODS add_table_metadata IMPORTING !io_ixmldocument TYPE REF TO if_ixml_document !io_root_node TYPE REF TO if_ixml_element . METHODS serialize_table_content IMPORTING !io_ixmldocument TYPE REF TO if_ixml_document !io_root_node TYPE REF TO if_ixml_element RAISING zcx_saplink . METHODS update_db_table_content IMPORTING !i_ixmldocument TYPE REF TO if_ixml_document RAISING zcx_saplink . METHODS deleteobject REDEFINITION . PRIVATE SECTION. DATA mo_xml_bridge TYPE REF TO lcl_tlogo_xml_bridge . data include_last_changed type abap_bool. CONSTANTS co_xml_metadata TYPE string VALUE 'objMetaData' ##NO_TEXT. METHODS get_xml_bridge RETURNING VALUE(ro_xml_bridge) TYPE REF TO lcl_tlogo_xml_bridge . METHODS metadata_to_xml IMPORTING !it_metadata TYPE lcl_tlogo_xml_bridge=>tt_obj_metadata RETURNING VALUE(ro_metadata_element) TYPE REF TO if_ixml_element . METHODS xml_to_metadata IMPORTING !io_metadata_element TYPE REF TO if_ixml_element RETURNING VALUE(rt_metadata) TYPE lcl_tlogo_xml_bridge=>tt_obj_metadata . METHODS validate_metadata IMPORTING !it_metadata TYPE lcl_tlogo_xml_bridge=>tt_obj_metadata RAISING zcx_saplink . ENDCLASS. CLASS ZSAPLINK_GENERIC_OBJ IMPLEMENTATION. METHOD add_table_metadata. * add the table's metdata DATA(lt_metadata) = get_xml_bridge( )->get_table_metadata( CONV #( me->objname ) ). * encapsulate the simple transformation metadata-table-element to have a fixed name DATA(lo_md_element) = io_ixmldocument->create_element( co_xml_metadata ). lo_md_element->append_child( me->metadata_to_xml( lt_metadata ) ). io_root_node->append_child( lo_md_element ). ENDMETHOD. METHOD checkexists. exists = me->get_xml_bridge( )->exists( CONV #( objname ) ). ENDMETHOD. METHOD constructor. */---------------------------------------------------------------------\ *| This file is part of SAPlink. | *| | *| SAPlink is free software; you can redistribute it and/or modify | *| it under the terms of the GNU General Public License as published | *| by the Free Software Foundation; either version 2 of the License, | *| or (at your option) any later version. | *| | *| SAPlink is distributed in the hope that it will be useful, | *| but WITHOUT ANY WARRANTY; without even the implied warranty of | *| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | *| GNU General Public License for more details. | *| | *| You should have received a copy of the GNU General Public License | *| along with SAPlink; if not, write to the | *| Free Software Foundation, Inc., | *| 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | *\---------------------------------------------------------------------/ super->constructor( name = name ). me->include_last_changed = include_last_changed. ENDMETHOD. METHOD createixmldocfromobject. * convention by saplink: The root element has to be named with the OBJTYPE, * the first attribute of the root node denotes the objname DATA lo_root_node TYPE REF TO if_ixml_element. ixmldocument = ixml->create_document( ). lo_root_node = ixmldocument->create_element( me->getobjecttype( ) ). lo_root_node->set_attribute( name = 'objname' " NAME value = objname ). serialize_table_content( io_ixmldocument = ixmldocument io_root_node = lo_root_node ). add_table_metadata( io_ixmldocument = ixmldocument io_root_node = lo_root_node ). ixmldocument->append_child( lo_root_node ). ENDMETHOD. METHOD createobjectfromixmldoc. * validate the metadata of the underlying DB tables * As insert/update/delete to a table is being performed, the table structure actually * defines an interface. The compatibility of this interface has to be validated prior * to consuming it DATA(lo_obj_metadata_elem) = ixmldocument->get_elements_by_tag_name( name = co_xml_metadata )->get_item( 0 ). IF lo_obj_metadata_elem IS INITIAL. BREAK-POINT. "this seems to be an old file-format where no consistency between the tables can be checked. * => proceed only if you know what you're doing and jump over the next statement. RAISE EXCEPTION TYPE zcx_saplink EXPORTING textid = zcx_saplink=>error_message msg = 'Old (unsupported) format'. ELSE. DATA(lt_obj_metadata) = me->xml_to_metadata( CAST #( lo_obj_metadata_elem->get_first_child( ) ) ). me->validate_metadata( lt_obj_metadata ). ENDIF. * write the content serialized in the XML document into the DB tables update_db_table_content( ixmldocument ). ENDMETHOD. METHOD deleteobject. "do not do anything - the update of the object implicitly deletes obsolete entries ASSERT 1 = 1. RETURN. * there is an opportunity to explicitly purge all tables with the corresponding keys, * but this is actually not necessary (and quite a critical operation). get_xml_bridge( )->delete_object( CONV #( objname ) ). ENDMETHOD. METHOD get_xml_bridge. IF mo_xml_bridge IS INITIAL. * can't be called in the constructor as getObjectType is intended to be polymorphic mo_xml_bridge = NEW lcl_tlogo_xml_bridge( i_tlogo = CONV #( me->getobjecttype( ) ) iv_include_last_changed = me->include_last_changed ). ENDIF. ro_xml_bridge = mo_xml_bridge. ENDMETHOD. METHOD metadata_to_xml. DATA(lo_document_md) = ixml->create_document( ). CALL TRANSFORMATION id SOURCE metadata = it_metadata RESULT XML lo_document_md. ro_metadata_element = lo_document_md->get_root_element( ). ENDMETHOD. METHOD serialize_table_content. * read table content to XML IF get_xml_bridge( )->exists( CONV #( me->objname ) ) = abap_false. RAISE EXCEPTION TYPE zcx_saplink EXPORTING textid = zcx_saplink=>not_found. ENDIF. get_xml_bridge( )->compose_xml( EXPORTING i_objnm = CONV #( me->objname ) " Object name in object directory IMPORTING e_string_xml = DATA(lv_string_xml) " XML Data ). DATA(lo_xml_bridge_document) = convertstringtoixmldoc( xmlstring = lv_string_xml ). io_root_node->append_child( lo_xml_bridge_document->get_root_element( ) ). ENDMETHOD. METHOD update_db_table_content. * unpack the actual document from the saplink-specific wrapper DATA(lo_xml_bridge_transport_elem) = i_ixmldocument->get_elements_by_tag_name( name = CONV #( lcl_tlogo_xml_bridge=>p_c_xml_tag_transport ) )->get_item( 0 ). IF lo_xml_bridge_transport_elem IS INITIAL. RAISE EXCEPTION TYPE zcx_saplink EXPORTING textid = zcx_saplink=>incorrect_file_format msg = 'No object data found'. ELSE. DATA(lo_xml_bridge_document) = cl_ixml=>create( )->create_document( ). lo_xml_bridge_document->append_child( lo_xml_bridge_transport_elem ). ENDIF. * during existence check, a sanity check is being performed (that not more than one entry in the * primary table is affected). Thus, issue an existence check without evaluating the result get_xml_bridge( )->exists( CONV #( me->objname ) ). get_xml_bridge( )->parse_xml( EXPORTING i_objnm = CONV #( me->objname ) " Object name in object directory i_string_xml = convertixmldoctostring( lo_xml_bridge_document ) " String with XML Data IMPORTING e_subrc = DATA(lv_subrc_parsing) " Return Value, Return Value After ABAP Statements ). IF lv_subrc_parsing IS INITIAL. get_xml_bridge( )->save( IMPORTING e_subrc = DATA(lv_subrc_save) ). IF lv_subrc_save IS INITIAL. * perform after import methods get_xml_bridge( )->activate( ). ELSE. RAISE EXCEPTION TYPE zcx_saplink EXPORTING textid = zcx_saplink=>error_message msg = |An error occurred when saving { objname }. Check Application log Object { cl_rso_repository=>p_c_bal_log_object }|. ENDIF. ELSE. RAISE EXCEPTION TYPE zcx_saplink EXPORTING textid = zcx_saplink=>error_message msg = 'Object could not be identified in source'. ENDIF. ENDMETHOD. METHOD validate_metadata. * this method checks whether the metadata of the tables of the transport object * substantially differ between the object serialized and the current system. * This is necessary as the DB-table is treated as interface in this tool * all the tables which are filled in the source need to exist locally with all fields from * the source system existing with the same technical datatype locally as well DEFINE exception_metadata. RAISE EXCEPTION TYPE zcx_saplink EXPORTING textid = zcx_saplink=>error_message msg = 'Database structure differs. Object cannot be imported.'. END-OF-DEFINITION. LOOP AT it_metadata ASSIGNING FIELD-SYMBOL() WHERE count > 0. "only the relevant tables need to be validated DATA lt_dfies TYPE dfies_table. * get the DDIC info of the local table structure CALL FUNCTION 'DDIF_NAMETAB_GET' EXPORTING tabname = CONV ddobjname( -db_table ) TABLES dfies_tab = lt_dfies EXCEPTIONS not_found = 1. ASSERT sy-subrc = 0. * compare the fields-information which is relevant to technical compatibility. LOOP AT -fields_definition ASSIGNING FIELD-SYMBOL(). READ TABLE lt_dfies ASSIGNING FIELD-SYMBOL() WITH KEY fieldname = -fieldname. IF sy-subrc NE 0. exception_metadata. ENDIF. IF -datatype NE -datatype OR -inttype NE -inttype. exception_metadata. ENDIF. IF -leng NE -leng. "-intlen NE -intlen. Does not have to be the same when transporting between unicode and non-unicode-systems exception_metadata. ENDIF. IF -decimals NE -decimals. exception_metadata. ENDIF. ENDLOOP. ENDLOOP. ENDMETHOD. METHOD xml_to_metadata. DATA(lo_document_md) = ixml->create_document( ). lo_document_md->append_child( io_metadata_element ). CALL TRANSFORMATION id SOURCE XML lo_document_md RESULT metadata = rt_metadata . ENDMETHOD. ENDCLASS.