SOA is an S(tate)O(f)M(ind) 1st … a bag of tricks 2nd …
In these three recent blogs:
[Without bread-crumbs, Hansel and Gretel meet the WWW (Wicked Witch of Web-Services) | Without bread-crumbs, Hansel and Gretel meet the WWW (Wicked Witch of Web-Services)]
[CodExpertise vs BPXpertise: which is the tail and which is the dog? | CodExpertise vs BPXpertise: which is the tail and which is the dog?]
[Into the Valley of Depth Rode the Implicit Enhancers | Into the Valley of Depth Rode the Implicit Enhancers]
I’ve tried to keep a promise to Mark Finnern – namely, to show that SOA is really an SOM (StateOfMind) that one can cultivate, even if one does not have access to particular tools for implementing SOA (e.g. PI7.1, WDA, etc.)
Here is another example from real-life to make the same point.
The client wants a download to BW/BPC of the on-line report you get from MD4C when you choose a project on the project tab.
But here’s the kicker – the client wants the correct WBS element associated with each line of the MD4C project report download
Well – in some cases this is easy – for some MD4C elements, you can get a pspel from PLAF which you can take into PRPS and get a WBS.
But for other cases, not so easy.
So what to do?
Well, you poke around for a few days and all of a sudden you realize that what you really want to do is to solve this problem using two itabs that standard SAP code already generates: the ioel itab underlyng the MD4C report (actually generated by the program PP_ORDER_PROGRESS) with certain elements of the g_tree_tab itab underlying the CN41N report on a project (actually generated by program RPSINFO.
Why? Because the g_tree_tab itab generated by RPSINFO actually contains enough information to tie elements of this itab to elements of the ioel itab. And, by using a little bit of hashing and reverse-order table reads, you can get the associations you need without ever leaving memory to do a single select against PLAF, PRPS, PRHI, etc.
But how do you get the g_tree_itab from CN41N/RPSINFO into the same address space as the ioel itab from MD4C/PP_ORDER_PROGRESS (so you can bounce from one to the other to your heart’s content …)
Well, what you do is get into an SOA SOM.
First, you do an implicit enhancement to the EXPORT_TABLES_TO_MEMORY form of RPSINFO so that if a certain SET/GET memory parameter is set to certain value, you leave the program after exporting excerpts of the itabs in this form to memory. (Note: you don’t export the actual SAP itabs because you don’t need everything that’s in them; also, you really only need g_tree_itab but you take excerpts of all of them because they might come in handy later on.)
Second, you do an implicit enhancement to the function module MD_PROJECT_REPORT that’s called by MD4C/PP_ORDER_PROGRESS, so that the ioel table is exported to memory as soon as it’s built. Furthermore, to make sure that this function module has all the parameters it wants, you don’t call it directly – you perform START_SELECTION NEW in PP_ORDER_PROGRESS.
Finally, you write a piece of code that: 1) calls RPSINFO and then imports the ioel table that you’ve exported in your enhancement; 2) performs START_SELECTION_NEW in PP_ORDER_PROGRESS and then imports the excerpt of g_tree_itab (and the other itabs) that you’ve expored in your enhancement to MD_PROJECT_REPORT.
And now, you can bounce from your ioel itab excerpt into your gt_tree_itab excerpt to your heart’s content, finding the right WBS element in the latter for each element of the former. (To make this efficient, it’s worthwhile hashing your excerpt of gt_tree_itab so that you can immediately find out where you need to be in the standard excerpt of gt_tree_itab, so that you can simply read upwards to find the lowest available WBS element.)
But look at what you’ve done here: you’ve done SOA without ever using PI 7.1 or WDA. Because what SOA is really about in the SAP environment is figuring out how to deconstruct and reconstruct SAP code so that you can take only what you need from it, and never have to write a line of custom code that you really don’t need to write.
To show that the above is not “blue sky”, all the relevant code (except the hashing and bouncing) appears below. (The other reason I’m exhibiting this code is to show that a class-based persistence approach would be a lot better than using FG’s and secondary exports to session memory …)
Here’s the main function that lets you bring your ioel and g_tree_tab excerpts together in the same address space:
FUNCTION ZMD_INTGR8_MD4C_CN41N.
“—-
<br />““Local Interface:<br />” IMPORTING
” REFERENCE(PROJECT) TYPE PS_PSPID<br />” REFERENCE(MATNRS) TYPE MD_T_MATNR OPTIONAL
“—-
<br />DATA:<br /> lv_zbpcmd4c TYPE xfeld,<br /> lv_selscr TYPE sy-dynnr,<br /> lv_pspid TYPE ps_pspid,<br /> lv_posid TYPE ps_posid,<br /> lv_pshir TYPE pshir,<br /> lv_plnum TYPE plnum,<br /> lv_aufnr TYPE aufnr,<br /> lv_netw TYPE nw_aufnr,<br /> gt_vbap LIKE TABLE OF vbap WITH HEADER LINE,<br /> l_werks TYPE werks_d.</p><p>DATA: BEGIN OF gt_matnr OCCURS 0,<br /> matnr LIKE afpod-matnr,<br /> END OF gt_matnr.</p><p> SET PARAMETER ID ‘PFL’ FIELD ‘000000000001’.<br /> SET PARAMETER ID ‘PROFID’ FIELD ‘000000000001’.<br /> SET PARAMETER ID ‘ZBPCMD4C’ FIELD ‘X’.</p><p> SUBMIT RPSINFO<br /> USING SELECTION-SCREEN 1000<br /> WITH cn_projn = project<br /> AND RETURN.</p><p> lv_selscr = ‘0020’.<br /> lv_pspid = project.<br /> PERFORM start_selection_new IN PROGRAM PP_ORDER_PROGRESS<br /> USING<br /> lv_selscr<br /> gt_vbap[]<br /> gt_matnr[]<br /> l_werks<br /> lv_pspid<br /> lv_posid<br /> lv_pshir<br /> lv_plnum<br /> lv_aufnr<br /> lv_netw.</p><p> IMPORT gt_ioel FROM MEMORY ID ‘ZBPCMD4C_IOEL’.<br /> IMPORT gt_act FROM MEMORY ID ‘ZBPCMD4C_ACT’.<br /> IMPORT gt_affh FROM MEMORY ID ‘ZBPCMD4C_AFFH’.<br /> IMPORT gt_afru FROM MEMORY ID ‘ZBPCMD4C_AFRU’.<br /> IMPORT gt_kbed FROM MEMORY ID ‘ZBPCMD4C_KBED’.<br /> IMPORT gt_netwrk FROM MEMORY ID ‘ZBPCMD4C_NETWRK’.<br /> IMPORT gt_plaf FROM MEMORY ID ‘ZBPCMD4C_PLAF’.<br /> IMPORT gt_proj FROM MEMORY ID ‘ZBPCMD4C_PROJ’.<br /> IMPORT gt_prps FROM MEMORY ID ‘ZBPCMD4C_PRPS’.<br /> IMPORT gt_resb FROM MEMORY ID ‘ZBPCMD4C_RESB’.<br /> IMPORT gt_tree FROM MEMORY ID ‘ZBPCMD4C_TREE’.</p><p>ENDFUNCTION.</p><p> </p><p>Here’s the enhancement to RPSINFO:</p><p> </p><p>FORM export_tables_to_memory .<br />”””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””$”$SE:(1) Form EXPORT_TABLES_TO_MEMORY, Start A<br />$$-Start: (1)—-
$$<br />ENHANCEMENT 1 ZMME_INTERCEPT_RSPINFO. “active version<br />—
</p><p><br />DATA:<br /> lv_zbpcmd4c TYPE xfeld.</p><p> GET PARAMETER ID ‘ZBPCMD4C’ FIELD lv_zbpcmd4c.</p><p> IF lv_zbpcmd4c = ‘X’.<br /> PERFORM create_rspinfo_itab_xcrpts.<br /> LEAVE PROGRAM.<br /> ENDIF.</p><p>ENDENHANCEMENT.<br />$*$-End: (1)
$$<br /> EXPORT :<br /> g_tree_tab<br /> g_imtp<br /> g_proj<br /> g_prps<br /> g_vbak<br /> g_vbap<br /> g_plaf<br /> g_afab<br /> g_kbed<br /> g_resb<br /> g_afru<br /> g_mlst<br /> g_pstx<br /> g_drad<br /> g_affh<br /> g_act<br /> g_netwrk<br /> g_vsindex<br /> g_out_s000<br /> textsymbols TO MEMORY ID ‘CNIS_SHARED_TABS’.</p><p>ENDFORM. ” tablesto_memory</p><p>”””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””$”$SE:</p><p> </p><p>Here’s the second enhancement to RPSINFO to take excerpts of the SAP itabs:</p><p> </p><p>ENHANCEMENT 1 ZMME_INTERCEPT_RSPINFO_FORM. “active version<br />FORM create_rspinfo_itab_xcrpts.</p><p>FIELD-SYMBOLS:<br /> <fs_oact> TYPE cnpsj_act_type,<br /> <fs_oaffh> TYPE cnpsj_affh_type,<br /> <fs_oafru> TYPE cnpsj_afru_type,<br /> <fs_okbed> TYPE cnpsj_kbed_type,<br /> <fs_onetwrk> TYPE cnpsj_net_type,<br /> <fs_oplaf> TYPE cnpsj_plaf_type,<br /> <fs_oproj> TYPE cnpsj_proj_type,<br /> <fs_oprps> TYPE cnpsj_prps_type,<br /> <fs_oresb> TYPE cnpsj_resb_type,<br /> <fs_otree> TYPE cnpsj_struc,</p><p> <fs_act> TYPE ZMDS_RPS_ACT_XCRPT,<br /> <fs_affh> TYPE ZMDS_RPS_AFFH_XCRPT,<br /> <fs_afru> TYPE ZMDS_RPS_AFRU_XCRPT,<br /> <fs_kbed> TYPE ZMDS_RPS_KBED_XCRPT,<br /> <fs_netwrk> TYPE ZMDS_RPS_NETWRK_XCRPT,<br /> <fs_plaf> TYPE ZMDS_RPS_PLAF_XCRPT,<br /> <fs_proj> TYPE ZMDS_RPS_PROJ_XCRPT,<br /> <fs_prps> TYPE ZMDS_RPS_PRPS_XCRPT,<br /> <fs_resb> TYPE ZMDS_RPS_RESB_XCRPT,<br /> <fs_tree> TYPE ZMDS_RPS_TREE_XCRPT.</p><p>DATA:<br /> lt_act TYPE STANDARD TABLE OF ZMDS_RPS_ACT_XCRPT,<br /> lt_affh TYPE STANDARD TABLE OF ZMDS_RPS_AFFH_XCRPT,<br /> lt_afru TYPE STANDARD TABLE OF ZMDS_RPS_AFRU_XCRPT,<br /> lt_kbed TYPE STANDARD TABLE OF ZMDS_RPS_KBED_XCRPT,<br /> lt_netwrk TYPE STANDARD TABLE OF ZMDS_RPS_NETWRK_XCRPT,<br /> lt_plaf TYPE STANDARD TABLE OF ZMDS_RPS_PLAF_XCRPT,<br /> lt_proj TYPE STANDARD TABLE OF ZMDS_RPS_PROJ_XCRPT,<br /> lt_prps TYPE STANDARD TABLE OF ZMDS_RPS_PRPS_XCRPT,<br /> lt_resb TYPE STANDARD TABLE OF ZMDS_RPS_RESB_XCRPT,<br /> lt_tree TYPE STANDARD TABLE OF ZMDS_RPS_TREE_XCRPT,</p><p> ls_return TYPE bapiret2.</p><p> LOOP AT g_act ASSIGNING <fs_oact>.<br /> APPEND INITIAL LINE TO lt_act ASSIGNING <fs_act>.<br /> MOVE-CORRESPONDING <fs_oact> TO <fs_act>.<br /> ENDLOOP.<br /> CLEAR g_act.</p><p> LOOP AT g_affh ASSIGNING <fs_oaffh>.<br /> APPEND INITIAL LINE TO lt_affh ASSIGNING <fs_affh>.<br /> MOVE-CORRESPONDING <fs_oaffh> TO <fs_affh>.<br /> ENDLOOP.<br /> CLEAR g_affh.</p><p> LOOP AT g_afru ASSIGNING <fs_oafru>.<br /> APPEND INITIAL LINE TO lt_afru ASSIGNING <fs_afru>.<br /> MOVE-CORRESPONDING <fs_oafru> TO <fs_afru>.<br /> ENDLOOP.<br /> CLEAR g_afru.</p><p> LOOP AT g_kbed ASSIGNING <fs_okbed>.<br /> APPEND INITIAL LINE TO lt_kbed ASSIGNING <fs_kbed>.<br /> MOVE-CORRESPONDING <fs_okbed> TO <fs_kbed>.<br /> ENDLOOP.<br /> CLEAR g_kbed.</p><p> LOOP AT g_netwrk ASSIGNING <fs_onetwrk>.<br /> APPEND INITIAL LINE TO lt_netwrk ASSIGNING <fs_netwrk>.<br /> MOVE-CORRESPONDING <fs_onetwrk> TO <fs_netwrk>.<br /> ENDLOOP.<br /> CLEAR g_netwrk.</p><p> LOOP AT g_plaf ASSIGNING <fs_oplaf>.<br /> APPEND INITIAL LINE TO lt_plaf ASSIGNING <fs_plaf>.<br /> MOVE-CORRESPONDING <fs_oplaf> TO <fs_plaf>.<br /> ENDLOOP.<br /> CLEAR g_plaf.</p><p> LOOP AT g_proj ASSIGNING <fs_oproj>.<br /> APPEND INITIAL LINE TO lt_proj ASSIGNING <fs_proj>.<br /> MOVE-CORRESPONDING <fs_oproj> TO <fs_proj>.<br /> ENDLOOP.<br /> CLEAR g_proj.</p><p> LOOP AT g_prps ASSIGNING <fs_oprps>.<br /> APPEND INITIAL LINE TO lt_prps ASSIGNING <fs_prps>.<br /> MOVE-CORRESPONDING <fs_oprps> TO <fs_prps>.<br /> ENDLOOP.<br /> CLEAR g_prps.</p><p> LOOP AT g_resb ASSIGNING <fs_oresb>.<br /> APPEND INITIAL LINE TO lt_resb ASSIGNING <fs_resb>.<br /> MOVE-CORRESPONDING <fs_oresb> TO <fs_resb>.<br /> ENDLOOP.<br /> CLEAR g_resb.</p><p> LOOP AT g_tree_tab ASSIGNING <fs_otree>.<br /> APPEND INITIAL LINE TO lt_tree ASSIGNING <fs_tree>.<br /> MOVE-CORRESPONDING <fs_otree> TO <fs_tree>.<br /> ENDLOOP.<br /> CLEAR g_tree_tab.</p><p>CALL FUNCTION ‘ZMD_GLBLZ_RSP_ITABS'<br /> EXPORTING<br /> ACT = lt_act<br /> AFFH = lt_affh<br /> AFRU = lt_afru<br /> KBED = lt_kbed<br /> NETWRK = lt_netwrk<br /> PLAF = lt_plaf<br /> PROJ = lt_proj<br /> PRPS = lt_prps<br /> RESB = lt_resb<br /> TREE = lt_tree<br /> IMPORTING<br /> return = ls_return.</p><p>ENDFORM.</p><p>ENDENHANCEMENT.</p><p> </p><p>Here’s the function that sends your RPSINFO excerpts to memory </p><p>FUNCTION ZMD_GLBLZ_RSP_ITABS.<br />*”
<br />““Local Interface:<br />” IMPORTING<br />” VALUE(ACT) TYPE ZMDY_RPS_ACT_XCRPT<br />” VALUE(AFFH) TYPE ZMDY_RPS_AFFH_XCRPT<br />” VALUE(AFRU) TYPE ZMDY_RPS_AFRU_XCRPT<br />” VALUE(KBED) TYPE ZMDY_RPS_KBED_XCRPT<br />” VALUE(NETWRK) TYPE ZMDY_RPS_NETWRK_XCRPT<br />” VALUE(PLAF) TYPE ZMDY_RPS_PLAF_XCRPT<br />” VALUE(PROJ) TYPE ZMDY_RPS_PROJ_XCRPT<br />” VALUE(PRPS) TYPE ZMDY_RPS_PRPS_XCRPT<br />” VALUE(RESB) TYPE ZMDY_RPS_RESB_XCRPT<br />” VALUE(TREE) TYPE ZMDY_RPS_TREE_XCRPT<br />” EXPORTING<br />” VALUE(RETURN) TYPE BAPIRET2<br />“
<br /> gt_act[] = act[].<br /> gt_affh[] = affh[].<br /> gt_afru[] = afru[].<br /> gt_kbed[] = kbed[].<br /> gt_netwrk[] = netwrk[].<br /> gt_plaf[] = plaf[].<br /> gt_proj[] = proj[].<br /> gt_prps[] = prps[].<br /> gt_resb[] = resb[].<br /> gt_tree[] = tree[].</p><p> EXPORT gt_act TO MEMORY ID ‘ZBPCMD4C_ACT’.<br /> EXPORT gt_affh TO MEMORY ID ‘ZBPCMD4C_AFFH’.<br /> EXPORT gt_afru TO MEMORY ID ‘ZBPCMD4C_AFRU’.<br /> EXPORT gt_kbed TO MEMORY ID ‘ZBPCMD4C_KBED’.<br /> EXPORT gt_netwrk TO MEMORY ID ‘ZBPCMD4C_NETWRK’.<br /> EXPORT gt_plaf TO MEMORY ID ‘ZBPCMD4C_PLAF’.<br /> EXPORT gt_proj TO MEMORY ID ‘ZBPCMD4C_PROJ’.<br /> EXPORT gt_prps TO MEMORY ID ‘ZBPCMD4C_PRPS’.<br /> EXPORT gt_resb TO MEMORY ID ‘ZBPCMD4C_RESB’.<br /> EXPORT gt_tree TO MEMORY ID ‘ZBPCMD4C_TREE’.</p><p>ENDFUNCTION.</p><p> </p><p>Here’s the enhancement to MD_PROJECT_REPORT (called by PP_ORDER_PROGRESS)</p><p> </p><p>ENHANCEMENT 1 ZMDE_INTERCEPT_PP_ORDER_PRGRS2. “active version</p><p>FIELD-SYMBOLS:<br /> <fs_oioelx> TYPE ioel,<br /> <fs_ioel> TYPE ioel.</p><p>DATA:<br /> lv_zbpcmd4c TYPE xfeld,<br /> lt_ioel TYPE MD_IOELX,<br /> ls_return TYPE bapiret2.</p><p> GET PARAMETER ID ‘ZBPCMD4C’ FIELD lv_zbpcmd4c.<br /> IF lv_zbpcmd4c <> ‘X’.<br /> RETURN.<br /> ENDIF.</p><p> LOOP AT ioelx ASSIGNING <fs_oioelx>.<br /> APPEND INITIAL LINE to lt_ioel ASSIGNING <fs_ioel>.<br /> MOVE-CORRESPONDING <fs_oioelx> TO <fs_ioel>.<br /> ENDLOOP.</p><p> CALL FUNCTION ‘ZMD_GLBLZ_PP_ORD_PRGRS_IOEL'<br /> EXPORTING<br /> IOEL = lt_ioel<br /> IMPORTING<br /> RETURN = ls_return.</p><p>ENDENHANCEMENT.<br />$$-End: (1)
$$<br />ENDFUNCTION.</p><p> </p><p>Here’s the auxilary function that exports your ioel excerpt to memory:</p><p> </p><p>FUNCTION ZMD_GLBLZ_PP_ORD_PRGRS_IOEL.<br />*”
<br />““Local Interface:<br />” IMPORTING<br />” VALUE(IOEL) TYPE MD_IOELX<br />” EXPORTING<br />” REFERENCE(RETURN) TYPE BAPIRET2<br />*”—
gt_ioel[] = ioel[].
EXPORT gt_ioel TO MEMORY ID ‘ZBPCMD4C_IOEL’.
ENDFUNCTION.