0.1. 在数据库中动态创建、使用、删除程序
在SAP数据库中动态生成程序,调用后删除(该程序没有分配到包)
REPORT z14143_13.
"创建report
DATA: code TYPE TABLE OF string,
prgnm(10) TYPE c VALUE 'ZTEST_SUB',
lw_string TYPE string.
* form the dynamic-program
CONCATENATE 'PROGRAM' prgnm '.' INTO lw_string SEPARATED BY space.
APPEND lw_string TO code.
APPEND 'WRITE:/10 ''Hello, this is the transient program!''.' TO code.
INSERT REPORT prgnm FROM code."通过内表code创建report
* call the transiet program
SUBMIT (prgnm) AND RETURN."执行程序
* append the transient program
READ REPORT prgnm INTO code."读取report到内表code
APPEND 'WRITE:/10 ''Hello, this is the transient program! 2nd Time append.''.' TO code.
INSERT REPORT prgnm FROM code."通过内表code重写report
SUBMIT (prgnm) AND RETURN."再次执行程序
DELETE REPORT prgnm."删除程序
0.2. 动态临时子程序
0.2.1. 动态子例程
REPORT z14143_13.
DATA:
code TYPE TABLE OF string,
subrtnm(10) TYPE c VALUE 'TEST',
prog TYPE program,
msg(20) TYPE c,
line(10) TYPE c,
word(10) TYPE c,
off(3) TYPE c,
lw_string TYPE string,
sid TYPE string.
* prepare the ”Dynamic Subroutine sentence”
APPEND 'PROGRAM SUBPOOL.' TO code.
CONCATENATE 'FORM' subrtnm '.' INTO lw_string SEPARATED BY space.
APPEND lw_string TO code.
APPEND 'Write:/10 ''This is one transient subroutine''.' TO code.
APPEND 'ENDFORM.' TO code.
* create subroutine dynamically
GENERATE SUBROUTINE POOL code NAME prog MESSAGE msg LINE line WORD word OFFSET off SHORTDUMP-ID sid. "生成子程序
IF sy-subrc = 0.
PERFORM (subrtnm) IN PROGRAM (prog) IF FOUND.
ELSEIF sy-subrc = 4.
WRITE:/ 'Error occurs in line:',line, / msg, /'Word:', word, / 'Offset:', off.
ELSEIF sy-subrc = 8.
MESSAGE sid TYPE 'I'.
ENDIF.
0.2.2. 动态类
0.2.2.1. 静态方法的类
DATA itab TYPE TABLE OF string.
DATA prog TYPE string.
DATA class TYPE string.
APPEND: `program.` TO itab,
`class main definition.` TO itab,
` public section.` TO itab,
` class-methods: meth,meth2.` TO itab,
`endclass.` TO itab,
`class main implementation.` TO itab,
` method meth.` TO itab,
` message 'Test' type 'I'.` TO itab,
` endmethod.` TO itab,
` method meth2.` TO itab,
` message 'Test2' type 'I'.` TO itab,
` endmethod.` TO itab,
`endclass.` TO itab.
GENERATE SUBROUTINE POOL itab NAME prog.
CONCATENATE `\PROGRAM=` prog `\CLASS=MAIN` INTO class.
CALL METHOD (class)=>meth2.
0.2.2.2. 实例方法的类
DATA itab TYPE TABLE OF string.
DATA prog TYPE string.
DATA class TYPE string.
DATA oref TYPE REF TO object.
APPEND: `program.` TO itab,
`class main definition.` TO itab,
` public section.` TO itab,
` methods meth.` TO itab,
`endclass.` TO itab,
`class main implementation.` TO itab,
` method meth.` TO itab,
` message 'Test' type 'I'.` TO itab,
` endmethod.` TO itab,
`endclass.` TO itab.
GENERATE SUBROUTINE POOL itab NAME prog.
CONCATENATE `\PROGRAM=` prog `\CLASS=MAIN` INTO class.
CREATE OBJECT oref TYPE (class).
CALL METHOD (class)=>meth.
1. SAP动态RFC
1.1. 动态类测试DEMO
1.1.1. 正常的方式创建一个类并调用
CLASS rfccallDEFINITION.
PUBLICSECTION.
CLASS-METHODS:method1
IMPORTING
method1input1 TYPE i
method1input2 TYPE i
EXPORTING
method1output1 TYPE i
method1output2 TYPE i,
method2 IMPORTING
method2input1 TYPE i
method2input2 TYPE i
EXPORTING
method2output1 TYPE string.
ENDCLASS.
CLASS rfccall IMPLEMENTATION.
METHOD method1.
method1output1 = method1input1 + method1input2.
method1output2 = method1input1 * method1input2.
ENDMETHOD.
METHOD method2.
method2output1 = method2input1 && method2input2.
ENDMETHOD.
ENDCLASS.
START-OF-SELECTION.
DATA: liTYPE i,
lm TYPEi,
ls TYPEstring.
call METHOD rfccall=>method1
EXPORTING
method1input1 =1
method1input2 =2
IMPORTING
method1output1 =li
method1output2 =lm.
CALL METHOD rfccall=>method2
EXPORTING
method2input1 =1
method2input2 =2
IMPORTING
method2output1 =ls.
1.1.2. 动态构造类、方法,动态调用
TYPES BEGIN OF transtru.
TYPES datatype TYPE char36.
TYPES dataname TYPE char36.
TYPES datavalue TYPE char36.
TYPES END OF transtru.
DATA BEGIN OF ls_rfcparameter.
DATA methodname TYPE char36.
DATA inputdata TYPE TABLE OF transtru.
DATA outputdata TYPE TABLE OF transtru.
DATA body TYPE string.
DATA END OF ls_rfcparameter.
DATA lt_classmethod LIKE TABLE OF ls_rfcparameter.
DATA: inputstring TYPE string,
outputstr TYPE string,
codestr TYPE TABLE OF string WITH HEADER LINE,
bodystr TYPE TABLE OF string WITH HEADER LINE.
DATA prog TYPE string.
DATA: ptab TYPE abap_parmbind_tab,
etab TYPE abap_excpbind_tab.
inputstring = '{"METHODS":[{"METHODNAME":"METHOD1","INPUTDATA":[{"DATATYPE":"CHAR36","DATANAME":"METHOD1INPUT1","DATAVALUE":"1"}' &&
',{"DATATYPE":"CHAR36","DATANAME":"METHOD1INPUT2","DATAVALUE":"2"}],"OUTPUTDATA":[{"DATATYPE":"CHAR36","DATANAME":"METHOD1OUTPUT1"}' &&
',{"DATATYPE":"CHAR36","DATANAME":"METHOD1OUTPUT2"}],"BODY":"METHOD1OUTPUT1 = METHOD1INPUT1 +' &&
' METHOD1INPUT2.METHOD1OUTPUT2 = METHOD1INPUT1 * METHOD1INPUT2."},{"METHODNAME":"METHOD2","INPUTDATA"' &&
':[{"DATATYPE":"CHAR36","DATANAME":"METHOD2INPUT1","DATAVALUE":"1"},{"DATATYPE":"CHAR36","DATANAME":"METHOD2INPUT2","DATAVALUE":"2"}],"OUTPUTDATA"' &&
':[{"DATATYPE":"CHAR36","DATANAME":"METHOD2OUTPUT1"}],"BODY":"METHOD2OUTPUT1 = METHOD2INPUT1 && METHOD2INPUT2."}]}'.
CALL TRANSFORMATION id SOURCE XML inputstring RESULT methods = lt_classmethod.
codestr[] = VALUE #( ( `PROGRAM.` ) ( `CLASS MAIN DEFINITION.` ) ( ` PUBLIC SECTION.` ) ( ` CLASS-METHODS: ` ) ).
* 动态定义所有类方法
CLEAR codestr.
LOOP AT lt_classmethod ASSIGNING FIELD-SYMBOL(<fs_classmethod>).
APPEND ` ` && <fs_classmethod>-methodname TO codestr.
IF <fs_classmethod>-inputdata IS NOT INITIAL.
APPEND ` IMPORTING ` TO codestr.
LOOP AT <fs_classmethod>-inputdata ASSIGNING FIELD-SYMBOL(<fs_transtru>).
APPEND ` ` && <fs_transtru>-dataname && ` TYPE ` && <fs_transtru>-datatype TO codestr.
ENDLOOP.
ENDIF.
IF <fs_classmethod>-inputdata IS NOT INITIAL.
APPEND ` EXPORTING ` TO codestr.
LOOP AT <fs_classmethod>-outputdata ASSIGNING <fs_transtru>.
APPEND ` ` && <fs_transtru>-dataname && ` TYPE ` && <fs_transtru>-datatype TO codestr.
ENDLOOP.
ENDIF.
APPEND ` ,` TO codestr.
ENDLOOP.
codestr[ lines( codestr ) ] = ' .'.
codestr[] = VALUE #( BASE codestr[] ( `ENDCLASS.` ) ( `CLASS MAIN IMPLEMENTATION.` ) ).
LOOP AT lt_classmethod ASSIGNING <fs_classmethod>.
CLEAR codestr.
APPEND ` METHOD ` && <fs_classmethod>-methodname && `.` TO codestr.
SPLIT <fs_classmethod>-body AT '.' INTO TABLE bodystr.
LOOP AT bodystr.
IF bodystr IS INITIAL.
CONTINUE.
ENDIF.
CONCATENATE bodystr '.' INTO codestr.
APPEND codestr.
CLEAR codestr.
ENDLOOP.
APPEND ` ENDMETHOD.` TO codestr.
ENDLOOP.
APPEND `ENDCLASS.` TO codestr.
GENERATE SUBROUTINE POOL codestr[] NAME prog.
CONCATENATE `\PROGRAM=` prog `\CLASS=MAIN` INTO DATA(class).
"动态调用
LOOP AT lt_classmethod ASSIGNING <fs_classmethod>.
CLEAR: ptab,etab.
IF <fs_classmethod>-inputdata IS NOT INITIAL.
LOOP AT <fs_classmethod>-inputdata ASSIGNING <fs_transtru>.
ptab = VALUE #( BASE ptab ( name = <fs_transtru>-dataname kind = cl_abap_objectdescr=>exporting value = REF #( <fs_classmethod>-inputdata[ sy-tabix ]-datavalue ) ) ).
ENDLOOP.
ENDIF.
"动态调用类方法
IF <fs_classmethod>-outputdata IS NOT INITIAL.
LOOP AT <fs_classmethod>-outputdata ASSIGNING <fs_transtru>.
ptab = VALUE #( BASE ptab ( name = <fs_transtru>-dataname kind = cl_abap_objectdescr=>importing value = REF #( <fs_classmethod>-outputdata[ sy-tabix ]-datavalue ) ) ).
ENDLOOP.
ENDIF.
CALL METHOD (class)=>(<fs_classmethod>-methodname)
PARAMETER-TABLE ptab "参数
EXCEPTION-TABLE etab. "异常
IF etab IS INITIAL.
LOOP AT <fs_classmethod>-outputdata ASSIGNING <fs_transtru>.
ASSIGN ptab[ name = <fs_transtru>-dataname kind = cl_abap_objectdescr=>importing ]-value TO FIELD-SYMBOL(<fs_test>).
ASSIGN <fs_test>->* TO FIELD-SYMBOL(<fs_testdata>) .
<fs_transtru>-datavalue = <fs_testdata>.
CONDENSE <fs_transtru>-datavalue.
ENDLOOP.
outputstr = /ui2/cl_json=>serialize( data = lt_classmethod compress = '' pretty_name = /ui2/cl_json=>pretty_mode-none ).
ELSE.
outputstr = /ui2/cl_json=>serialize( data = etab compress = '' pretty_name = /ui2/cl_json=>pretty_mode-none ).
ENDIF.
cl_demo_output=>display_json( outputstr ).
CLEAR outputstr.
ENDLOOP.
1.1.3. 改写成RFC
参数类型必须为string
FUNCTION z14143_dy_class.
*"----------------------------------------------------------------------
*"*"本地接口:
*" IMPORTING
*" VALUE(I_STRING) TYPE STRING OPTIONAL
*" EXPORTING
*" VALUE(O_STRING) TYPE STRING
*"----------------------------------------------------------------------
* i_string = '{"METHODS":[{"METHODNAME":"METHOD1","INPUTDATA":[{"DATATYPE":"CHAR36","DATANAME":"METHOD1INPUT1","DATAVALUE":"1"},{"DATATYPE":"CHAR36","DATANAME":"METHOD1INPUT2","DATAVALUE":"2"}],"OUTPUTDATA":[{"DATATYPE":"CHAR36",
*"DATANAME":"METHOD1OUTPUT1"},{"DATATYPE":"CHAR36","DATANAME":"METHOD1OUTPUT2"}],"BODY":"METHOD1OUTPUT1 = METHOD1INPUT1 + METHOD1INPUT2.METHOD1OUTPUT2 = METHOD1INPUT1 * METHOD1INPUT2."},{"METHODNAME":"METHOD2","INPUTDATA":[{"DATATYPE":"CHAR36",
*"DATANAME":"METHOD2INPUT1","DATAVALUE":"1"},{"DATATYPE":"CHAR36","DATANAME":"METHOD2INPUT2","DATAVALUE":"2"}],"OUTPUTDATA":[{"DATATYPE":"CHAR36","DATANAME":"METHOD2OUTPUT1"}],"BODY":"METHOD2OUTPUT1 = METHOD2INPUT1 && METHOD2INPUT2."}]}'.
TYPES BEGIN OF transtru.
TYPES datatype TYPE char36.
TYPES dataname TYPE char36.
TYPES datavalue TYPE string.
TYPES END OF transtru.
DATA BEGIN OF ls_rfcparameter.
DATA methodname TYPE char36.
DATA inputdata TYPE TABLE OF transtru.
DATA outputdata TYPE TABLE OF transtru.
DATA body TYPE string.
DATA END OF ls_rfcparameter.
DATA lt_classmethod LIKE TABLE OF ls_rfcparameter.
DATA:codestr TYPE TABLE OF string WITH HEADER LINE,
bodystr TYPE TABLE OF string WITH HEADER LINE,
linestr TYPE TABLE OF string WITH HEADER LINE.
DATA: prog TYPE string,
prostring TYPE string.
DATA: ptab TYPE abap_parmbind_tab,
etab TYPE abap_excpbind_tab.
DATA errorstring TYPE string.
DATA: msg(20) TYPE C,
LINE(10) TYPE C,
word(10) TYPE C,
off(3) TYPE C,
sid(3) TYPE C.
CALL TRANSFORMATION id SOURCE XML i_string RESULT methods = lt_classmethod.
codestr[] = VALUE #( ( `PROGRAM.` ) ( `CLASS MAIN DEFINITION.` ) ( ` PUBLIC SECTION.` ) ( ` CLASS-METHODS: ` ) ).
* 动态定义所有类方法
CLEAR codestr.
LOOP AT lt_classmethod ASSIGNING FIELD-SYMBOL(<fs_classmethod>).
APPEND ` ` && <fs_classmethod>-methodname TO codestr.
IF <fs_classmethod>-inputdata IS NOT INITIAL.
APPEND ` IMPORTING ` TO codestr.
LOOP AT <fs_classmethod>-inputdata ASSIGNING FIELD-SYMBOL(<fs_transtru>).
APPEND ` ` && <fs_transtru>-dataname && ` TYPE ` && <fs_transtru>-datatype TO codestr.
ENDLOOP.
ENDIF.
IF <fs_classmethod>-inputdata IS NOT INITIAL.
APPEND ` EXPORTING ` TO codestr.
LOOP AT <fs_classmethod>-outputdata ASSIGNING <fs_transtru>.
APPEND ` ` && <fs_transtru>-dataname && ` TYPE ` && <fs_transtru>-datatype TO codestr.
ENDLOOP.
ENDIF.
APPEND ` ,` TO codestr.
ENDLOOP.
codestr[ lines( codestr ) ] = ' .'.
codestr[] = VALUE #( BASE codestr[] ( `ENDCLASS.` ) ( `CLASS MAIN IMPLEMENTATION.` ) ).
LOOP AT lt_classmethod ASSIGNING <fs_classmethod>.
CLEAR codestr.
APPEND ` METHOD ` && <fs_classmethod>-methodname && `.` TO codestr.
SPLIT <fs_classmethod>-body AT '.' INTO TABLE bodystr.
LOOP AT bodystr.
IF bodystr IS INITIAL.
CONTINUE.
ENDIF.
"一行不能超过128个字符
IF strlen( bodystr ) > 127.
REFRESH linestr.
SPLIT bodystr AT space INTO TABLE linestr.
prostring = ''.
LOOP AT linestr INTO DATA(lv_str).
IF strlen( prostring && ` ` && lv_str ) < 127.
prostring = prostring && ` ` && lv_str.
ELSE.
codestr = prostring.
APPEND codestr.
CLEAR codestr.
prostring = lv_str.
ENDIF.
ENDLOOP.
bodystr = prostring.
ENDIF.
CONCATENATE bodystr '.' INTO codestr.
APPEND codestr.
CLEAR codestr.
ENDLOOP.
APPEND ` ENDMETHOD.` TO codestr.
ENDLOOP.
APPEND `ENDCLASS.` TO codestr.
GENERATE SUBROUTINE POOL codestr[] NAME prog MESSAGE msg LINE line WORD word OFFSET off SHORTDUMP-ID sid.
IF sy-subrc <> 0.
o_string = 'Error occurs in line:' && line && msg && 'Word:' && word && 'Offset:' && off.
RETURN.
ENDIF.
CONCATENATE `\PROGRAM=` prog `\CLASS=MAIN` INTO DATA(class).
"动态类所有方法调用
LOOP AT lt_classmethod ASSIGNING <fs_classmethod>.
CLEAR: ptab,etab.
IF <fs_classmethod>-inputdata IS NOT INITIAL.
LOOP AT <fs_classmethod>-inputdata ASSIGNING <fs_transtru>.
ptab = VALUE #( BASE ptab ( name = <fs_transtru>-dataname kind = cl_abap_objectdescr=>exporting value = REF #( <fs_classmethod>-inputdata[ sy-tabix ]-datavalue ) ) ).
ENDLOOP.
ENDIF.
"动态调用类方法
IF <fs_classmethod>-outputdata IS NOT INITIAL.
LOOP AT <fs_classmethod>-outputdata ASSIGNING <fs_transtru>.
ptab = VALUE #( BASE ptab ( name = <fs_transtru>-dataname kind = cl_abap_objectdescr=>importing VALUE = REF #( <fs_classmethod>-outputdata[ sy-tabix ]-datavalue ) ) ).
ENDLOOP.
ENDIF.
CALL METHOD (class)=>(<fs_classmethod>-methodname)
PARAMETER-TABLE ptab "参数
EXCEPTION-TABLE etab. "异常
IF etab IS INITIAL.
LOOP AT <fs_classmethod>-outputdata ASSIGNING <fs_transtru>.
ASSIGN ptab[ name = <fs_transtru>-dataname kind = cl_abap_objectdescr=>importing ]-value TO FIELD-SYMBOL(<fs_test>).
ASSIGN <fs_test>->* TO FIELD-SYMBOL(<fs_testdata>) .
<fs_transtru>-datavalue = <fs_testdata>.
CONDENSE <fs_transtru>-datavalue.
ENDLOOP.
ELSE.
errorstring = /ui2/cl_json=>serialize( data = etab compress = '' pretty_name = /ui2/cl_json=>pretty_mode-none ).
ENDIF.
ENDLOOP.
IF errorstring IS NOT INITIAL.
o_string = errorstring.
ELSE.
o_string = /ui2/cl_json=>serialize( data = lt_classmethod compress = '' pretty_name = /ui2/cl_json=>pretty_mode-none ).
ENDIF.
ENDFUNCTION.
1.1.4. 调用RFC
REPORT z14143_12.
DATA i_string TYPE string.
DATA o_string TYPE string.
i_string = '{"METHODS":[{"METHODNAME":"METHOD1","INPUTDATA":[{"DATATYPE":"CHAR36","DATANAME":"METHOD1INPUT1","DATAVALUE":"1"}' &&
',{"DATATYPE":"CHAR36","DATANAME":"METHOD1INPUT2","DATAVALUE":"2"}],"OUTPUTDATA":[{"DATATYPE":"CHAR36","DATANAME":"METHOD1OUTPUT1"}' &&
',{"DATATYPE":"CHAR36","DATANAME":"METHOD1OUTPUT2"}],"BODY":"METHOD1OUTPUT1 = METHOD1INPUT1 +' &&
' METHOD1INPUT2.METHOD1OUTPUT2 = METHOD1INPUT1 * METHOD1INPUT2."},{"METHODNAME":"METHOD2","INPUTDATA"' &&
':[{"DATATYPE":"CHAR36","DATANAME":"METHOD2INPUT1","DATAVALUE":"1"},{"DATATYPE":"CHAR36","DATANAME":"METHOD2INPUT2","DATAVALUE":"2"}],"OUTPUTDATA"' &&
':[{"DATATYPE":"CHAR36","DATANAME":"METHOD2OUTPUT1"}],"BODY":"METHOD2OUTPUT1 = METHOD2INPUT1 && METHOD2INPUT2."}]}'.
CALL FUNCTION 'Z14143_DY_CLASS'
EXPORTING
i_string = i_string
IMPORTING
o_string = o_string
.
cl_demo_output=>display_json( o_string ).