How to improve the ADT Class Runner with additiona... - SAP Community
source link: https://community.sap.com/t5/technology-blogs-by-members/how-to-improve-the-adt-class-runner-with-additional-features/ba-p/13673454
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
What is a Class Runner?
A class runner is a great tool to test code snippets and run code directly from ADT. You can even write a simple log to the console in Eclipse.
What can be improved?
When using multiple systems and complex projects I got annoyed at some point in time, that I don't know from which system the last log was, when it was written by which runner and if the last execution has finished or failed maybe.
Thats when I started my own class runner that have some improved capabilities.
How does it look like?
The output looks like this:
- You see when, what, by whom and where it was started.
- For every log entry you get a timestamp.
- You see when the execution finished.
- All times and dates are formatted in your personal date and time format
What about the ABAP code? Your code gets defined in the logic() method.
CLASS zcl_runner_demo DEFINITION
PUBLIC
INHERITING FROM zcl_base_runner
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
METHODS: logic REDEFINITION.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_runner_demo IMPLEMENTATION.
METHOD logic.
write( `Hello World` ).
write( `this is a demo of the enhanced class runner` ).
write( 123 ).
ENDMETHOD.
ENDCLASS.
Methods write() and out->write()
The write() method has the same signature as the out->write() method, you can even access the original out->write() if needed.
METHOD logic.
write( `Hello World` ).
write( `this is a demo of the enhanced class runner` ).
write( 123 ).
out->write( `bare write` ).
ENDMETHOD.
of course you can pass structured and table data to write(), like you can do to out->write()
METHOD logic.
DATA ls_airport type /dmo/airport.
write( `Hello World` ).
ls_airport = value #( airport_id = 'SAP' city = 'Dokkerland' ).
write( ls_airport ).
write( name = 'Info about airport' data = ls_airport ).
ENDMETHOD.
Uncaught exceptions
Method logic is secured against uncaught exceptions.
METHOD logic.
write( `Hello World` ).
raise EXCEPTION new cx_abap_invalid_name( ).
ENDMETHOD.
It logs the behaviour:
How does it look under the hood?
It is basically an abstract class that wraps the original ADT class runner:
"! <p class="shorttext synchronized" lang="en">Base Runner</p>
"! Improved class runner with enhanced logging capabilities
CLASS zcl_base_runner DEFINITION
PUBLIC
ABSTRACT
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun .
"! <p class="shorttext synchronized" lang="en">This method implements your logic</p>
"! You can use { .METH:write } with enhanced capabilities or the { .DATA:out }->write( ) for plain logging.
"! @raising cx_root | <p class="shorttext synchronized" lang="en">any exception not caught, will be handled in the runner.</p>
METHODS logic ABSTRACT
RAISING cx_root.
CLASS-METHODS convertuuid
IMPORTING
str TYPE string
RETURNING VALUE(rv_uuid) TYPE sysuuid_c32.
PROTECTED SECTION.
DATA out TYPE REF TO if_oo_adt_classrun_out.
"! <p class="shorttext synchronized" lang="en">wrapper for out->write( )</p>
"! this enhances the default function by writing a timestamp.
"! this method should be used in {@link .METH:logic }
"! @parameter data | <p class="shorttext synchronized" lang="en"></p>
"! @parameter name | <p class="shorttext synchronized" lang="en"></p>
METHODS write
IMPORTING
data TYPE any
name TYPE string OPTIONAL.
PRIVATE SECTION.
"! <p class="shorttext synchronized" lang="en">determine the current timestamp and returns as string</p>
"! <ul><li>in users timezone</li><li>in users prefered format</li></ul>
"! @parameter rv_dateandtime | <p class="shorttext synchronized" lang="en"></p>
CLASS-METHODS getCurrentDateandTimeFormatted
RETURNING VALUE(rv_dateandtime) TYPE string.
"! <p class="shorttext synchronized" lang="en">draws a horizontal line on the console</p>
"!
"! @parameter out | <p class="shorttext synchronized" lang="en"></p>
CLASS-METHODS horizontalLine
IMPORTING out TYPE REF TO if_oo_adt_classrun_out.
ENDCLASS.
CLASS zcl_base_runner IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
me->out = out.
horizontalline( out ).
TRY.
out->write( |Start on { xco_cp=>current->tenant( )->get_url( io_type = xco_cp_tenant=>url_type->ui )->get_host( ) } runner { cl_abap_classdescr=>get_class_name( me ) } by { cl_abap_context_info=>get_user_formatted_name( ) }| &&
| at { getcurrentdateandtimeformatted( ) }| ).
CATCH cx_abap_context_info_error INTO DATA(lc_context_error).
"handle exception
out->write( 'Error occured in determine current user:' ).
out->write( lc_context_error->get_text( ) ).
ENDTRY.
TRY.
me->logic( ).
CATCH cx_root INTO DATA(lc_error).
"handle exception
write( 'Error occured in executing the logic:' ).
write( lc_error->get_text( ) ).
DATA(previous) = lc_error->previous.
IF lc_error->previous IS BOUND.
write( name = 'Previous' data = lc_error->previous->get_text( ) ).
ENDIF.
ENDTRY.
out->write( |Done at { getcurrentdateandtimeformatted( ) }| ).
horizontalline( out ).
ENDMETHOD.
METHOD write.
DATA(descr_ref) = cl_abap_typedescr=>describe_by_data( data ).
IF name IS INITIAL.
IF descr_ref IS INSTANCE OF cl_abap_elemdescr.
out->write( data = |{ getcurrentdateandtimeformatted( ) }: { data }| ).
ELSE.
out->write( data = |{ getcurrentdateandtimeformatted( ) }:| ).
out->write( data = data ).
ENDIF.
ELSE.
IF descr_ref IS INSTANCE OF cl_abap_elemdescr.
out->write( data = |{ getcurrentdateandtimeformatted( ) }: { Name }:{ data }| ).
ELSE.
out->write( data = |{ getcurrentdateandtimeformatted( ) }: { Name }:| ).
out->write( data = data ).
ENDIF.
ENDIF.
ENDMETHOD.
METHOD getcurrentdateandtimeformatted.
DATA tsp TYPE tzntstmps.
DATA(lo_unix_timestamp) = xco_cp=>sy->unix_timestamp( ).
DATA(lo_moment) = lo_unix_timestamp->get_moment( xco_cp_time=>time_zone->user ).
tsp = lo_moment->as( xco_cp_time=>format->abap )->value.
rv_dateandtime = |{ tsp TIMESTAMP = USER }|.
ENDMETHOD.
METHOD horizontalline.
out->write( repeat( val = '-' occ = 120 ) ).
ENDMETHOD.
METHOD convertuuid.
DATA(lo_uuid) = xco_cp_uuid=>format->c36->to_uuid( str ).
rv_uuid = xco_cp_uuid=>format->c32->from_uuid( lo_uuid ).
ENDMETHOD.
ENDCLASS.
Summary
The improved class runner is a tool that supports SAP NetWeaver , SAP S/4HANA and SAP BTP, ABAP environment , basically everywhere the class runner is supported.
I put in a function for UUID conversion that I used in one of my last projects a lot, of course its optional.
It would be easy to extend this logic for application job execution too. All you need is an additional wrapper that rewrites the write method to append an application log and calls the logic method from the application job.
Feel free to share, reuse and enhance this idea.
If you like this post or it helped you, don't hesitate to give kudos.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK