Quantcast
Channel: ABAP Development
Viewing all 948 articles
Browse latest View live

The case of source compare utility

$
0
0

Hi,

 

Recently I was involve in complex development environment that was not working so well.....

 

The overhead of this adventure was the need to verify that the code was transported successfully form the development environment to multiple target systems .

 

Usually for small scale changes the split screen editor is sufficient but when we are talking about multiple programs, functions, class, and interfaces the job become tedious and error prone.

 

Fortunately I found some documents about functions RS_CMP_COMPUTE_DELTA and RPY_PROGRAM_READ and using those I wrote program Z_R_EITAN_TEST_15_02 .

 

The program was written using 740 and use a little bit of "String Templates" (those funny looking {})

 

The program is quite new (there might be some bugs there...) but gain some experience in the field....

 

Lets check a a program:

 

 

The result:

 

List of include:

 

 

If there is a discrepancy we get:

 

 

It was a nice surprise to find out that class work as well !!!!

 

The hot spot takes us to SE24

 

 

Any comment is welcome.

 

Enjoy.


How to perform an ATC check automatically during transport TASK release

$
0
0

The ABAP Test Cockpit (ATC) can easily be configured to check every transport request that is released.

 

But in case you are using transport of copies to import into the quality/test system (for example if you use SAP ChaRM for transport management), it is not possible in the standard to perform the ATC checks automatically when transporting from development to quality/test system.

 

On the other hand, in various places, for example the SAP Code Inspector book by Randolf Eilenberger and others, it is described how to trigger a Code Inspector test for every transport task release.

 

I have not yet found a description how to call the ATC automatically, when a transport task is released.

 

If this is what you want in your development system, you only have to implement one method in an implementation of BAdI CTS_REQUEST_CHECK:

 

METHOD if_ex_cts_request_check~check_before_release.

 

  DATA is_ok TYPE abap_bool VALUE abap_true.

 

  SELECT SINGLE trfunction, strkorr FROM e070 WHERE trkorr = @request

                              INTO (@DATA(trfunction), @DATA(strkorr)).

  ASSERT sy-subrc = 0.

  " only process release of transport tasks,

  " not transport requests.

  " And only customer code (not repairs, not customizing).

  CHECK strkorr IS NOT INITIAL AND trfunction = 'S'.

 

  TRY.

      DATA(or_factory) = NEW cl_satc_api_factory( ).

      DATA(it_objects) = cl_satc_object_set_factory=>create_for_transport( request

                                                             )->if_satc_object_set~get_object_keys( ).

      DATA(or_objects) = cl_satc_object_set_factory=>create_for_object_keys( it_objects ).

 

      DATA(or_variant) = NEW cl_satc_ci_check_variant( ).

      or_variant->set_name( 'Z_STANDARD' ).  " replace with your check variant

      DATA(or_run_config) = or_factory->create_run_config_with_chk_var( EXPORTING i_object_set = or_objects

                                                                                                                  i_check_variant = or_variant

                                                                                                                  i_description = |Transport release { request } | ).

      DATA(or_run_controller) = or_factory->create_run_controller( or_run_config ).

      or_run_controller->run( IMPORTING e_result_access = DATA(or_result_access) ).

      or_result_access->get_findings( IMPORTING e_findings = DATA(it_f) ).

      LOOP AT it_f ASSIGNING FIELD-SYMBOL(<wa_f>) WHERE ( kind = 'E' OR kind = 'W' ) " errors/warnings

                                                    AND exceptn<> 'P'. " pseudo comments and pragmas

        is_ok = abap_false.

        EXIT.

      ENDLOOP.

    CATCH cx_satc_failurecx_satc_not_found INTO DATA(cx).

      DATA(exc_text) = cx->get_text( ).

      MESSAGE exc_text TYPE 'E'.

      is_ok = abap_false.

    CATCH cx_satc_empty_object_set cx_satc_invalid_argument INTO cx" ok, if transport is empty or contains only non-checkable objects

  ENDTRY.

 

  IF is_ok = abap_true.

    MESSAGE s007(zs_dev_tools_local).  " success message - create your own message

  ELSE.

    MESSAGE s008(zs_dev_tools_local).  " failure message - create your own message

    " we only get the execution ID with this "dirty" cast:

    DATA(or_result_access_int) = CAST cl_satc_result_access( or_result_access ).

    CALL FUNCTION 'SATC_AC_DISPL_RESULT_BY_EXEC'

      EXPORTING i_execution_id = or_result_access_int->if_satc_result_access~result_id

      EXCEPTIONS

        xpt_no_results     = 1

        xpt_not_authorized = 2

        xpt_display_used   = 3

        OTHERS             = 4.

    ASSERT sy-subrc = 0.

    RAISE cancel.

  ENDIF.

ENDMETHOD.

 

(This coding uses some of the new 7.40 SP08 language features, so you may have to adapt it.)

 

That’s it, basically.

 

I noted however, that include programs are not tested when transported on their own, because the ATC methods that I call only test frame programs (type 1 reports, classes, function groups). I did not find an easy way to overcome this using standard ATC framework functions, so I programmed it in a local class with the following methods:

 

  CLASS-METHODS:

      enrich_main_programs

        CHANGING c_it_keys                  TYPE if_satc_object_set=>ty_object_keys,

      is_include_program

        IMPORTING i_object                    TYPE if_satc_object_set=>ty_object_key

        RETURNING VALUE(r_is_include_program) TYPE abap_bool,

      get_main_programs_for_include

        IMPORTING i_object    TYPE if_satc_object_set=>ty_object_key

        RETURNING VALUE(r_it) TYPE if_satc_object_set=>ty_object_keys,

      is_mainprog_included

        IMPORTING

                  i_it_mainprogs    TYPE if_satc_object_set=>ty_object_keys

                  i_it_current_keys TYPE if_satc_object_set=>ty_object_keys

        RETURNING VALUE(r) TYPE abap_bool,

 

  METHOD enrich_main_programs.

    LOOP AT c_it_keys ASSIGNING FIELD-SYMBOL(<wa>).

      IF is_include_program( <wa> ).

        DATA(it_main_programs) = get_main_programs_for_include( <wa> ).

        IF it_main_programs IS NOT INITIAL

           AND NOT is_mainprog_included( EXPORTING i_it_mainprogs = it_main_programs

                                                   i_it_current_keys  = c_it_keys ).

          INSERT it_main_programs[ 1 ] INTO TABLE c_it_keys.

        ENDIF.

      ENDIF.

    ENDLOOP.

  ENDMETHOD.

 

  METHOD is_include_program.

    r_is_include_program = abap_false.

    CHECK i_object-obj_type = 'PROG'.

    SELECT SINGLE subc FROM reposrc WHERE progname = @i_object-obj_name AND subc = 'I'

                                           INTO @DATA(subc) ##warn_ok##needed.

    IF sy-subrc = 0.

      r_is_include_program = abap_true.

    ENDIF.

  ENDMETHOD.

 

  METHOD get_main_programs_for_include.

    DATA it_mainprogs LIKE STANDARD TABLE OF i_object-obj_name.

    DATA wa LIKE LINE OF r_it.

    CLEAR r_it. " if there are no main programs, return initial

    CALL FUNCTION 'RS_GET_MAINPROGRAMS'

      EXPORTING

        name         = i_object-obj_name

      TABLES

        mainprograms = it_mainprogs

      EXCEPTIONS

        cancelled    = 1

        OTHERS       = 2.

    ASSERT sy-subrc = 0.

    wa-obj_type = 'PROG'.

    LOOP AT it_mainprogs ASSIGNING FIELD-SYMBOL(<wa>).

      wa-obj_name = <wa>.

      INSERT wa INTO TABLE r_it.

    ENDLOOP.

  ENDMETHOD.

 

  METHOD is_mainprog_included.

    r = abap_false.

    LOOP AT i_it_mainprogs ASSIGNING FIELD-SYMBOL(<wa>).

      READ TABLE i_it_current_keys WITH KEY obj_type = <wa>-obj_typeobj_name = <wa>-obj_name

                                  TRANSPORTING NO FIELDS.

      IF sy-subrc = 0.

        r = abap_true.

        RETURN.

      ENDIF.

    ENDLOOP.

  ENDMETHOD.

 

Now, enrich_main_programs() needs to be called to change it_objects after the statement that is creating it_objects.

 

Edit 25.04.2016: exception handling for cx_satc_invalid_argument added.

Easily count custom code (Z Code) lines in your system

$
0
0

One of my colleague asked this question and I found that it is very easy to get the custom lines count in your server. Here is how.

 

1. Goto Tcode /SDF/CD_CCA =>Select "SAP Clone Finder"

 

2. In the field "Customer Namespace" provide "/0CUST/".

 

3. Keep all other fields empty.

 

4. Select "Similarity Check Off"

 

1.PNG

 

5. Run. (F8)

 

6. Select the "Object Size" column and hit "Total" button.

2.PNG

 

You have your Count of Custom Code in your system.

My CDS view self study tutorial - Part 7 unveil the secret of @ObjectModel.readOnly

$
0
0

 

Almost one month has passed since my last tutorial and now I am able to build a useful UI5 application with CDS view + Smart template

 

See my study result recently:


Now let me continue the self study tutorial.


In my application with edit function enabled, I have set posting date as read only by using the annotation below according to sap help.

clipboard1.png

It works as expected in the runtime. However, why it works? Being a developer, I hate the fact that these whole stuff work as a black box to me. I want to know what happens under the hood. Here below I will share with you how I dig it out via debugging in both frontend and backend.

clipboard2.png

1. Debugging in UI5 application

 

In Chrome development tool, I know that the editable state is controlled by property "editable" of the given UI model.

