Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
somnath
Active Participant
6,508
Hello,

Introduction:


CDS doesn't need any introduction so let's get to the core of the topic for which I am writing this blog post.

I was investigating on certain CDS annotations and I was missing something called "where used" option for CDS, this is a feature which we ABAPers use almost every day! But when comes to this CDS, no such option I could find. If you are using DDIC view instead of DDLS Entity then probably you can, but that is NOT the right approach and with "define view entity" syntax you wouldn't get any DDIC view generated, right?

updates: This "where used" feature is available from S4 onwards, which I missed to add before.


So let's build it, the good point is SAP keeps everything in some table at the end. The utility can search:

  1. Any programs which might be using the CDS you have entered as an input

  2. Any parent CDS (VDM) which is using the input CDS


Disclaimer: The coding may have bugs and have ample scopes of improvement, so feel free to get this tuned / tailored, the way you want. 

 
REPORT zcds_utility.

TYPES:BEGIN OF ty_ddls_w,
ddls TYPE ddlname,
o_type TYPE trobjtype,
obj_name TYPE progname,
END OF ty_ddls_w,

BEGIN OF ty_funcm,
funcname TYPE rs38l_fnam,
pname TYPE pname,
END OF ty_funcm,

ty_ddls_t TYPE STANDARD TABLE OF ty_ddls_w WITH EMPTY KEY,
ty_funcm_t TYPE STANDARD TABLE OF ty_funcm WITH EMPTY KEY.

DATA:w_ddls_f TYPE string,
t_ddls_w TYPE ty_ddls_t,
t_func TYPE ty_funcm_t.

SELECTION-SCREEN: BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-001.

SELECTION-SCREEN SKIP 1.

SELECTION-SCREEN BEGIN OF LINE.
PARAMETERS:p_rad1 RADIOBUTTON GROUP rb1.
SELECTION-SCREEN COMMENT 5(20) comment1.
PARAMETERS: p_ddls1 TYPE ddlname.
SELECTION-SCREEN END OF LINE.

SELECTION-SCREEN SKIP 1.

SELECTION-SCREEN BEGIN OF LINE.
PARAMETERS:p_rad2 RADIOBUTTON GROUP rb1.
SELECTION-SCREEN COMMENT 5(20) comment2.
PARAMETERS: p_ddls2 TYPE ddlname.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN:END OF BLOCK b1.

AT SELECTION-SCREEN OUTPUT.

comment1 = 'CDS Where Used:'.
comment2 = 'CDS Components:'.

CLASS lcl_event_handler DEFINITION.

PUBLIC SECTION.

TYPES:BEGIN OF lty_source_code,
src_cd TYPE char1000_idoc,
END OF lty_source_code.

DATA:
lo_alv TYPE REF TO cl_salv_table,
lt_alv TYPE ty_ddls_t.


METHODS constructor
IMPORTING
i_alv TYPE REF TO cl_salv_table.

METHODS on_double_click
FOR EVENT if_salv_events_actions_table~double_click
OF cl_salv_events_table
IMPORTING row column.

ENDCLASS.

CLASS lcl_event_handler IMPLEMENTATION.

METHOD constructor.
lo_alv = i_alv.
ENDMETHOD.

METHOD on_double_click.

DATA: lt_source_cd TYPE STANDARD TABLE OF lty_source_code,
l_obj_name TYPE progname,
l_type TYPE trobjtype,
l_ddls TYPE ddlname.

CHECK column = 'OBJ_NAME'.

l_obj_name = lt_alv[ row ]-obj_name.
l_type = lt_alv[ row ]-o_type.
l_ddls = lt_alv[ row ]-ddls.

CASE l_type.

WHEN 'DDLS'.

TRY.
cl_dd_ddl_handler_factory=>create( )->read(
EXPORTING
name = CONV ddlname( to_upper( l_obj_name ) )
IMPORTING
ddddlsrcv_wa = DATA(ddlsrcv_wa) ).
CATCH cx_dd_ddl_read INTO DATA(exc).
cl_demo_output=>display( exc->get_text( ) ).
ENDTRY.
IF ddlsrcv_wa-source IS INITIAL.
cl_demo_output=>display( |Nothing found| ).
RETURN.
ENDIF.

cl_demo_output=>display( replace( val = ddlsrcv_wa-source
sub = |\n|
with = ``
occ = 0 ) ).

WHEN OTHERS.

*---get the source code (other then DDLS)
READ REPORT l_obj_name INTO lt_source_cd.
IF sy-subrc EQ 0.

