乐趣区

关于sap:增强版本的自开发SAP-WebClient-UI-Repository-Information-System

My original tool introduced in blog Repository Information System for WebClient UI Component does not satisfy my colleagues, they have more requirement, as always
Some key requirements:

(1) I would like to know how many UI Component has used component set for example PROD_ALL defined in runtime repository.

(2) I have a data element for example COMT_PRODUCT_ID, I know it is used as context node attribute PRODUCT_ID in context node PRODUCT.

Now I would like to have a list of all WebClient UI component where the given data element is used as a certain context node attribute.

Here below is how I fulfill this requirement via some development.

Step 1

Create a database table CRMD_WEBUI_COM_H to store the relationship between a WebClient UI component and its assigned Genil component set
The technical definition of this table:

With this table, now it is easy for me to figure out how many UI component are using for example Genil component set PROD_ALL, that is 85:

Execute the following report to fill the content into this table:

REPORT crm_webui_tool_fill_bolset.
DATA: lt_ui                TYPE TABLE OF o2appl-applname,
      lt_dir               TYPE TABLE OF o2pagdir-applname,
      lv_loader            TYPE REF TO cl_bsp_wd_stream_loader,
      lv_bol_component_set TYPE string,
      lv_xml               TYPE string,
      lt_result            TYPE TABLE OF crmd_webui_com_h.

SELECT applname INTO TABLE lt_ui FROM o2appl WHERE
  applname NOT LIKE 'Z%'.

SELECT DISTINCT applname INTO TABLE lt_dir FROM o2pagdir
    FOR ALL ENTRIES IN lt_ui WHERE o2pagdir~applname = lt_ui-table_line
      AND o2pagdir~pagekey = 'BSPWDCOMPONENT.DO'.

CREATE OBJECT lv_loader.
LOOP AT lt_dir ASSIGNING FIELD-SYMBOL(<page>).
  CLEAR: lv_xml.
  lv_xml = lv_loader->load_from_bsp_page( iv_bsp_appl = <page>
                                        iv_bsp_page   = 'Repository.xml' ).
  CHECK lv_xml IS NOT INITIAL.
  TRY.
      CALL TRANSFORMATION bsp_wd_rt_rep_runtime
        SOURCE XML        lv_xml
        RESULT model    = lv_bol_component_set.
    CATCH cx_root INTO DATA(cx_root).
      WRITE:/ |xml parse error for component: {<page>}| COLOR COL_NEGATIVE.
      CONTINUE.
  ENDTRY.

  APPEND INITIAL LINE TO lt_result ASSIGNING FIELD-SYMBOL(<result>).
  <result> = VALUE #(appl = <page> bol_set = lv_bol_component_set).
ENDLOOP.
DELETE FROM crmd_webui_com_h.
INSERT  crmd_webui_com_h FROM TABLE lt_result.

WRITE:/ |BOL index table inserted: {lines( lt_result) }| COLOR COL_NEGATIVE.

Step 2

Create a table CRMD_WUI_PROPERT to store the metadata of all Genil Component set.
The table contains Genil component model name, model node name and the DDIC structure used by the model node.

Use this report to fill content into it:

REPORT crm_webui_tool_fill_node_struc.

DATA:
  lt_bol_set  TYPE TABLE OF crmd_webui_com_h-bol_set,
  lt_result   TYPE TABLE OF crmd_wui_propert,
  lt_obj_list TYPE crmt_ext_obj_name_tab.

SELECT DISTINCT bol_set INTO TABLE lt_bol_set FROM crmd_webui_com_h
   WHERE bol_set <> space.

DATA(lo_core) = cl_crm_bol_core=>get_instance( ).
LOOP AT lt_bol_set ASSIGNING FIELD-SYMBOL(<bol>).
  TRY.
      lo_core->load_component_set(<bol>).
    CATCH cx_root.
      CONTINUE.
  ENDTRY.
  DATA(object_model) = CAST if_genil_obj_model(cl_crm_genil_model_service=>get_runtime_model() ).
  object_model->get_object_list(IMPORTING et_object_list = lt_obj_list).
  LOOP AT lt_obj_list ASSIGNING FIELD-SYMBOL(<object>).
    TRY.
        DATA(result) = object_model->get_object_properties(iv_object_name = <object>).
      CATCH cx_root.
        CONTINUE.
    ENDTRY.
    APPEND INITIAL LINE TO lt_result ASSIGNING FIELD-SYMBOL(<result>).
    <result> = VALUE #( component_set = <bol> node_name = <object>
    attr_struct_name = result-attr_struct ).
  ENDLOOP.