clipboard3.png


So set a breakpoint on SmartField.setEditable function as below, then click edit button, we can observe the parameter bValue is passed as false into this function. Now next question, how and where is this bValue calculated to false?

clipboard4.png

From the callstack I can find another important function: canUpdateProperty. Inside this function, from line 241 we can get this conclusion: any property with attribute "sap:updatable" equals to false, will be rendered as read only in UI.

clipboard5.png

Apparently this attribute is set in backend, as we can confirm by checking in metadata:

clipboard6.png

Now question to ABAP backend: I never specify any annotation like sap:updatable = false in my CDS view, where does it come from?

clipboard5.png

 

2. Debugging in ABAP backend

 

In this method, framework is scanning against annotation with name "OBJECTMODEL.READONLY", as defined in constant in line 836.

If found, ls_sfc-read_only is set as true.

clipboard7.png

This assignment will lead to the check succeeds in line 848 ( since by default a field is editable ), as a result an entry is inserted into internal table mt_element_static_field_ctrl.

clipboard10.png

This is the detail view of the entry for posting date in the table.

clipboard11.png

Later, the internal table is evaluated and if there is entry with read_only = abap_true existing ( see line 71 ), lv_creatable and lv_updatable is set as false.

clipboard12.png

Finally in line 82 and 85, lv_creatable and lv_updatable are used to set property accordingly. All secrets are published now!

clipboard13.png

My CDS view self study tutorial - Part 8 my summary of different approaches for annotation declaration and generation

$
0
0

 

During my recent CDS view explore I have experienced several ways of CDS view annotation declaration or generation. I list them in this blog for study purpose.

 

Approach 1: developer does not declaration explicitly, but backend generates automatically

 

Take this field for example:

clipboard1.png

I do not declare any display format on this field. It has DATS data type in the backend.

clipboard2.png

When you publish this CDS view as OData service and check its metadata response, you can find the annotation "sap:display-format=Date" is automatically added. Who adds it?

clipboard3.png

Answer: it is added here. Backend framework will automatically add corresponding annotation according to the data type of exposed field.

clipboard4.png

Approach 2: developer adds one style of annotation, and backend framework detects such annotation, and do some conversion

 

One example of this kind of approach can already be found from tutorial 7 - unveil the secret of @ObjectModel.readOnly


In that tutorial I explained how the annotation defined by developer ( @ObjectModel.readOnly: true ) is converted by backend framework into sap:updatable = false.

 

@ObjectModel.readOnly: true

 

Z_i_Order_View.posting_date

 

We can also look into another example. We have use the following annotation "@Consumption.valueHelp: '_statusfixedvalue' " to assign a value help to field txt04:

 

@Consumption.valueHelp: '_statusfixedvalue'

Z_i_Order_View.txt04,

 

When framework has scanned the annotation in line 47, it will set flag lv_consumption_vh as true.

clipboard6.png


Base on the fact whether the assigned value help is a consumption or foreign key value help, different element name are put to internal table lt_param_display and finally all the left annotation necessary for value help is generated by framework:

clipboard7.png

And this picture below explains where does each field in metadata response come from. The logic in method _add_value_help is very useful as it teaches us how to create necessary annotation via ABAP code, which we will use later.

clipboard8.png

Approach 3: developer adds necessary annotation via ABAP code

If you would like to build a drop down list based on a CDS view field like the status field below,

clipboard9.png

it is not just enough to use the annotation "Consumption.valueHelp" in CDS view source code - you would just get a drop down list with technical code of status value displayed. Instead, you must tell Smart template framework to display status description text in drop down list.

clipboard10.png

In order to archieve it, you must add the following ABAP code in DEFINE method of the MPC_EXT class of your OData service, to tell the framework that the text property for "status_code" is "status_text" by annotation. The usage of such coding to create annotation by ABAP code is learned from method _add_value_help mentioned in approach 2.


lo_txt_property = model->get_entity_type( 'Z_C_Status_FixedvalueType' )->get_property( 'status_code' ).

lo_txt_property->set_value_list( /iwbep/if_mgw_odata_property=>gcs_value_list_type_property-fixed_values ).

lo_text_anno = lo_txt_property->/iwbep/if_mgw_odata_annotatabl~create_annotation( 'sap' ).

lo_text_anno->add( iv_key = 'text' iv_value = 'status_text').

 

For details please refer to this blog How to build a drop down list using Smart template + CDS view

 

Approach 4: developer adds UI related annotation in CDS view which are consumed by UI5 SmartTemplate

 

All UI related annotation which could be inserted into CDS view source code could be found from SAP help.

 

Those UI annotations will not be converted by ABAP backend:

 

@UI.identification: [ { position: 10 } ]

Z_i_Order_View.posting_date

 

All UI related annotations could be retrieved via the url below:

clipboard1.png

And in the runtime, SmartTemplate also uses this very url to retrieve UI annotations so that it can know what styles of UI control the annotated CDS view field must be rendered as.

clipboard2.png

 

Conclusion

For approach 1 & 2, they sometimes look mysterious as everything happens under the hood. Fortunately we are in ABAP world and we can debug everything to clarify what confuses us by ourselves

 

Select-options to RFC_READ_TABLE options

$
0
0

Hello.

 

This is not going to be rocket-science, but after searching SCN for some time not finding the answer/code I needed, but realizing that many people have the same/similar requirement to mine, I decided to share this code via this blog.

 

Summary:

* you have a report with select-options

* you need to collect data from remote systems and despite all the warnings that the RFC_READ_TABLE function module should not be used (although it is used in zillions of SAP standard programs as well as customer programs so it is zero chance SAP would ever change or remove this function module, I would say), you decided to go for RFC_READ_TABLE.

* you need to transfer the complex selection provided by the user to the remote system because downloading all the data to the local system and deleting the data based on the selection locally is just so inefficient and slow (try transferring huge tables via RFC once and you will understand why this blog...)

* ...which means you need to transfer the select-options to the remote system, because the selection is much smaller and faster to transfer than all the data in the table you need to download

 

Here is the code you need...

* first comes the part of the WHERE clause that you can easily specify manually/hardcode in the source code, because it never changes

* then comes the conversion of one select-option (so for more select-options you need to do this several times)

* ...and finally comes the code that puts the two together

 