DATA(l_source_code) = REDUCE string( INIT lv_src TYPE string
*---Don't consider ANY commented code
FOR lw_source IN lt_source_cd
INDEX INTO lv_index
WHERE ( table_line+0(1) NE '*' )
NEXT lv_src = to_upper( lv_src ) &&
space && to_upper( lw_source-src_cd ) && | LINE#: { lv_index }#| ).

CLEAR lt_source_cd.

DATA(l_search_pattern) = `(?:LINE#: (\d)+)(?=#[\w\s]+` && |{ l_ddls }| && `)`.
DATA(lv_result) = match( val = l_source_code
regex = l_search_pattern
case = abap_false ).
IF lv_result IS NOT INITIAL.
DATA(lv_line) = match(
val = lv_result
regex = `(?:LINE#:\s)([0-9]+)`
case = abap_false
).
SPLIT lv_line AT ':' INTO DATA(l_part1) DATA(l_part2).
CONDENSE l_part2 NO-GAPS.


ELSE.
MESSAGE |Object: { l_ddls }, has no direct usage| TYPE 'S'.
ENDIF.

ENDIF.
CALL FUNCTION 'RS_TOOL_ACCESS'
EXPORTING
operation = 'SHOW'
object_name = l_obj_name
object_type = l_type
position = COND char10( WHEN l_part2 = 0 THEN space ELSE ( l_part2 + 1 ) )
EXCEPTIONS
not_executed = 1
invalid_object_type = 2
OTHERS = 3.
IF sy-subrc <> 0.
* Implement suitable error handling here
ENDIF.
ENDCASE.
ENDMETHOD.

ENDCLASS.

START-OF-SELECTION.

CASE abap_true.

WHEN p_rad1.

IF p_ddls1 IS INITIAL.
MESSAGE 'Enter a CDS View to proceed!' TYPE 'S'.
LEAVE LIST-PROCESSING.
ENDIF.

w_ddls_f = '\TY:' && p_ddls1.

*---Find parent DDLS (if any)
SELECT * FROM ddls_ris_index
INTO TABLE @DATA(t_ddls_where_used)
WHERE used_artifact_fullname = @w_ddls_f.
IF sy-subrc EQ 0.
LOOP AT t_ddls_where_used REFERENCE INTO DATA(lo_ddls).
APPEND INITIAL LINE TO t_ddls_w REFERENCE INTO DATA(lo_ddls_wu).
SPLIT lo_ddls->used_artifact_fullname AT ':' INTO DATA(w_part1) DATA(w_part2).

lo_ddls_wu->ddls = w_part2.
lo_ddls_wu->o_type = 'DDLS'.
lo_ddls_wu->obj_name = lo_ddls->ddlsrc_name.
ENDLOOP.
ENDIF.

*----find all other ABAP Objects where input DDLS been used
SELECT name,
include,
CASE repo~subc

WHEN '1' THEN 'REPS'
WHEN 'K' THEN 'CLAS'
WHEN 'I' THEN 'INCL'
WHEN 'F' THEN 'FUGR'
ELSE 'UN'
END AS o_type

FROM wbcrossgt AS wb
LEFT OUTER JOIN reposrc AS repo
ON wb~include = repo~progname
INTO TABLE @DATA(lt_wbcrossgt)
WHERE otype = 'TY'
AND name = @p_ddls1
AND indirect = @space.
IF sy-subrc EQ 0.
SORT lt_wbcrossgt BY name include o_type.

*---Check for Function Modules
LOOP AT lt_wbcrossgt REFERENCE INTO DATA(lo_wbcross) WHERE o_type = 'UN'.
APPEND INITIAL LINE TO t_func REFERENCE INTO DATA(lo_func).
lo_func->funcname = lo_wbcross->include.
ENDLOOP.

IF t_func IS NOT INITIAL.
SELECT funcname,
pname
FROM tfdir INTO TABLE @DATA(t_tfdir)
FOR ALL ENTRIES IN @t_func
WHERE funcname = @t_func-funcname.
IF sy-subrc EQ 0.
SORT t_tfdir BY funcname.
ENDIF.
ENDIF.

LOOP AT lt_wbcrossgt REFERENCE INTO lo_wbcross.
APPEND INITIAL LINE TO t_ddls_w REFERENCE INTO lo_ddls_wu.

IF lo_wbcross->o_type = 'UN' AND line_exists( t_tfdir[ funcname = lo_wbcross->include ] ).
lo_ddls_wu->ddls = p_ddls1.
lo_ddls_wu->o_type = 'FUNC'.
lo_ddls_wu->obj_name = lo_wbcross->include.
ELSE.

lo_ddls_wu->ddls = p_ddls1.
lo_ddls_wu->o_type = lo_wbcross->o_type.
lo_ddls_wu->obj_name = lo_wbcross->include.
ENDIF.

ENDLOOP.

ENDIF.


WHEN p_rad2.
MESSAGE 'This feature, not yet Supported' TYPE 'S'.
LEAVE LIST-PROCESSING.
ENDCASE.

IF t_ddls_w IS NOT INITIAL.

CALL METHOD cl_salv_table=>factory
IMPORTING
r_salv_table = DATA(lo_alv1)
CHANGING
t_table = t_ddls_w.

IF lo_alv1 IS BOUND.
lo_alv1->get_functions( )->set_all( abap_true ).
lo_alv1->get_columns( )->set_optimize( abap_true ).

DATA(lo_evt_handler) = NEW lcl_event_handler( lo_alv1 ).
DATA(lo_events) = lo_alv1->get_event( ).
SET HANDLER lo_evt_handler->on_double_click FOR lo_events.

lo_evt_handler->lt_alv = t_ddls_w.
lo_alv1->display( ).
ENDIF.

ELSE.

MESSAGE 'No records found!' TYPE 'S'.
LEAVE LIST-PROCESSING.

ENDIF.

Conclusion:


This utility perhaps can save some time and get you to the right piece of program / DDLS where the CDS being used. Double clicking will open the exact line of code or DDLS which you were looking for.

Please share your feedback and any issues you have encountered while using it. As I said, I didn't test all the possible ways so good to know from you.

Thanks,

Somnath
3 Comments
Labels in this area