ENDLOOP.

DELETE FROM crmd_wui_propert.
INSERT crmd_wui_propert FROM TABLE lt_result.

Step 3

Now it is time to extract needed information from each WebClient UI component. The information I need is:

  • Context node class name
  • the name of view where the context node is defined
  • the name of WebClient UI component where the context node is defined
  • the name of context node itself
  • the name of Genil Model node which is bound to the current context node
  • the DDIC structure used by the bound Genil Model node

Create a table CRMD_WUI_CONTX_H to store those information:

Execute this report to fill content into it:

REPORT crm_webui_tool_fill_context_h.

DATA: lt_pagdir TYPE TABLE OF o2pagdir,
      lt_result TYPE TABLE OF crmd_wui_contx_h,
      lt_struct TYPE TABLE OF crmd_wui_propert,
      lt_set    TYPE TABLE OF crmd_webui_com_h,
      ls_flag   TYPE crmd_wui_index_f,
      lv_index  TYPE int4 value 1,
      lt_all_context_node TYPE TABLE OF vseoextend-clsname,
      lt_context_node_name TYPE TABLE OF vseoattrib,
      lo_cls    TYPE REF TO cl_bsp_wd_context_node.

SELECT applname pagekey implclass INTO CORRESPONDING FIELDS OF TABLE lt_pagdir
    FROM o2pagdir AS a INNER JOIN crmd_webui_com_h AS b ON a~applname = b~appl
   WHERE pagekey LIKE '%.DO'.

SORT lt_pagdir BY applname.

SELECT * INTO TABLE lt_struct FROM crmd_wui_propert.
SELECT * INTO TABLE lt_set FROM crmd_webui_com_h.
SELECT clsname INTO TABLE lt_all_context_node FROM vseoextend WHERE refclsname =
   'CL_BSP_WD_CONTEXT_NODE'.
SELECT clsname attvalue INTO CORRESPONDING FIELDS OF TABLE lt_context_node_name
  FROM vseoattrib FOR ALL ENTRIES IN lt_all_context_node WHERE clsname =
  lt_all_context_node-table_line AND cmpname = 'BASE_ENTITY_NAME'.