cheers Otto

 

 DATA lt_options TYPE tt_option.   DATA lt_selopt TYPE TABLE OF ddshselopt.   DATA ls_selopt LIKE LINE OF lt_selopt.   DATA ls_option LIKE LINE OF et_options.   DATA lv_where TYPE string.   FIELD-SYMBOLS <so_fld> LIKE LINE OF so_fld.
 CLEAR ls_option.   CONCATENATE 'FROM_DAT <= ''' sy-datum ''' AND TO_DAT >= ''' sy-datum '''' INTO ls_option.   APPEND ls_option TO et_options.
CLEAR: lt_selopt[].   LOOP AT so_fld ASSIGNING <so_fld>.     CLEAR: ls_selopt.     MOVE-CORRESPONDING <so_fld> TO ls_selopt.     ls_selopt-shlpfield = 'FIELD'.     APPEND ls_selopt TO lt_selopt.   ENDLOOP.
CLEAR lv_where.   CALL FUNCTION 'F4_CONV_SELOPT_TO_WHERECLAUSE'     IMPORTING       where_clause = lv_where     TABLES       selopt_tab   = lt_selopt.   CLEAR: lt_options[].   PERFORM convert_where_to_rfc_options USING lv_where CHANGING lt_options.   IF lt_options IS NOT INITIAL.     APPEND 'AND' TO et_options.     APPEND LINES OF lt_options TO et_options.     CLEAR lt_options[].   ENDIF.
FORM convert_where_to_rfc_options USING iv_where TYPE rsstring CHANGING et_options TYPE tt_option.   DATA lv_where LIKE iv_where.   DATA lv_bit TYPE so_text.   DATA lv_len TYPE int4.   IF iv_where IS INITIAL.     RETURN.   ENDIF.   CLEAR lv_where.   lv_where = iv_where.   DO.     IF lv_where IS INITIAL.       EXIT.     ENDIF.     CLEAR lv_len.     lv_len = strlen( lv_where ).     IF lv_len <= 72.       APPEND lv_where TO et_options.       EXIT.     ELSE.       lv_bit = lv_where.       lv_len = 71.       DO 71 TIMES.         IF lv_bit+lv_len(1) = ' '.           EXIT.         ENDIF.         lv_len = lv_len - 1.       ENDDO.
*** Index of the last space is in LV_LEN now.       APPEND lv_bit(lv_len) TO et_options.       lv_where = lv_where+lv_len.     ENDIF.   ENDDO.
ENDFORM.

HCM Processes and Forms for a Newbie in ABAP HR

$
0
0

Hi All,

 

Up until now I had never worked on ABAP HR, it always did sound very different and is very different also! Always had my fears in logical databases. But then I guess I was very unaware of other interesting things that were part of SAP HR one of them being the HCM Processes and Forms.

 

Beautiful concept introduced by SAP to have SAP HR processes viewed/updated in forms with minimal coding efforts. I really got blown away by this! Entire HR processes can be viewed into custom designed forms, both in Adobe and FPM. You see the beauty of these HCM Processes and forms are that we don't have to worry about DB updates, all taken care by SAP standard. Fields and its attributes can defined in one single place and the form will display it accordingly.

 

It also has the option for integrate it with an SAP workflow, more fun added to it.

 

Its exactly like an configuration!

 

Before I forget yes we can do real coding to make it behave as per requirements, BADi makes it is further easy and before you wonder off thinking where and all, the BADi's can be created within the form itself.

 

One stop for configuring, designing, and coding.

 

One more thing these forms can also be integrated with SAP Fiori!

Editor's Block Mode

$
0
0

I think erveryone knows the block mode of the edtor where you can select a block of characters while holding down the ALT-key.

2016-04-28_15-09-35.jpg

 

Did you know, that you can replace ALL of the selected characters at once?

Just type the new text and it will be changed instantly on all selected characters.

 

See video:

 

To have some more text in here let me close with the common scn salutation:

 

Reward points if helpful

Enno


BRFplus conquers the Whirling Circle of DEATH

$
0
0

BRFplus vs the Whirling Circle of Death


Hourglass.GIF

This story has a happy ending....

 

I have been playing around with BRFplus now, for many years, ever since a spent one winter reading the SAP Press book on the subject every work lunchtime, when I was in the beer garden around the corner from the office in Heidelberg.

 

I have used it in my day to day job for various things, and wrote a chapter on the subject in my own SAP Press book. In the course of all this I used the BRF workbench in version 7.02, 7.31 and 7.40 of ABAP.

 

In every case I found the performance of the workbench to be appalling. I would spend half the time staring at the whirling circle on the screen, which appeared every time I did a drop down, or pressed enter, any sort of round trip. As for both decision tables and decision trees entering every single value takes about a million button presses this was, as can be imagined, torture, or as I had to endure one million whirling circles for every branch of the decision tree.

 

Well, times move on, and at the moment I am writing the second edition of my book and this time I have a 7.50 system to play with. That makes me a very happy bunny, but when the time came to once again turn to BRF+ I thought to myself "my new system is a test system, it is physically in Singapore". I am in Sydney and all my previous systems had been physically in Melbourne. I had worried the extra latency would make matters even worse.

 

Anyway, before I got going, I emailed the inventor of BRF+, Carsten Zeigler, and asked him had much changed between 7.40 and 7.50. He said that most improvements these days were going into the add-on product DSM, makes sense to me, SAP has to make money after all, and that would explain why the appearance of the screens had not changed between 7.40 and 7.50, when they had changed vastly between 7.02 and 7.40, but for the core BRF+ product that there was a corker of an OSS note that could vastly improve performance all over the shop.

 

This is OSS Note 2280740. I downloaded it, it had a syntax error, since I now had a direct line to SAP a new version of the note came out within 24 hours, I downloaded that and all was well.

 

I can now report that all my whirling circle woes are gone. You still have to press a lot of buttons, that will change in the future I am assured, but at least I do not have to watch my good old mate the circle whirling away all day. I don't see it at all now, once the very first time the program compiles, and never again. And this is with the extra latency.

 

So, this is wonderful news. Previously whenever I had tried to demonstrate this to anybody (the big delay) the little man inside the computer figured out what I was up to and sped up the application whilst I was screen sharing or trying to do a ScreenCam, and then slowed it back down when I was on my own again. The little men inside the computer are like that, I have the same situation at work, if someone calls me over, whatever is broken fixes itself for the duration I am staring at the screen, and the problem re-occurs when I walk off.

 

Once I solved the problem by turning my back on the screen and shouting "I'm not looking, I'm not looking!" while an accomplice recorded a video on their phone of what the user was doing. That technique worked, the problem occurred of course under those laboratory conditions.

 

Anyway, moving back to the previous poor performance of BRF+ that bad performance had given me a rather skewed negative view of Web Dynpro applications. The only two I ever used were BRF+ and the leave request, and both were very "circly".

 

And whatever happened to the hourglass anyway? What did it ever do to be consigned to the dustbin of history? I bet it is lying in a gutter somewhere, drinking meths, and complaining about the injustice of it all.

 

Anyway, it can't be Web Dynpro that was the problem, as now the BRF+ performance is fine. I still think Web Dynpro looks hideous, worse than the SAP GUI if that's possible, but that is by the by.

 

So, the moral of the story is, if you use BRF+, and have a 7.31 system or higher, apply the good old note 2280740 and see what happens. It changes about one billion classes and methods (the ones that start with FDT (Funky Decision Tool, the original name for BRF+)) all for the better.

 

So I told Cartsen that the note worked and he said great, could I write a blog about the improvements I had encountered. This has been it, though I imagine he may be somewhat puzzled by the rambling, incoherent, nature of it....

 

Cheersy Cheers

 

Paul

News about ABAP Package Concept: Naming Conventions for Package Hierarchies

$
0
0

In this blog entry I’ll describe impact of OSS note 2297645 for ABAP development: https://launchpad.support.sap.com/#/notes/2297645/ . For me this is a very important ABAP innovation. SAP Partners and software architects now can optimize existing ABAP packages according state-of-the-art development:

  • We need smaller and sometimes encapsulated packages to develop small and innovative applications like Fiori and UI5 apps.
  • We can start to split up huge development classes into smaller ones to improve the software structure. This is a chance: software is getting more transparent and can be maintained with lesser costs.
  • We encapsulate existing objects like CDS objects to prevent dangers of reuse (think of CDS for BI vs. CDS for BI for example).

 

This is now possible by keeping existing naming conventions. This allows customers and partners to create modern package hierarchies like SAP does in the following picture:

SFDT.PNG

 

The BRFplus framework is developed as subpackages of the package SFDT where all development object have a same namespace prefix FDT_. Modern SAP solution have this property (BRFplus is just an example):

  • It has a welldefined structure which helps to understand the solution and makes maintenance easier.
  • The development process becomes easier since one can define responsibilities for development object on the level of packages.
  • There is a common namespace prefix which is necessary in a complex development landscape.

 

The package concept is really cool since it allows you split up huge packages into smaller one according different concerns. The benefit is a better software modularization which is necessary for modern ABAP developemt containing of smaller applications and new interface technology (Fiori & OData), operational reporting (CDS and BW on ERP) and so on. I already blogged about it in a series of blogs, f.e. ABAP Package Concept Part 4 – How to perform package checks. Please remark that this blog is not about package concept - I will show how to use it together with existing ("legacy") naming conventions.

 

Development Classes and Naming Conventions – A look back into the Past

At the beginning of every ABAP development project development packages and naming conventions are defined. The central note https://launchpad.support.sap.com/#/notes/84282/EN described how it goes:

84282.PNG

 

I give you a small example: For FI development often development packages like /ACME/FI have been introduced and the object names started with a namespace prefix /ACMR/FI_. This is necessary to avoid duplicate objects especially in complex system landscapes. According OSS note 84282 you can define the name range a transparent table TRESN which is displayed in the following picture.

FI.PNG

 

With this entry in maintenance view V_TRESN following is guaranteed:

  • There is a check which prevents that an object starting with a different name prefix can be assigned to this package.
  • And if an object is created there is a proposal for the correct package according to the namespace prefix.

 

This is extremely useful especially in larger development projects where software is transported between different development systems and we have to avoid clashes in naming conventions. Those naming conventions also make it possible to redesigning systems by moving software into a deeper software component.

 

Please be also aware that such checks are also possible (perhaps somewhat limitated) with check programs like Code Inspector (transaction SCI). But usually those checks come much too late: Once an ABAP application is developed, object renamings are difficult and expensive.

But above TRESN definition has one disadvantage: a namespace can be assigned to a package but not a package hierarchy. So we can’t apply state of the art software structure like in the following example with SFDT: the SAP application BRFplus is contained in subpackages of the package SFDT and all objects have the same namespace prefix FDT_.

 

Unfortunately this is not possible with package SFDT_BRFPLUS because the name space prefix FDT_ can be assigned only to a single package (so far). This was changed with OSS note 2297645. No we can define a namespace prefix for a package hierarchy by choosing the value „H“ like it is done on the following picture:

FIH.PNG

The letter “H” in the picture means “hierarchical” since it allows one namespace prefix for a package hierarchy. Now we create subpackages of package /ACME/FI like /ACME/FI_ODATA, /ACME/FI_CDS… to introduce a proper software modularization and keep existing naming conventions.

 

Summary

One of the drawbacks of ABAP language is that development classes (now called packages) don’t define namespaces by themselves. Therefore we have to use namespace prefixes for development objects and checks at development time to prevent renamings.

 

Since the ABAP package concept moved on, the naming conventions for package hierarchies had to follow. And now it is here and ready to use!

ENHANCE YOUR CODING STYLE

$
0
0

     Imagine yourself in a situation where you are asked to explore about a topic by just an introductory heading.Seems like judging the contents of book by merely reading its title.Difficult,isn't it?

    Same happens for a beginner like me who at the first time gets confused between a table and a workarea. It is almost impossible to sail through the oceans of Function Modules and God forbid if you get across an OOPS object, you can find yourself hitting your head against the wall.You have to understand a code(not always yours) and if your luck runs out you have to make changes to it to meet a requirement. It sometimes also happened that it made me land into a serious confusion, while trying to understand my own code which I developed a few months ago.

 

    It was after sometime my colleague told me a secret so that no other person who works on same object faces the same fate like me. It is not a big thing but a minor thing that we all ignore or forget. It is 'POWER OF COMMENTING'. An object, however complex it maybe, becomes easy to understand if it has been properly described in comments about it.Moreover every person has a way of coding and doing things which are not easy to understand for others. Many of us find it boring and time consuming but if a new person works on an object developed by you in future,it becomes a lot easier.

  Proper commenting is a healthy practice to code. A simple comment can help you understand the reason for using a particular unknown FM or why is there a particular condition in select query. After leaving no stone unturned to understand coding,this is what I figured out about the magic of “Commenting”:


1.Increases Readability of Code

    It is always easy to go through a code if you know what a particular statement does.It can help you understand the gist quickly and understand your requirement easily.


2.Increases Navigation Speed

    Many times it happens you need to change a particular field or a particular part of code but it takes time to find its position in a lengthy code.Commenting makes it easier,just press Ctrl+F and search your field or module.


3.Avoids Confusion

    A new person can get confused if he/she sees a new object or even a select query he has no idea about.Proper comment,at proper places can help avoid that confusion.

  

   So where and what should we comment.The answer is, wherever you feel this part needs some description.For example


   In select queries:

select1.JPG

 

  To define what an include contains:


include.JPG



   To establish relationship between displayed and technical field name:

 

relation.JPG


  Or to simply make the code more understandable:

 

simple.JPG



Summary:

It is always easier to impart your knowledge of coding to others in a systematic simple way.This also benefits others in dealing with troubles and setting benchmarks for making coding a good learning exercise.


Afterall we all are here to 'LEARN AND DECODE' what SAP has to offer.Aren't we?

CL_DEMO_OUTPUT, Part 1 of 2 - Usage

$
0
0

In the ABAP Keyword Documentation, in SCN blogs or in other demos you might have recognized the usage of class CL_DEMO_OUTPUT. This blog in two parts will explain that class a little bit closer. Part 1 explains its usage while Part 2 will have a look behind the scenes.

 

Disclaimer

 

The classes described here are not intended for productive usage. You might use them in demonstration programs, local test programs or for temporary testing in productive programs. You must not use them productively in productive programs.

Motivation

 

From the beginning, ABAP lacked a simple way of outputting data for test or demonstration purposes (System.out.println(...) in Java or printf in C so to say). In the old SAP GUI days of classical dynpros you could use the MESSAGE statement for short outputs in information messages or you mainly (mis)used the WRITE statemtent for creating list output. Simple and straightforward - but only in executable programs (reports)! Already in classical dialog programs this kind of WRITE output failed. Even worse in service oriented programming using classes. And nowadays when programming ABAP in ADT for UI5 and FIORI? Don't ask. The class CL_DEMO_OUTPUT was invented as a demonstration, how this lack can be circumvented.


Methods of CL_DEMO_OUTPUT

 

The methods of class CL_DEMO_OUTPUT create simple outputs of data in example programs without the need of classical lists. The class can be used via static methods and instance methods. The following methods create output in an output stream:


  • Methods BEGIN_SECTION, NEXT_SECTION, and END_SECTION create headers and open or close header levels.

  • Methods WRITE_DATA, WRITE_TEXT, WRITE_XML, WRITE_JSON, and WRITE_HTML write different kinds of output into the output stream.

    • With method WRITE_DATA you can write elementary data objects (no reference variables), structures with elementary components, and internal tables of such line types.

    • The other methods create formated outputs of texts, XML, JSON, or HTML data.

  • Method WRITE is generic. It handles ABAP data as well as texts (in non proportional format).

 

  • Methods DISPLAY_... (available  as static methods only) work as WRITE_..., but close the current output stream and open a new one. If a SAP GUI is available, the output is displayed in a window.

  • Method LINE creates a horzontal line.

  • Method DISPLAYcloses the current output stream and opens a new one. If a SAP GUI is available, the output is displayed in a window. Optionally you can also pass data to DISPLAY as you can do for WRITE.

  • Method GET works like DISPLAY but does not display the data. Instead the formated output data are returned in a text string and can be handled further.

 

The standard output format is HTML. Optionally you can choose a simple text format with tabulators and line breaks. You choose the format with method SET_MODE for the static methods or using the input parameter MODE of the factory method NEW for the instance methods.

 

The class CL_DEMO_OUTPUT is available in release 7.03/7.31 since SP07 and in higher releases. It has a class documentation.


Code Examples

 

The most simple and common type of usage might look as follows:


SELECT *

       FROM scarr

       INTO TABLE @DATA(carriers).

 

cl_demo_output=>display( carriers ).


The output is:


out1.gif


A program using more than one static method of CL_DEMO_OUTPUT might look as follows:


SELECT *

       FROM scarr

       INTO TABLE @DATA(carriers).

CALL TRANSFORMATION id SOURCE carriers = carriers

                       RESULT XML DATA(xml).


cl_demo_output=>begin_section( `Some Text` ).

cl_demo_output=>write_text( |blah blah blah \n| &&

                            |blah blah blah| ).

cl_demo_output=>next_section( `Some Data` ).

cl_demo_output=>begin_section( `Elementary Object` ).

cl_demo_output=>write_data( carriers[ 1 ]-carrid ).

cl_demo_output=>next_section( `Internal Table` ).

cl_demo_output=>write_data( carriers ).

cl_demo_output=>end_section( ).

cl_demo_output=>next_section( `XML` ).

cl_demo_output=>write_xml( xml ).

cl_demo_output=>display( ).


Since this looks very ugly, it is better to use the instance methods instead of the static methods if you call more than 3 to 4 methods of the class within a program:


SELECT *

       FROM scarr

       INTO TABLE @DATA(carriers).

CALL TRANSFORMATION id SOURCE carriers = carriers

                       RESULT XML DATA(xml).

 

cl_demo_output=>new(

  )->begin_section( `Some Text`

  )->write_text( |blah blah blah \n| &&

                 |blah blah blah|

  )->next_section( `Some Data`

  )->begin_section( `Elementary Object`

  )->write_data( carriers[ 1 ]-carrid

  )->next_section( `Internal Table`

  )->write_data( carriers

  )->end_section(

  )->next_section( `XML`

  )->write_xml( xml

  )->display( ).


Both give the same output:


out2.gif


You might ask yourself two things:


  • How can static methods and instance methods have the same name?

    The instance methods are interface methods. Method NEW returns a reference variable of type IF_DEMO_OUTPUT. This interface is implemented by CL_DEMO_OUTPUT. The interface methods have the same names as the static methods of the class. 
           
  • Why can you chain these methods?

    For this convenience, each instance method returns the self reference me.


If you want a more simplistic output, you can switch to text mode:


SELECT *

       FROM scarr

       INTO TABLE @DATA(carriers).

 

cl_demo_output=>new( 'TEXT'

  )->display( carriers ).


out3.gif


If you want to deal with the resulting formatted data yourself, you use GET instead of DISPLAY:


SELECT *

       FROM scarr

       INTO TABLE @DATA(carriers).


DATA(html) = cl_demo_output=>get( carriers ).


cl_abap_browser=>show_html( html_string = html ).


This produces the same output as the first example above.


You can also examine and run the following programs to get a complete overview of all possiblities:


  • DEMO_USAGE_OUTPUT_STATIC
  • DEMO_USAGE_OUTPUT_INSTANCE


Examples of Usage

 

An example how CL_DEMO_OUTPUT can be used by a framework is provided by the ABAP Keyword Documentation in ADT (aka ABAP in Eclipse). If an example of the ABAP Example Library uses CL_DEMO_OUTPUT, the documentation framework allows you to execute the example and displays the output. This is done by getting the HTML output from CL_DEMO_OUTPUT  and merging it into the (non SAP GUI) documentation display.

 

out4.gif

 

Another example is quite remarkable. CL_DEMO_OUTPUT made it to the stage in SAP Teched 2013!

 

Here a snapshot from Dr. Vishal Sikka's keynote:

 

out5.jpg

 

I guess it is quite safe to assume that nobody recognized where that demo output came from  .

(B.t.w., see  AMDP, Comparison of SQLScript with Open SQL for a closer look at the performance results of that example; The bad ABAP results above come from nested SELECT loops ...).

 

 

Conclusion

 

The methods of CL_DEMO_OUTPUT can serve for quick and dirty outputs in tests or in demo programs. But the class is not made for productive usage. Particularly, CL_DEMO_OUTPUT and the framework behind are not prepared for handling large amounts of data.

 

 

Note

 

CL_DEMO_OUTPUT has a little sister CL_DEMO_INPUT that can be used for simple inputs of elementary values.



CL_DEMO_OUTPUT, Part 2 of 2 - A Look Behind

$
0
0

In this blog we will look a little bit closer behind the curtain of CL_DEMO_OUTPUT, the usage of which was introduced in Part 1.

 

Disclaimer

The classes described here are not intended for productive usage. You might use them in demonstration programs, local test programs or for temporary testing in productive programs. You must not use them productively in productive programs.

 

XML Output Stream

While it is always CL_DEMO_OUTPUT that appears in demos and examples, the most important thing lies behind: An XML-based output stream that was invented to demonstrate how ABAP data can be written device independently into a stream for further processing. This output stream is produced by class CL_DEMO_OUTPUT_STREAM. The usage of this class can look as follows:


SELECT *

       FROM scarr

       INTO TABLE @DATA(carriers).

 

DATA(stream) = cl_demo_output_stream=>open( ).


stream->write_text( iv_text   = 'XML of CL_DEMO_OUTPUT_STREAM'

                    iv_format = if_demo_output_formats=>heading

                    iv_level  = 1 ).

stream->write_data( ia_value  = carriers[ 1 ]-carrid

                    iv_name   = 'FIELD'

                    iv_format = if_demo_output_formats=>nonprop ).

stream->write_data( ia_value  = carriers

                    iv_name   = 'CARRIERS'

                    iv_format = if_demo_output_formats=>nonprop ).


DATA(xml) = stream->close( ).

 

cl_abap_browser=>show_xml( xml_xstring = xml ).

 

The XML result is:

out6.gif

  • An output stream is an object opened by static method OPEN.


  • For filling the stream, class CL_DEMO_OUTPUT_STREAM accepts texts, elementary ABAP data, structures with elementary components and internal tables of these line types. CL_DEMO_OUTPUT_STREAM interprets each ABAP data object as a table with a structured line type - an idea taken from OData. This means for each kind of possible data input the same XML structure emerges: an object with a name, a list of components and a set of rows. An elementary data object is represented like a table with one row. This format is simpler than OData and can easily handled by a consumer and, e.g., be converted into HTML.


  • An output stream can be closed by instance method CLOSE. This raises an instance event COMPLETED.


Event Handlers

CL_DEMO_OUTPUT_STREAM demonstrates how a simple XML output stream for ABAP data might look like. The next step are examples for consumers of such a stream. Such examples are the classes CL_DEMO_OUTPUT_HTML and CL_DEMO_OUTPUT_TEXT.


An example for handling the output stream with CL_DEMO_OUTPUT_HTML can look like:


SELECT *

       FROM scarr

       INTO TABLE @DATA(carriers).

 

DATA(stream) = cl_demo_output_stream=>open( ).

SET HANDLER cl_demo_output_html=>handle_output FOR stream ACTIVATION 'X'.


stream->write_text( iv_text   = 'HTML for CL_DEMO_OUTPUT_STREAM'

                    iv_format = if_demo_output_formats=>heading

                    iv_level  = 1 ).

stream->write_data( ia_value  = carriers[ 1 ]-carrid

                    iv_name   = 'FIELD'

                    iv_format = if_demo_output_formats=>nonprop ).

stream->write_data( ia_value  = carriers

                    iv_name   = 'CARRIERS'

                    iv_format = if_demo_output_formats=>nonprop ).


DATA(xml) = stream->close( ).

SET HANDLER cl_demo_output_html=>handle_output FOR stream ACTIVATION ' '.


Method HANDLE_OUTPUT of CL_DEMO_OUTPUT_HTML converts the XML stream to HTML, writes it to the ABAP memory, and displays it if a SAP GUI is available.


out7.gif


Looks familiar?


You can do the same with CL_DEMO_OUTPUT_TEXT in order to convert the XML stream to a simple text string. Methods HANDLE_OUTPUT of these classes also raise an event when the conversion is completed.


Putting it Together

Now that we have demonstration classes that show how an output stream can be created and handled we only need a framework that allows its comfortable usage. An that's what CL_DEMO_OUTPUT demonstrates.


  • CL_DEMO_OUTPUT is simply a wrapper for CL_DEMO_OUTPUT_STREAM, CL_DEMO_OUTPUT_HTML, and CL_DEMO_OUTPUT_TEXT.


  • The methods of CL_DEMO_OUTPUT
    • open and close streams
    • set the handlers
    • pass data to the methods of CL_DEMO_OUTPUT_STREAM

 

That's basically all!


Besides that, some effort goes into retrieving the names of the ABAP data in order to pass them to the stream, but that's a gimmick.


Examples for Usage

In the package SABAP_DEMOS_OUTPUT_STREAM you find the following programs that demonstrate the usage of the output stream:

 

  • DEMO_OUTPUT_STREAM
  • DEMO_USAGE_OUTPUT_STREAM


Conclusion

The demonstration classes shown here serve as an example how a simple output framework could be achieved for ABAP.

 

  • CL_DEMO_OUTPUT_STREAM creates an XML output stream. The XML format is a working example how such a stream might look like, if you do not want to use more complicated things like OData. You can easily invent other or better formats. The class CL_DEMO_OUTPUT_STREAM is a working example, for creating such a stream but its implementation is far from being marketable.

  • CL_DEMO_OUTPUT_HTML, and CL_DEMO_OUTPUT_TEXTare working examples how an XML output stream can be handled. Again the implementation is far from being suited for productive usage. If you take a class as CL_DEMO_OUTPUT_STREAM as given, you can easily go and create your own handlers for that class in order to consume the output stream.

  • Last but not least CL_DEMO_OUTPUT is nothing but a working example, how an output stream and its consumers might be used conveniently.

 

And that's that ...

Logging Expressions

$
0
0

In two preceding blogs I bragged about CL_DEMO_OUTPUT.

 

Predictably, there is some disappointment because this class is not intended for productive usage.


Fair enough. But you can use it for testing purposes.


As an example, I will show you how you can use CL_DEMO_OUTPUT to produce a logfile for an expression. Quick and dirty.


To do so I choose the following simple constructor expression.


TYPES itab TYPE STANDARD TABLE OF i WITH EMPTY KEY.

 

DATA(itab) =

  VALUE itab(

    FOR i = 1 UNTIL i > 3

    FOR j = 1 UNTIL j > 3

      ( i * 10 + j ) ).

 

Of course, you can test the result with cl_demo_output=>display( itab ).

 

But assume that you want to know what happens inside the expression and it is a more complicated expression and you don't want to debug or you can't or don't want to use other convenience tools (watchpoint, logpoints) provided by the ABAP Workbench/ADT or whatsoever.

 

In that situation you can instrumentalize an expression with CL_DEMO_OUTPUT, e.g. by misusing a LET expression:



DATA(log) = cl_demo_output=>new( ).

 

DATA(itab) =

  VALUE itab(

    FOR i = 1 UNTIL i > 3

    FOR j = 1 UNTIL j > 3

 

    LET o = log->write( |{ i }, { j }\n{ i * 10 + j } | )->line( ) IN

 

      ( i * 10 + j ) ).

 

log->display( ).



Adding these three temporary lines to the above code gives:


out8.gif


Note that the local variable o declared behind LET is not used at all. It simply serves as hook for writing into the output object referenced by log.



There are no limits to the imagination!













ABAP Program to start and stop SAP PI communication channels

$
0
0

Introduction


We recently faced an issue with JMS receiver communication channels in SAP PI which are frequently throwing error in case of network,connectivity issues or when the MQ queue manager is restarted.JMS receiver channels unable to reconnect to WebSphere - MQ queue manager and every time we need to manually restart the communication channels in case of this issue.


Error


JMS channel fails to connect to MQ whenever any network problem occurs. This generates the following error

“MQJMS1016: an internal error has occurred. Please contact your system administrator.

Detail: java.lang.NullPointerException:  in sending to destination queue: //TESTXXX”.


Root Cause


The main reason for this issue is that Queue Manager which would break all the connections that are idle for more than 10 minutes interval and whenever a network problem occurs the PI JMS channel goes down.


This problem is caused due to a limitation in all versions of Websphere MQ including 6.x that has been acknowledged by IBM. Websphere MQ diverges from the JMS specification and other JMS products in its behavior of notifying the JMS connection exception listener. (javax.jms.ExceptionListener).


When only a javax.jms.QueueSender object is created from a javax.jms.Session object associated with a javax.jms.Connection object, errors/drops in the connection do not invoke the associated exceptionlistener set on the connection object. Instead an exception is encountered only when the next JMS message (javax.jms.Message) is sent through the JMS sender.

However, when a MessageListener (asynchronous) is created on a Session object associated with a JMS Connection, WSMQ informs the connection's ExceptionListener immediately.There are no current solutions to the problem, only work arounds are provided.


As per the SAP note :0000948016 we need to create a ABAP program and set up batch jobs and schedule it to start and stop the JMS receiver communication channels in SAP PI.


https://websmp230.sap-ag.de/sap/support/notes/convert2pdf/0000948016?sap-language=EN


ABAP program Code


*&---------------------------------------------------------------------*

*& Report  ZRESTART_JMS_RCVR_CHANNEL

*&

*&---------------------------------------------------------------------*

*&

*&

*&---------------------------------------------------------------------*

 

REPORT  ZRESTART_JMS_RCVR_CHANNEL.

 

SET EXTENDED CHECK OFF.

 

DATA: client TYPE REF TO if_http_client.

DATA: cclient TYPE REF TO if_http_client.

DATA: dummy TYPE string,

      subrc TYPE sysubrc.

 

 

PARAMETERS:

            dest TYPE rfcdest.

 

DATA:

            protocol(8) TYPE c VALUE 'HTTP/1.0',

            path(128) TYPE c,

            mandant TYPE symandt,      " default sy-mandt,

            username TYPE syuname,     " default sy-uname,

            password(128) TYPE c,

            langu TYPE sylangu,

            listen TYPE c VALUE space,

            scheme     TYPE i VALUE 1.

 

DATA: host_str TYPE string,

      service_str TYPE string.

DATA:  ncolor TYPE i VALUE 4.

DATA : tx TYPE f, ta TYPE i, te TYPE i.

DATA : mintime TYPE f VALUE 1000000000.

DATA : t(10) TYPE p.

 

INCLUDE RSHTTPPIN_DISPLAY .

 

  DATA: wa_inout TYPE type_alv_entry,

        l_columns TYPE REF TO cl_salv_columns_table,

        l_column  TYPE REF TO cl_salv_column_table,

        l_status TYPE i,

        l_string TYPE string.

 

START-OF-SELECTION.

 

  GET RUN TIME FIELD ta.

  CALL METHOD cl_http_client=>create_by_destination

    EXPORTING

      destination              = dest

    IMPORTING

      client                   = client

    EXCEPTIONS

      destination_not_found    = 1

      internal_error           = 2

      argument_not_found       = 3

      destination_no_authority = 4

      plugin_not_active        = 5

      OTHERS                   = 5.

  IF sy-subrc <> 0.

    CASE sy-subrc.

      WHEN 3.

        MESSAGE s000(sr) WITH

          'Create failed: Argument not found'.       "#EC NOTEXT

      WHEN 4.

       MESSAGE s000(sr) WITH

         'Create failed: destionation no authority'. "#EC NOTEXT

      WHEN 5.

        MESSAGE s000(sr) WITH

         'Create failed: plugin not active'.         "#EC NOTEXT

      WHEN OTHERS.

        MESSAGE s000(sr) WITH 'Create failed'.       "#EC NOTEXT

    ENDCASE.

    EXIT.

  ENDIF.

 

  client->propertytype_accept_cookie = client->co_prompt.

 

  IF NOT username IS INITIAL AND

     NOT password IS INITIAL.

 

    DATA: password_str TYPE string.

    password_str = password.

    DATA: lclient TYPE REF TO cl_http_client,

           user TYPE string.

    user = username.

    lclient ?= client.

    CALL METHOD client->authenticate

      EXPORTING

        client   = mandant

        username = user

        password = password_str

        language = langu.

 

 

    "call method lclient->authentication.

    "Set request method

  ENDIF.

  CALL METHOD client->request->set_header_field

    EXPORTING

      name  = '~request_method'

      value = 'GET'.

 

  "Set request protocol

  IF protocol = 'HTTP/1.0'.

    CALL METHOD client->request->set_header_field

      EXPORTING

        name  = '~server_protocol'

        value = 'HTTP/1.0'.

  ELSE.

    CALL METHOD client->request->set_header_field

      EXPORTING

        name  = '~server_protocol'

        value = 'HTTP/1.1'.

  ENDIF.

 

  dummy = path.

  cl_http_utility=>set_request_uri( request = client->request

                                    uri     = dummy ).

  CALL METHOD client->send

    EXCEPTIONS

      http_communication_failure = 1

      http_invalid_state         = 2

      http_processing_failed     = 3

      OTHERS                     = 4.

  IF sy-subrc <> 0.

    CALL METHOD client->get_last_error

      IMPORTING

        code    = subrc

        MESSAGE = dummy.

 

    MESSAGE s000(sr) WITH dummy.

    EXIT.

  ENDIF.

 

  IF listen IS INITIAL.

    CALL METHOD client->receive

      EXCEPTIONS

        http_communication_failure = 1

        http_invalid_state         = 2

        http_processing_failed     = 3

        OTHERS                     = 4.

    IF sy-subrc <> 0.

      CALL METHOD client->get_last_error

        IMPORTING

          code    = subrc

          MESSAGE = dummy.

      MESSAGE s000(sr) WITH dummy.

      EXIT.

    ENDIF.

  ELSE.

    CALL METHOD client->listen

      RECEIVING

        client                     = cclient

      EXCEPTIONS

        http_communication_failure = 1

        http_no_open_connection    = 2.

    IF sy-subrc = 0.

      CALL METHOD client->receive

        EXCEPTIONS

          http_communication_failure = 1

          http_invalid_state         = 2.

      IF sy-subrc <> 0.

        CALL METHOD client->get_last_error

          IMPORTING

            code    = subrc

            MESSAGE = dummy.

        MESSAGE s000(sr) WITH dummy.

        EXIT.

      ENDIF.

    ELSE.

      IF sy-subrc <> 0.

        MESSAGE s000(sr) WITH 'communication error'.

        EXIT.

      ENDIF.

    ENDIF.

  ENDIF.

 

wa_inout-name = text-005.

CALL METHOD  client->response->get_status(

    IMPORTING code = l_status ).

  wa_inout-value = l_status.

  CONDENSE wa_inout-value.

  write:/ wa_inout-name, wa_inout-value.

 

  wa_inout-name = text-004.

  CALL METHOD  client->response->get_status(

    IMPORTING reason = l_string ).

  wa_inout-value = l_string.

  write:/ wa_inout-name, wa_inout-value.

 

  wa_inout-name = text-006.

  wa_inout-value = t.

  CONDENSE wa_inout-value.

  CONCATENATE wa_inout-value text-007 INTO wa_inout-value

    SEPARATED BY space.

  write:/ wa_inout-name, wa_inout-value.

 

ABAP report ‘ZRESTART_JMS_RCVR_CHANNEL’will takes HTTP Destination's [START and STOP] as input and triggers Connection test for the same. 


For every receiver JMS channel, two variants are created that would pass the StartChannelHTTP Destination and StopChannelDestination respectively. Finally, a batch job "ZRESTART_JMS_REC" is to be created with two steps.


First step is to call the Report "ZRESTART_JMS_RCVR_CHANNEL" with Stop variant.

Second step to call the Report with Start Variant. It’s scheduled to be executed a periodic intervals.


This process will prevent all Receiver JMS channels to be automatically start and stop the channels.


Step by step to visualize your CDS view via Analysis Path Framework (APF)

$
0
0

Analysis Path Framework (APF) is a framework which provides reuse components that allow you to build and enhance interactive analytical Web applications. Recently during my self study, I find out that an OData service exposed by CDS view could easily be consumed by APF.

 

Here below is detailed step.

 

For prerequisites to use APF, you can find it in SAP help.

In my case, I have the following PFCG role assigned:


clipboard1.png

And this role has the following role menu assigned:

clipboard2.png

Step1. Create a simple header and item CDS view, and a consumption view to expose as OData service.

 

Below source code is for item view:

@AbapCatalog.sqlViewName: 'zorITem'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'order item detail'
define view Z_I_Order_Item as select from zorder_item {  key zorder_item.parent_id,  key zorder_item.item_id,  zorder_item.item_text
}
Below source code for header view:
@AbapCatalog.sqlViewName: 'zorheader'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'header view'
define view Z_I_Order_Header as select from zorder_header
association [0..*] to Z_I_Order_Item as _Item
on $projection.object_id = _Item.parent_id
{  key zorder_header.object_id,  zorder_header.description,  @ObjectModel.association.type: #TO_COMPOSITION_CHILD  _Item
}

The corresponding database in ABAP for these two CDS views are listed below:

clipboard3.png

clipboard4.png

The source code of CDS view:

@AbapCatalog.sqlViewName: 'zjorderview'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Jerry order consumption view'
@OData.publish: true
define view Z_C_Order as select from Z_I_Order_Header {  key Z_I_Order_Header.object_id,  Z_I_Order_Header.description,  @ObjectModel.association.type: [#TO_COMPOSITION_CHILD]  Z_I_Order_Header._Item
}

Since I use the annotation OData.publish:true, so a corresponding OData service Z_C_Order_CDS is generated automatically.

 

Register it via tcode /IWFND/MAINT_SERVICE. Once done, ensure the metadata access could successfully be done.

clipboard5.png

Step2. Expose the created OData service via APF

 

Click tile APF Configuration Modeler,

clipboard6.png

Create a new Application:

clipboard7.png

Use the default semantic object:

clipboard8.png

Create a new configuration which acts as a container for sub settings such as Filters and Categories:

clipboard9.png

In Smart Filter, choose the OData service and entity type created from previous step.

clipboard10.png

And a new category:

clipboard11.png

clipboard12.png

Select this new category and create a new step:

clipboard13.png

In the step creation page, just select all the two properties exposed by CDS view Z_C_Order, that is:

clipboard14.png

Create a new Representation based on this step:

clipboard15.png

Here for representation type, I just choose the most simple one: Table. Choose property from drop down list for table display.

clipboard16.png

Once done, click execute button, you will see the following screen:

clipboard17.png

clipboard18.png

Then choose the table representation:

clipboard19.png

Then the table is displayed as expected:

clipboard20.png

Its content matches with the data in the corresponding database table.

clipboard21.png

Download payslip in PDF format employee wise to Application Server

$
0
0

This blog describes the option to download payslip of each employee in separate PDF files to application server. In the case of smartform, the payslip of each employee will be printed in each page of smart form output. The function module illustrated below will handle the process of downloading payslip to application server. You can call it in your custom program.


FUNCTION ZPYSLP_PDF_DWNLD_APP_SRV.

*"*"Local Interface:

*"  IMPORTING

*" REFERENCE(I_FORMNAME) TYPE  CHAR30

*" REFERENCE(I_FILENAME) TYPE  STRING

*" REFERENCE(I_PRESENTATION) TYPE  CHAR1 OPTIONAL

*" REFERENCE(I_APPLICATION) TYPE CHAR1 DEFAULT 'X'

*" REFERENCE(IT_FINAL) TYPE ZTT_PAYSLIP

*" REFERENCE(I_DATE) TYPE  CHAR20

*"  EXCEPTIONS

*" ERROR_PRESENTATION_SERVER

 

DATA:   FNAM             TYPE RS38L_FNAM,   "FORM NAME

         CONTROL_PARAMETERS TYPE SSFCTRLOP,    "CONTROL PARAMETERS

         OUTPUT_OPTIONS     TYPE SSFCOMPOP,    "OUTPUT OPTIONS

         JOB_OUTPUT_INFO    TYPE SSFCRESCL,

         DOCTAB_ARCHIVE     TYPE DOCS OCCURS 0,

         BIN_FILESIZE(132TYPE C,

         WA_DATA            TYPE TLINE,

         E_DATA_OTF         TYPE TABLE OF TLINE,

         LV_JOB_OUTPUT_INFO TYPE SSFCRESCL,

         LV_LINES           TYPE I,

         LV_COUNT(1)       TYPE N,

         LT_PAYSLIP         TYPE ZTT_PAYSLIP,

         WA_FINAL           TYPE ZST_PAYSLIP,

         LV_FILENAME        TYPE STRING,

         LV_APPFILE         TYPE STRING.

 

CLEAR LV_LINES.

DESCRIBE TABLE IT_FINAL LINES LV_LINES. “FINAL INTERNAL TABLE IN SMARTFORM



DO.

   LV_COUNT = LV_COUNT + 1.

   CLEAR: WA_FINAL, LT_PAYSLIP, LV_FILENAME, LV_APPFILE.

   REFRESH LT_PAYSLIP.

 

   IF LV_COUNT LE LV_LINES.

     READ TABLE IT_FINAL INTO WA_FINAL INDEX LV_COUNT.

     IF SY-SUBRC EQ 0.

       APPEND WA_FINAL TO LT_PAYSLIP.

     ENDIF.

   ELSE.

     EXIT.

   ENDIF.

 

 

IF I_PRESENTATION = 'X'.

     CONCATENATE 'PAYSLIP' WA_FINAL-PERNR '.PDF' INTO LV_FILENAME.

     LV_APPFILE = LV_FILENAME.

     CONCATENATE I_FILENAME LV_FILENAME INTO LV_FILENAME.

   ENDIF.

 

   IF I_APPLICATION = 'X'. "FILE NAME IN APPLICATION SERVER

     CLEAR LV_FILENAME.

     CONCATENATE I_FILENAME '/PAYSLIP' WA_FINAL-PERNR '.PDF' INTO LV_FILENAME.

   ENDIF.

 

*--INITIALIZE THE CONTROL PARAMETERS

   CONTROL_PARAMETERS-NO_OPEN     = 'X'.

   CONTROL_PARAMETERS-NO_CLOSE    = 'X'.

   CONTROL_PARAMETERS-NO_DIALOG   = 'X'.

   CONTROL_PARAMETERS-GETOTF      = 'X'.

 

 

*--INITIALIZE OUTPUT OPTIONS

   OUTPUT_OPTIONS-TDDEST    = 'LOCL'.


*--GET THE SMART FORM F.M NAME

   CALL FUNCTION 'SSF_FUNCTION_MODULE_NAME'

     EXPORTING

       FORMNAME           = I_FORMNAME

     IMPORTING

       FM_NAME            = FNAM

     EXCEPTIONS

       NO_FORM            = 1

       NO_FUNCTION_MODULE = 2

       OTHERS             = 3.



*--OPEN THE SMARTFORM

   CALL FUNCTION 'SSF_OPEN'

     EXPORTING

*       ARCHIVE_PARAMETERS =

       USER_SETTINGS      = ' '

*       MAIL_SENDER        =

*       MAIL_RECIPIENT     =

*       MAIL_APPL_OBJ      =

       OUTPUT_OPTIONS     = OUTPUT_OPTIONS

       CONTROL_PARAMETERS = CONTROL_PARAMETERS

* IMPORTING

*       JOB_OUTPUT_OPTIONS =

     EXCEPTIONS

       FORMATTING_ERROR   = 1

       INTERNAL_ERROR     = 2

       SEND_ERROR         = 3

       USER_CANCELED      = 4

       OTHERS             = 5.

 

   IF SY-SUBRC <> 0.

* IMPLEMENT SUITABLE ERROR HANDLING HERE

   ENDIF.


*--START SMARTFORM

   CALL FUNCTION FNAM

     EXPORTING

*       ARCHIVE_INDEX      =

*       ARCHIVE_INDEX_TAB  =

*       ARCHIVE_PARAMETERS =

       CONTROL_PARAMETERS = CONTROL_PARAMETERS

*       MAIL_APPL_OBJ      =

*       MAIL_RECIPIENT     =

*       MAIL_SENDER        =

       OUTPUT_OPTIONS     = OUTPUT_OPTIONS

       USER_SETTINGS      = ' '

       PAY_COMP           = LT_PAYSLIP

       DATE               = I_DATE

*     IMPORTING

*       DOCUMENT_OUTPUT_INFO       =

*       JOB_OUTPUT_INFO    =

*       JOB_OUTPUT_OPTIONS =

     EXCEPTIONS

       FORMATTING_ERROR   = 1

       INTERNAL_ERROR     = 2

       SEND_ERROR         = 3

       USER_CANCELED      = 4

       OTHERS             = 5.


*--CLOSE THE SMARTFORM

   CALL FUNCTION 'SSF_CLOSE'

     IMPORTING

       JOB_OUTPUT_INFO  = JOB_OUTPUT_INFO

     EXCEPTIONS

       FORMATTING_ERROR = 1

       INTERNAL_ERROR   = 2

       SEND_ERROR       = 3

       OTHERS           = 4.


*--CONVERT TO THE SMARTFORM OTF OUTPUT TO THE PDF

   CALL FUNCTION 'CONVERT_OTF_2_PDF'

*    EXPORTING

*      USE_OTF_MC_CMD         = 'X'

     IMPORTING

       BIN_FILESIZE           = BIN_FILESIZE

     TABLES

       OTF                    = JOB_OUTPUT_INFO-OTFDATA

       DOCTAB_ARCHIVE         = DOCTAB_ARCHIVE

       LINES                  = E_DATA_OTF

     EXCEPTIONS

       ERR_CONV_NOT_POSSIBLE  = 1

       ERR_OTF_MC_NOENDMARKER = 2

       OTHERS                 = 3.


IF I_PRESENTATION = 'X'.

     CALL FUNCTION 'GUI_DOWNLOAD'

       EXPORTING

         FILENAME                = LV_FILENAME

         FILETYPE                = 'BIN'

       TABLES

         DATA_TAB                = E_DATA_OTF

       EXCEPTIONS

         FILE_WRITE_ERROR        = 1

         NO_BATCH                = 2

         GUI_REFUSE_FILETRANSFER = 3

         INVALID_TYPE            = 4

         NO_AUTHORITY            = 5

         UNKNOWN_ERROR           = 6

         HEADER_NOT_ALLOWED      = 7

         SEPARATOR_NOT_ALLOWED   = 8

         FILESIZE_NOT_ALLOWED    = 9

         HEADER_TOO_LONG         = 10

         DP_ERROR_CREATE         = 11

         DP_ERROR_SEND           = 12

         DP_ERROR_WRITE          = 13

         UNKNOWN_DP_ERROR        = 14

         ACCESS_DENIED           = 15

         DP_OUT_OF_MEMORY        = 16

         DISK_FULL               = 17

         DP_TIMEOUT              = 18

         FILE_NOT_FOUND          = 19

         DATAPROVIDER_EXCEPTION  = 20

         CONTROL_FLUSH_ERROR     = 21

         OTHERS                  = 22.

     IF SY-SUBRC EQ 0.

*        RAISE ERROR_PRESENTATION_SERVER.

     ENDIF.

   ELSEIF I_APPLICATION = 'X'.

     OPEN DATASET LV_FILENAME FOR OUTPUT IN BINARY MODE.

     IF SY-SUBRC = 0.

       LOOP AT E_DATA_OTF INTO WA_DATA.

         TRANSFER WA_DATA TO LV_FILENAME.

       ENDLOOP.

       CLOSE DATASET LV_FILENAME.

     ELSE.

       WRITE : / 'OPERATING SYSTEM COULD NOT OPEN FILE'.

     ENDIF.

   ENDIF.

ENDDO.

ENDFUNCTION.



CALL FUNCTION MODULE IN CUSTOM PROGRAM (Driver program for SmartForm)

 

 

       CALL FUNCTION 'ZFM_PYSLP_PDF_DWNLD_APP_SRV'

         EXPORTING

           I_FORMNAME    = 'ZSF_PAYSLIP' “SMARTFORM NAME

           I_FILENAME    = '/ABCD/PYSLP' “LOCATION IN APPLICATION SERVER

*         I_PRESENTATION                  =

           I_APPLICATION = 'X'

           IT_FINAL      = IT_FINAL “FINAL INTERNAL TABLE IN SMARTFORM

           I_DATE        = LV_DATE

*       EXCEPTIONS

*         ERROR_PRESENTATION_SERVER       = 1

*         OTHERS        = 2

         .

       IF SY-SUBRC <> 0.

* IMPLEMENT SUITABLE ERROR HANDLING HERE

       ENDIF.

How to maintain the partner mobile phone when creating SO with BAPI_SALESORDER_CREATEFROMDAT2.

$
0
0

When creating sales order with BAPI_SALESORDER_CREATEFROMDAT2, we normally use the structure PARTNERADDRESSES to change the partner address data if needed. However, the "mobile phone" field is not contained in structure PARTNERADDRESSES. Means, in standard, the BAPI doesn't support maintaining the mobile phone number. It sometimes cause inconvenience in the project.

 

With this blog post, I would like to share some information about how to enhance the structure PARTNERADDRESSES to make the maintaining of mobile phone possible.


1. Enhance structure BAPIADDR1.

Firstly, we need to check the enhancement category and change it if necessary. Follow the below path to check the Enhancement category of structure.

SE11 to change structure BAPIADDR1.

Then execute MENU  >EXTRAS  >ENHANCEMENT CATEGORY

11111.png

Change it to: Can Be Enhanced (Deep).

Save and activate.



Secondly, create structure APPEND_BAPIADDR1_2 in the System and append this structure to structure BAPIADDR1.

For this purpose, proceed as follows:

Use Transaction SE11 to display structure BAPIADDR1. Via 'Goto' -> 'Append structure' the system issues a dialog box.

If you have no append structure, the dialog box will be like below. Enter 'APPEND_BAPIADDR1_2' into the input field.

22222.png

 

If you have already an append structure for the structure BAPIADDR1, the pop-up will be like below. You can use the existing one, or click on the create button to create a new one like above.

44444.jpg


After entering the Append Name and pressing enter, we come to the append structure creation screen as below. Enter the text and the field as below.

As a short text, enter 'APPEND for mobile phone number in structure BAPIADDR1'. You can enter any other text if you want.

For the "Component", I use "MOB_NUMBER" here. You can enter any value you want. It is the name of the field. You will see this name in the BAPI structure. And you need use the same field name when enhancing the interface. (I will show later.)

For the "Component type", please enter "AD_MBNMBR1".

33333.png

Save and activate the append structure.


Now, you will be able to see the MOB_NUMBER already in structure PARTNERADDRESSES as below, when executing BAPI_SALESORDER_CREATEFROMDAT2 in SE37. But it will not work, because the interface program has not been enhanced.

55555.png


2. Enhance interface program: FM ADDR_CONVERT_FROM_BAPIADDR1.

The sample code is:

* pass mobile phone number to sales order address.

   CLEAR ADTEL_WA.

   ADTEL_WA-ADTEL-TEL_NUMBER = ADDR1_COMPLETE_BAPI-MOB_NUMBER.

   IF NOT ADTEL_WA-ADTEL IS INITIAL.

     ADTEL_WA-ADTEL-FLGDEFAULT = 'X'.

     ADTEL_WA-ADTEL-R3_USER    = '3'.

     APPEND  ADTEL_WA TO ADDR1_COMPLETE-ADTEL_TAB  .

   ENDIF.


Here, you can see that I am passing the ADDR1_COMPLETE_BAPI-MOB_NUMBER value to ADTEL_WA-ADTEL-TEL_NUMBER. If you use other field name than MOB_NUMBER, then you will need to adjust the coding part accordingly.

ADTEL_WA-ADTEL-R3_USER = '3' is to tell the system that this number is the mobile phone number.


As for the place where to put the code, it is actually not important, only if you don't interrupt the existing code. The easiest way is to insert the code at the end of the FM.

I would suggest putting the coding here as below. Because it is just after the code for Telephone field. It looks beautiful.

666666.png


Activate the code.

Enhancement finished.


Now, you will be able to maintain the mobile phone number when creating sales order with BAPI_SALESORDER_CREATEFROMDAT2.

By the way, don't forget to link the address with ORDER_PARTNERS-ADDRESS = PARTNERADDRESSES-ADDR_NO.

 

Hope it is helpful.

 

Best regards,

Hualin Zhang



Code visualization using Moose

$
0
0

It is now possible to extract model information from a SAP system to analyze it using Moose in a Pharo virtual machine.

 

Pharo is a kind of Smalltalk and heavily used by specialists who develop techniques for code visualization especially for refactoring. The SAP model data is extracted using FAMIX, this allows a more detailed analysis as would be possible using UML. This is now possible due to a new open source extractor.

 

Currently extracted are for instance:
- Accesses to attributes of class

- Invocations of class methods

- Accesses to database tables

 

It is planned to add other objects like reports, functions, DSO and InfoCubes of SAP BW ...

 

Examples for diagrams are:

https://raw.githubusercontent.com/RainerWinkler/Moose-FAMIX-SAP-Extractor/master/wiki_pictures/Packages_with_classes_and_usages.png

 

https://raw.githubusercontent.com/RainerWinkler/Moose-FAMIX-SAP-Extractor/master/wiki_pictures/Classes_with_method_attr_usage.png

https://raw.githubusercontent.com/RainerWinkler/Moose-FAMIX-SAP-Extractor/master/wiki_pictures/Classes_with_names_and_method_usages_SABP_RTTI.png

This diagrams are not just images but it is possible to move the parts around, to see the names using mouse over or to explore it in detail by clicking on it.

 

You find details in this blog in "Custom Code Management":

 

http://scn.sap.com/community/abap/custom-code-management/blog/2016/03/13/solving-sap-problems-without-reading-code--extract-a-famix-model-to-moose

 

The coding to extract and other informations are available on the github project page: https://github.com/RainerWinkler/Moose-FAMIX-SAP-Extractor

My CDS view self study tutorial - Part 9 cube view and query view

$
0
0

In previous eight steps all we focus on is transactional stuff. This time let's touch some analytics stuff.

 

Let's first create a most simple database table in ABAP backend:

clipboard1.png

Then create a simple cube view:

 

@EndUserText.label: 'Jerry cube view'
@Analytics.dataCategory: #CUBE
@VDM.viewType: #COMPOSITE
@AccessControl.authorizationCheck:#CHECK
@AbapCatalog.sqlViewName: 'zprdcube'
define view Z_C_Prod_Cube as select from zprd_query{   key zprd_query.prod_id,  zprd_query.prod_text,  @DefaultAggregation: #MAX  zprd_query.quantity
}

 

This cube view has only three fields: prod_id, prod_text and quantity.

For more detail for annotation @Analytics.dataCategory: #CUBE, please refer to SAP help.

Then create a query view on top of the cube view:

@EndUserText.label: 'Jerry query verification'
@VDM.viewType: #CONSUMPTION
@Analytics.query: true
@AccessControl.authorizationCheck:#NOT_ALLOWED
@AbapCatalog.sqlViewName: 'zprdquery'
@OData.publish: true
define view Z_C_Product as select from Z_C_Prod_Cube {  key Z_C_Prod_Cube.prod_id,  Z_C_Prod_Cube.prod_text,  @DefaultAggregation: #MAX  Z_C_Prod_Cube.quantity
}

Since I use @OData.publish: true, a new OData service is automatically generated when this query view is activated.

We have already discussed how this generation is achieved in this blog: My CDS view self study tutorial - Part 4 how does annotation @OData.publish work.

 

Once activation is finished, we can do some testing. In ABAP backend I have two entries in the table:

clipboard1.png

So once we perform the read operation via generated OData service: /sap/opu/odata/sap/Z_C_Product_cds/Z_C_PRODUCT

 

we can see these two entries are returned in OData response automatically:

clipboard2.png

Let's do some further research to find out how these two entries are retrieved from backend.

 

We have CDS view name as Z_C_Product and the generated OData service based on it has name Z_C_Product_CDS.

Like normal CDS view activation with annotation @OData.publish: true, there is also a new ABAP class @OData.publish: true automatically generated, which has only one method redefined: GET_QUERY_NAME. In this method, a constant attribute is returned.

The content of this attribute: '2Czprdquery'.

 

The biggest difference compared with a normal CDS view activation is: when a query view is activated, the generated OData service data provider class has CL_NAT_ODATA_MODEL_ABS as its super class, giving you a hint that all data retrieved based on this query view will be handled by analytics framework.

clipboard3.png


While for a normal CDS view, the DPC class has super class CL_SADL_GTK_EXPOSURE_MPC, which means the data access in this case is done by SADL framework.

clipboard4.png

In order to figure out the detail data access logic implementation by analytics framework, I write the following report to simulate the OData call:

 

REPORT zcds_get_query_view_data.
DATA(lo_tool) = NEW cl_nat_generic_dpc( ).
DATA(lo_context) = NEW /iwbep/cl_mgw_context( ).
DATA: l_r_rs_gw_columns TYPE REF TO cl_abap_tabledescr,      l_t_rs_gw_columns TYPE REF TO data,      lo_request        TYPE REF TO /iwbep/cl_mgw_request,      lo_detail         TYPE REF TO /iwbep/if_mgw_core_srv_runtime=>ty_s_mgw_request_context,      ls_detail         TYPE  /iwbep/if_mgw_core_srv_runtime=>ty_s_mgw_request_context,      lt_header         TYPE tihttpnvp,      lt_filter         TYPE /iwbep/t_mgw_select_option,      lt_order          TYPE /iwbep/t_mgw_sorting_order,      ls_page           TYPE /iwbep/s_mgw_paging,      ls_header         TYPE LINE OF tihttpnvp.
FIELD-SYMBOLS:    <l_t_rs_gw>       TYPE        table.
lo_context->/iwbep/if_mgw_context~set_parameter( iv_name  = /iwbep/if_mgw_context=>gc_param_isn     iv_value = 'Z_C_PRODUCT_CDS' ).
lo_context->/iwbep/if_mgw_context~set_parameter(  iv_name  = /iwbep/if_mgw_context=>gc_param_isv        iv_value = '0001' ).
lo_tool->/iwbep/if_mgw_core_srv_runtime~set_context( lo_context ).
CREATE DATA lo_detail.
lo_request = NEW /iwbep/cl_mgw_request( ir_request_details = lo_detail it_headers = lt_header ).
DATA(lo_rt) = NEW cl_eq_bics_gw_rt( i_query          = '2Czprdquery'                                    i_servicetype_oq = abap_true ).
lo_rt->get_designtime(  IMPORTING    e_t_column_description = DATA(l_t_query_struc) ) .
l_r_rs_gw_columns = cl_eq_bics_gw_dt=>build_rs_structure( l_t_query_struc ).
CREATE DATA l_t_rs_gw_columns TYPE HANDLE l_r_rs_gw_columns.
ASSIGN l_t_rs_gw_columns->* TO <l_t_rs_gw>.
ls_detail-technical_request-service_name = 'Z_C_PRODUCT_CDS'.
ls_detail-technical_request-service_version = '0001'.
ls_detail-technical_request-source_entity_type =  ls_detail-technical_request-target_entity_type
= 'Z_C_PRODUCTType'.
ls_detail-technical_request-source_entity_set = ls_detail-technical_request-target_entity_set
= 'Z_C_PRODUCTTypeCollection'.
ls_header-name = 'dummy'.
APPEND ls_header TO ls_detail-technical_request-request_header.
CALL METHOD lo_tool->/iwbep/if_mgw_core_srv_runtime~read_entityset(  EXPORTING    iv_entity_name           = 'Z_C_PRODUCTType'    iv_source_name           = 'Z_C_PRODUCTType'    is_paging                = ls_page    it_order                 = lt_order    it_filter_select_options = lt_filter    is_request_details       = ls_detail  CHANGING    cr_entityset             = l_t_rs_gw_columns    ct_headers               = lt_header                               ).
ASSIGN l_t_rs_gw_columns->* TO <l_t_rs_gw>.
WRITE: 'lines of data: ', lines( <l_t_rs_gw> ).

 

With SAT trace I can easily locate the exact location of code where the data retrieve is done:

clipboard5.png

clipboard6.png

In this line the DB cursor is opened with generated SQL statement:

clipboard7.png

clipboard8.png

Mystery Revealed!

clipboard9.png

Viewing all 948 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>