DATA(lv_line) = lines(lt_pagdir).
LOOP AT lt_pagdir ASSIGNING FIELD-SYMBOL(<page>).
  CALL FUNCTION 'SAPGUI_PROGRESS_INDICATOR'
        EXPORTING
          percentage = (lv_index * 100) / lv_line
          text       = | UI Component being scanned: {<page>-applname} |.
  AT NEW applname.
    DATA(lo_model) = cl_bsp_wd_appl_model=>get_appl_model( EXPORTING  iv_bsp_appl        = <page>-applname
                                                       iv_model_type      = 'CL_BSP_WD_APPL_MODEL_DDIC' ).
  ENDAT.
  DATA(lv_name) = lo_model->get_runtime_context(<page>-implclass).

  DATA(lt_context) = lo_model->get_runtime_context_nodes(lv_name).
  LOOP AT lt_context ASSIGNING FIELD-SYMBOL(<context>).

    TRANSLATE <context>-implclass TO UPPER CASE.

    READ TABLE lt_context_node_name ASSIGNING FIELD-SYMBOL(<node_name>)
      WITH KEY clsname = <context>-implclass.
    CHECK sy-subrc = 0.
    REPLACE ALL OCCURRENCES OF '''' IN <node_name>-attvalue WITH space.

    READ TABLE lt_set ASSIGNING FIELD-SYMBOL(<set>) WITH KEY appl = <page>-applname.
    CHECK sy-subrc = 0.
    READ TABLE lt_struct ASSIGNING FIELD-SYMBOL(<struct>) WITH KEY component_set = <set>-bol_set
      node_name = <node_name>-attvalue.
    CHECK sy-subrc = 0.
    APPEND INITIAL LINE TO lt_result ASSIGNING FIELD-SYMBOL(<result>).
    <result> = VALUE #( context_node_cls = <context>-implclass
                        component = <page>-applname
                        view_name = <page>-pagekey
                        context_node_name = <context>-name
                        genil_node_name = <node_name>-attvalue
                        attr_struct_name = <struct>-attr_struct_name
                        ).
  ENDLOOP.
  lv_index = lv_index + 1.
ENDLOOP.

DELETE FROM crmd_wui_contx_h.
INSERT crmd_wui_contx_h FROM TABLE lt_result.

WRITE:/ |Entries inserted: {lines( lt_result) }| COLOR COL_GROUP.

Step 4

As the last step, now we need to provide the data type for each context node attribute. As a result I create this table CRMD_WUI_CN_ATTR to store the context node name, the component where it is defined, and each attribute name and data element name used by this context node attribute.

The table content is filled by this report:

REPORT crm_webui_tool_fill_cont_attr.

TYPES: BEGIN OF ty_field_type,
         fieldname TYPE dfies-fieldname,
         rollname  TYPE dfies-rollname,
       END OF ty_field_type.

TYPES: tt_field_type TYPE STANDARD TABLE OF ty_field_type WITH KEY fieldname.
TYPES: BEGIN OF ty_struct_types,
         struct_name  TYPE seocpdname,
         field_detail TYPE tt_field_type,
       END OF ty_struct_types.

TYPES: tt_struct_types TYPE STANDARD TABLE OF ty_struct_types WITH KEY struct_name.
DATA: lt_context_h   TYPE TABLE OF crmd_wui_contx_h,
      lt_result      TYPE TABLE OF crmd_wui_cn_attr,
      lt_dfies_tab   TYPE comt_dfies_tab,
      lt_struc_types TYPE tt_struct_types.

FIELD-SYMBOLS: <type> TYPE ty_struct_types.
SELECT * INTO TABLE lt_context_h FROM crmd_wui_contx_h.

LOOP AT lt_context_h ASSIGNING FIELD-SYMBOL(<context_node>).
  DATA(lo_model) = cl_bsp_wd_appl_model=>get_appl_model(
       EXPORTING  iv_bsp_appl = <context_node>-component
                   iv_model_type      = 'CL_BSP_WD_APPL_MODEL_DDIC' ).
  DATA(lt_attr) = lo_model->get_context_node_attr( iv_context_node_class  = <context_node>-context_node_cls
                                                          iv_mark_ext_attributes = abap_true ).
  READ TABLE lt_struc_types ASSIGNING <type> WITH KEY struct_name = <context_node>-attr_struct_name.
  IF sy-subrc <> 0.
    CALL FUNCTION 'DDIF_FIELDINFO_GET'
      EXPORTING
        tabname   = <context_node>-attr_struct_name
      TABLES
        dfies_tab = lt_dfies_tab.
    DATA(lt_field_type) = CORRESPONDING tt_field_type(lt_dfies_tab).
    APPEND INITIAL LINE TO lt_struc_types ASSIGNING <type>.
    <type> = VALUE #(struct_name = <context_node>-attr_struct_name field_detail = lt_field_type).
    CLEAR: lt_dfies_tab.
  ENDIF.
  LOOP AT lt_attr ASSIGNING FIELD-SYMBOL(<attr>).
    FIND '.' IN <attr>.
    CHECK sy-subrc = 0.
    SPLIT <attr> AT '.' INTO TABLE DATA(lt_field_name).
    READ TABLE <type>-field_detail ASSIGNING FIELD-SYMBOL(<field_type>) WITH KEY
      fieldname = lt_field_name[2].
    CHECK sy-subrc = 0.
    APPEND INITIAL LINE TO lt_result ASSIGNING FIELD-SYMBOL(<result>).
    <result> = CORRESPONDING #(<context_node>).
    <result>-attr_name = lt_field_name[2].
    <result>-attr_type = <field_type>-rollname.
  ENDLOOP.
ENDLOOP.

DELETE FROM crmd_wui_cn_attr.
INSERT crmd_wui_cn_attr FROM TABLE lt_result.

WRITE:/ |Lines inserted: {lines( lt_result) }| COLOR COL_NEGATIVE.

Once done, now it is very easy to answer the second question raised in the beginning of this blog:

How many UI Component have context node which uses data element COMT_PRODUCT_ID as context node attribute type?
Just query field ATTR_TYPE with value COMT_PRODUCT_ID:

And you get a list of all 993 usages:

要获取更多 Jerry 的原创文章,请关注公众号 ” 汪子熙 ”:

退出移动版