Quantcast
Channel: SCN : Blog List - ABAP Development
Viewing all 943 articles
Browse latest View live

Missing Comments and Documentation.. a bit like global warming

$
0
0

Thought of writing the blog the share the most common issue after a SAP maintenance project is handed over or when new consultants come into the project. The first few days there are high level descriptions/discussions of what's there in the landscape and what not. Then comes the hard part when bugs or tickets or incidents starts coming in. Then the effort taken often to understand the process is often painstaking due to lack of code comments or documentation(In code and as specifications) and usually ends up taking  more time compared to what might have been used if it was done in the first place

 

Little comments in the code if they are missing often don't reap the benefits immediately but always help in the long run. The missing comments are like small amounts of C02 that eventually causes water levels to rise and thus flooding or temperature swings..(when you manager is chasing you solve an incident or an issue and you don't have enough time to dig through the layers of custom code and hope that some documentation or comments would have helped)  and the effort to do it later is much more effort-intensive.

 

Now people might think what it has to do with say I create 1 Z-Report or 1-Function module or Just activate a BADI and write a small snippet of code. But in the long run artifacts or objects gets added over the years, remember business that use Z-process would not change often and keep doing even more customizations. I had the experience of working with such clients. They install SAP and then create Z-Transactions to fit in business requirement, might sound crazy and stubborn but the logic often given is I want my business to run my way not always the way what SAP says( suits them as they are one of the BIG 5 consulting firms ).

 

The other thing is now we get many versions of SAP modules and categories and often many scenarios and modules and processes and business practices are not always accounted for in standard SAP packages or often come later after SAP starts delivering it for such and industry. Such things are validated by the various solutions SAP has delivered from time to time. Like access of SAP clients shifted from Desktop client in its early years to web-based and now moving to cloud based to many new modules introduced over years to get into various industry segments.

 

Now how can small comments help in the log run..

 

Well the small comment that you write and may be leave the project will always help the other consultant coming in and trying to do some changes or add on code or comment out logic. I know the other aspect is people will say what about requirements and design documents. Well they are often done in a bare minimum way and often its not there. Another scenario is often say an age old documentation of a report of Module pool screens exist but the programs might have changed several times over years and the initial logic parts might have changed or many new features might have been added and that's not there in the documents. Such things often take more time as the developer has to understand the feature and then do any further changes.

 

The other most common scenario is copying BAPI or Standard FM's and then not doing any documentation. Specially with lots of flag fields and generic structures. If large code blocks and nested Z-objects are there they often raise the efforts to understand the code( I remember the days without the new editor and debugger ) .

 

Imagine how bad the demo programs will be provided by SAP, had they missed out on the comments I am sure few runs and debug would be required to know what's happening.

 

Often small comments and documentation set the pitch for quick understanding improves code readability and thus improving maintainability. Remember when you clicked the documentation button and it said only available in DE and then translated then via translation tools or sites in internet.

 

With the future going OOPS. Its good to have class and methods commented and documented as they are complex objects and say a Z-class with Z-methods if not documented can be hard on people following up with changes or additions to the same. Basic comments or on use of class and methods will always help.

 

So small missing documentation or comments can make a simple custom development look apparently complex. If present and done on the time development or changes are done can save a lot of effort for future and help improve code readability and maintenance.

 

So, follow the rule of always commenting or documenting even though it looks useless its good in long run. So ending this blog with few links on documentation.

 

http://help.sap.com/saphelp_40b/helpdata/EN/c8/19764e43b111d1896f0000e8322d00/content.htm

 

http://help.sap.com/saphelp_nw04s/helpdata/en/cf/fa40424319b16be10000000a155106/content.htm

 

http://help.sap.com/saphelp_erp60_sp/helpdata/en/43/b46c4853c111d395fa00a0c94260a5/content.htm

 

Cheers,

Arindam


Thoughts on OO Events Mechanism

$
0
0

Object oriented Events in ABAP

 

As i was moving into object oriented world ı come across with the concept EVENTS

 

Why Events?

 

Well, something important has happened

 

Someone needs to know!!

 

 

I started looking at the events, which was understandable but not really!!

There is a channel where there is the

  • publishers
  • subscribers

 

Publishers are the ones that raise the event or expose the event.

Subscribers are the ones that are interested in these events.

 

When i look at the examples they all give similar examples mostly on the Gui side of the things.

Events make more sense in the user interface at the end

Where as it makes more sense as the application get bigger and bigger

 

Before events in oo world there was Business Transaction Events that i get to know.

so there was events in that sense before

 

For e.g. Class CL_GUI_ALV_GRID for ALV Grid has published event like USER_COMMAND, DOUBLE_CLICK and ONDRAG etc which could be used by other objects (programs to subscribe and use).

 

How do we use Events in Our Apps

 

We need to decide whether we need events in our applications.

 

Define: is there an important news that involves some objects to know( coupling)

 

If the answer is yes and you are enthusiastic

 

Apply the events in your objects!!

 

 

Scenario:  i  am going to use a scenario here, lets say we have an application of  editors like word, excel

And the user is using these tools to create documents.

So we have word application excel application etc...

 

Document creation is going to be our main event!!

 

in my opinion better that all the events are exposed through interfaces!!

important:The full code is attached as a zip file you can see the other object like lcl_document below!!

 

 

Step 1 -- Define the publisher interface ( events are here)

 

in Code:

 

**Publisher

interface lif_event.

   EVENTS: document_created.

ENDINTERFACE.

 

Step 2- Define the Listener interface( who needs to know)

***Listener

INTERFACE lif_listener.

   METHODs: on_document_created FOR EVENT document_created

   of lif_event.

ENDINTERFACE.

 

Step 3 - Then comes to play the event publishers that implement the publishing interface.

All the listeners are registered through the interface

 

 

class lcl_word_app DEFINITION.

   PUBLIC SECTION.

     INTERFACES lif_publisher.

methods: create_document EXPORTING eo_document TYPE REF TO lcl_document.

ENDCLASS.

 

 

class lcl_excel_app DEFINITION.

   PUBLIC SECTION.

     INTERFACEs lif_publisher.

methods: create_document EXPORTING eo_document TYPE REF TO lcl_document.

ENDCLASS.

 

Step 4- Event listeners who are interested in the events

 

******Listeners go here!!!!!!

 

class lcl_listener_1 DEFINITION FINAL.

   PUBLIC SECTION.

     INTERFACES lif_listener.

     ALIASES on_document_created for lif_listener~on_document_created.

 

ENDCLASS.

 

 

class lcl_listener_2 DEFINITION FINAL.

   PUBLIC SECTION.

     INTERFACES lif_listener.

     ALIASES on_document_created for lif_listener~on_document_created.

 

ENDCLASS.

 

Last Steps of course:

 

***** is the User

class lcl_user DEFINITION.

   PUBLIC SECTION.

     class-data: lcl_word_app TYPE REF TO lcl_word_app,

                 lcl_excel_app  TYPE REF TO lcl_excel_app.

 

     CLASS-METHODS: class_constructor.

 

     METHODS: raise_word_event.

     METHODS: raise_excel_event.

ENDCLASS.

 

 

You can see the full code in the report z_test_events

 

 

I hope it was clear and you find it useful!!

 

Please comment on anything

Embedding Flash content in SAP GUI

$
0
0

Embedding Flash content in SAP GUI

 

 

We as ABAP Developers are always interested in making SAP more and more interesting as well as take things to the extreme. In this post I will try to embed a Flash animation in the SAP GUI.

Embedding Flash animations, unlike images, cannot be done by uploading content in SWO0 and then using a function module to fetch the content. Instead, the content needs to be displayed in a container which will somehow support flash content. We know that flash content is easily displayed in web browsers and thus can be displayed in SAP GUI as well if we are able to create a container for HTML content. There is a simple report available in SAP which helps us create a container for HTML in SAP GUI. You can go to SE38 or SE80 to check the report SAPHTML_DEMO1. This is a good example of cl_gui_html_viewer.

The report is quite simple to understand for an ABAPer and we can copy the report and screens and then customize the container using screen painter.

Given below is an example on a demo I made for test purposes.

 

gif.gif

(link: http://cdn.makeagif.com/media/8-01-2013/Cjh2Qa.gif)


Here, instead of linking the container's HTML content to a web page, I linked it to the swf object in a local drive. However, the flash object can be placed in

banner.jpg

a web server or an FTP server so that the content is available to all users. You may also upload the swf file in the MIME repository of a BSP application from where you can directly access the file.

 

 

The benefits of embedding a flash animation in SAP are many. For example, the customer might be intrigued by the idea that there exists a dynamic content in a particular SAP transaction where the user can view a demo or presentation. Interactive Flash animations can also serve many more purposes and extends the capabilities of SAP.

 

I know that you would like to try this for yourself, so check the above mentioned demo report or the code below. To get the report working you need to draw a custom container named 'HTML' in screen 100 of the report and a use the menu painter to enable the back button.

 

 

 

 

 

 

 

 

 


 

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

*& Report  ZTEST_GAURAB_01

*&

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

*&

*&

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

 

 

REPORT ztest_gaurab_01 MESSAGE-ID z1.

 

 

DATA: html_control TYPE REF TO cl_gui_html_viewer,

      my_container TYPE REF TO cl_gui_custom_container,

      fcode LIKE sy-ucomm,

      edurl(2048),

      alignment TYPE i.

 

 

SET SCREEN 100.

 

 

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

*&      Module  STATUS_0100  OUTPUT

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

MODULE status_0100 OUTPUT.

  SET PF-STATUS 'TESTHTM1'.

  SET TITLEBAR '001'.

 

 

  IF my_container IS INITIAL.

 

 

    CREATE OBJECT my_container

        EXPORTING

            container_name = 'HTML'

        EXCEPTIONS

            others = 1.

    CASE sy-subrc.

      WHEN 0.

*

      WHEN OTHERS.

        RAISE cntl_error.

    ENDCASE.

  ENDIF.

 

 

  IF html_control IS INITIAL.

    CREATE OBJECT html_control

         EXPORTING

              parent    = my_container.

    IF sy-subrc NE 0.

      RAISE cntl_error.

    ENDIF.

 

 

    PERFORM load_home_page.

  ENDIF.

ENDMODULE.                             " STATUS_0100  OUTPUT

 

 

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

*&      Module  USER_COMMAND_0100  INPUT

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

MODULE user_command_0100 INPUT.

 

 

  CASE fcode.

    WHEN 'BACK'.

      IF NOT html_control IS INITIAL.

        CALL METHOD html_control->free.

        FREE html_control.

      ENDIF.

      IF NOT my_container IS INITIAL.

        CALL METHOD my_container->free

          EXCEPTIONS

            OTHERS = 1.

        IF sy-subrc <> 0.

*         MESSAGE E002 WITH F_RETURN.

        ENDIF.

        FREE my_container.

      ENDIF.

 

 

      LEAVE PROGRAM.

 

 

    WHEN OTHERS.

      CALL METHOD cl_gui_cfw=>dispatch.

 

 

  ENDCASE.

  CLEAR fcode.

ENDMODULE.                             " USER_COMMAND_0100  INPUT

 

 

* Homepage form

FORM load_home_page.

  DATA: doc_url(80).

 

 

    doc_url = 'U:\Desktop\banner.swf'.

    CALL METHOD html_control->show_url

         EXPORTING

              url       = doc_url.

 

 

ENDFORM.                               " LOAD_HOME_PAGE


Logging Objects into DB in OO Abap

$
0
0

When to log objects into DB?

 

Applications get bigger and bigger due to the evolving changes in requirements.

 

Scenario: You are working on a project where users enter data through screens and

you probably do BAPI/BADI calls or BDC calls.

Application holds very valuable data, sensitive.

You need to save each data as possible.

 

Logging is one way of doing this.

You can log the data into tables...

 

Business Scenario: This is a real world exampleç lets say you are working on a project where

users can be able to create many acct documents at a time, depending on the data users enter.

 

So you need to save each data, screen data, the internal tables, etc....

 

Lets say user has entered all the screen data and lots of business calculations behind the scene occur.

Smth went wrong during the process we need to see every data thats been entered

Murphys Law things that can go wrong will definetely go wrong.

 

How to  Approach?

 

Foundation: Object oriented world we should be living inso we need to answer all these questions in OO world.

 

Approach: we will need to wrap all the data in objects from the screen data to the data that we will need to analyze.

 

Lets say screen data is wrapped up as a z class which hold many details of the screen as well as the internal tales.

 

 

How to store object into DB?

 

How can we store object into the DB, we need a way to map object to a data type.

The possible way is storing the object as raw data of course eg rawstring.

 

 

How to convert objects into raw data

 

Of course the answer lies at the Serilazibility and the transformation of the object

IF_SERIALIZABLE_OBJECT is the interface that needs to be implemented!!

 

**transform the object

  CALL TRANSFORMATION ID_INDENT

     SOURCE OBJ = IO_OBJECT ( has to be serializable)

     RESULT XML LT_RESTAB.

 

Then we can convert much easily ...:)

 

 

Here the Transformation

 

Sample code for the Transformation:

 

class ZCL_GENERAL definition

   public

   create public .

 

*"* public components of class ZCL_GENERAL

*"* do not include other source files here!!!

public section.

 

   class-methods TRANSFORM_OBJECT_TO_RAWSTRING

     importing

       !IO_OBJECT type ref to IF_SERIALIZABLE_OBJECT

     returning

       value(RV_XSTRING) type XSTRING

     exceptions

       TRANSFORMATION_FAILED .


   class-methods TRANSFORM_RAWSTRING_TO_OBJECT

     importing

       value(IV_XSTRING) type XSTRING

     exporting

       !EO_OBJECT type ref to IF_SERIALIZABLE_OBJECT

     exceptions

       TRANSFORMATION_FAILED .

 

endclass.

 

 

Implementation

 

Transformatıon Sample Code: Notice that there is also compression applied!!

 

 

METHOD TRANSFORM_OBJECT_TO_RAWSTRING.

   types:

     line_t(4096) type x .

   types:

     table_t type standard table of line_t .


   DATA:LT_RESTAB TYPE table_t.

   FIELD-SYMBOLS: <LFS_RESTAB> LIKE LINE OF LT_RESTAB.

 

 

   CALL TRANSFORMATION ID_INDENT

     SOURCE OBJ = IO_OBJECT

     RESULT XML LT_RESTAB.

 

   IF LT_RESTAB IS NOT INITIAL.

     LOOP AT LT_RESTAB ASSIGNING <LFS_RESTAB>.

       CONCATENATE RV_XSTRING <LFS_RESTAB>

       INTO RV_XSTRING IN BYTE MODE.

     ENDLOOP.

 

**compresss here

     TRY.

         CALL METHOD CL_ABAP_GZIP=>COMPRESS_BINARY

           EXPORTING

             RAW_IN   = RV_XSTRING

           IMPORTING

             GZIP_OUT = RV_XSTRING.

       CATCH CX_PARAMETER_INVALID_RANGE .

       CATCH CX_SY_BUFFER_OVERFLOW .

       CATCH CX_SY_COMPRESSION_ERROR .

     ENDTRY.

 

   ELSE.

     RAISE  TRANSFORMATION_FAILED.

   ENDIF.

 

 

   ENDMETHOD.

 

We transformed the object into raw data!!

 

Now we need to recover the data back tooo from rawstring back to the object we saved!!

 

 

How to Recover

Notice that we use compression to save more data!!!

 

 

METHOD TRANSFORM_RAWSTRING_TO_OBJECT.

   DATA: LV_XSTRING_DECOMPRESSED TYPE XSTRING.

 

 

***Restore the object here

****first decompress the object

*now decompress

   CL_ABAP_GZIP=>DECOMPRESS_BINARY(

     EXPORTING

       GZIP_IN     = IV_XSTRING

     IMPORTING

       RAW_OUT     = LV_XSTRING_DECOMPRESSED

          ).

 

 

   " revert TRANSFORMATION

   CALL TRANSFORMATION ID_INDENT

     SOURCE XML LV_XSTRING_DECOMPRESSED

     RESULT OBJ = EO_OBJECT.

 

   IF NOT EO_OBJECT IS BOUND.

     RAISE TRANSFORMATION_FAILED.

   ENDIF.

 

ENDMETHOD.

 

 

 

 

Testing the Transformation

 

Here is a sample code to test the transformation!!!

 

METHOD TEST_TRANSFORM.

   DATA: LO_OBJECT TYPE REF TO ZCL_TEST,

         LO_OBJECT_RECOVERED TYPE REF TO ZCL_TEST,

         LO_OBJECT_SERILIAZABLE TYPE REF TO IF_SERIALIZABLE_OBJECT,

         LV_XSTRING_COMPRESSED TYPE XSTRING

        .

 

 

 

   CREATE OBJECT LO_OBJECT.

 

   LV_XSTRING_COMPRESSED =

   ZCL_AKSA_GENERAL=>TRANSFORM_OBJECT_TO_RAWSTRING(

   IO_OBJECT = LO_OBJECT

     ).

 

 

   ZCL_AKSA_GENERAL=>TRANSFORM_RAWSTRING_TO_OBJECT(

      EXPORTING

        IV_XSTRING            = LV_XSTRING_COMPRESSED

      IMPORTING

        EO_OBJECT  =   LO_OBJECT_SERILIAZABLE

     EXCEPTIONS

       TRANSFORMATION_FAILED = 1

          ).

   IF SY-SUBRC <> 0.

* MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO

*            WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.

   ENDIF.

 

 

***type cast

   LO_OBJECT_RECOVERED ?= LO_OBJECT_SERILIAZABLE.

 

 

*  CL_AUNIT_ASSERT=>ASSERT_EQUALS(

*      EXP                  = LO_OBJECT

*      ACT                  = LO_OBJECT_RECOVERED

**    MSG                  = MSG

**      LEVEL                = CRITICAL

**    TOL                  = TOL

**    QUIT                 = METHOD

**    IGNORE_HASH_SEQUENCE = ABAP_FALSE

*         ).

 

 

 

ENDMETHOD.

 

 

Notice the type casting from the serliazable object back to the object type!!!


Open XML edit document Contents

$
0
0

This is a screen cast showing  Word Open XML documents generation

from  SAP.

after the documents are generated,

there is a nice example of how to manual

editing some of the documents contents

using Open XML principles

such as OPC ( open packaging convention ).

it can give you a better understanding

of Open XML in SAP

and think of how can it help you

in  your daily work.

 

 

http://youtu.be/t8s_PYLHKns

 

 

Enjoy

 

Ronen Almog

Things that are cool to change for everyone and those you’d better don’t touch

$
0
0

<rant>

Dear SAP,

I have just upgraded my system and there are several things I would like to ask you about. There are things that would be very cool if you could change them for everyone, every single SAP system at some stage (via upgrades and for new installations too). But there are also things, that don’t help at all. They don’t help me at least. Of course, this is my opinion only, and I am more wondering about your reasons (please share it with us, we are listening), than a blind criticism.

 

No, thank you: CALL FUNCTION pattern in SE80

First of all the trigger for this blog: When I use the function module pattern in SE80 after the upgrade to Basis 7.31, the default message handling is gone. I could understand what might have been the reason: you want the developers to more active and instead of just leaving the MESSAGE code there as the default handling, you want the developers to actually do something, right? Well, ok, good idea. But the problem is that (if I am not mistaken), the default MESSAGE statement was there for so long, that thousands of developers (more like millions?) have gotten used to it, they have been designing their code with this “feature in mind” and last but not least they have been very efficient using this particular part of the pattern.

I was FAR MORE efficient before you changed this. Now, when I use the CALL FUNCTION pattern, I must go search for a section of code, where I have this message handling from the old times. I want it the old way, but the system took it away.

Did you run a Design thinking session first and that got you this idea? Well, the source of the idea is not that important for me. Did anyone think about the impact? That is far more important for me.

 

No, thank you: Warnings from the syntax check

Example number two: I am a tidy developer, I don’t like warnings in my code and that is why 99,9% of my code is warning free (in case you’re interested, that 0,1% of the code with warnings is shortening the real field length to a shorter length for SQL operations; then I am able to compare something that is 40 characters long field, but I know it only has 20 characters long value with a DB field that is 20 characters long by definition; if you wonder what is the reason for this, it is of course the fact that fields with same values are often defined differently and I don’t want to spend time on conversions).

Now, after the upgrade, all my code turns yellow, because of the funny warning that you’ve introduced, that one can hide with pragma called ##TOO_MANY_ITAB_FIELDS. For those who don’t know it yet: if you define your work-area as type MARA, but you only select MATNR field, you will get this warning telling you that your work-area is too big which is a waste of memory (I am guessing that is the reason here). In case of single field I can understand that, total waste. But how often we – normal average ABAPers – select half of the fields from a table (knowing that we don’t need the other fields and that is why we don’t ask for them, we are efficient with our SQLs by naming the fields we want, so why do you tell me the same thing with this new warning?) and to be fast (and spare ourselves the effort to define a local or even a DDIC type) we define the work-area as TYPE TABLE OF whatever we’re querying?

 

Screenshots follow, so we all are on the same code-page:

message.png

pragmas.png

 

I want my code to be “green”. I don’t want any warnings. I must go and get rid of these so that I can see the IMPORTANT warnings - those telling me PROBLEMS with my code. Maybe the intention is right, but honestly… I don’t appreciate this particular effort. If it must be there, because customer asked for it, ok. But give me a mean to turn it off. Is there such way? I have checked the documentation and didn’t find one.

Added later: There is a very VERY fast way how to get rid of this warning. Guess what. If you perform SELECT * instead of listing the fields so you're now using all fields of your work-area, the warning goes away. I don't want to argue about your good intentions, dear SAP, but what is your estimation that people don't go this way? My estimation? Well, people hate annoying warnings more than sub-optimal database access...

 

Please do: clients 001 and 066

On the other hand there are things that are very good and the right way for the sake of the better world to do in the SAP standard. An example from the recent history would be the blog by Frank Bucholz: How to remove unused clients including client 001 and 066.

See my comment below the blog asking when we don’t install these clients at all instead of following instructions how to remove them. Frank is well known for his effort to make the world better, so the fact that I am highlighting his blog is to appreciate an important piece of information for everyone. It is not a criticism in any way. But it is also an appeal on SAP to finish doing the right thing here – don’t install what we don’t need. Taking care of these clients is for me far more important than adding warnings or removing patterns that add more work for the normal mortals.

</rant>

p.s.: If anyone knows how to get rid of these new “features”, please let me know. If anyone can explain why they are there and I am wrong, please also leave a comment.

Executing multiple function modules/BAPIs at a time

$
0
0

There have been times when an ABAPer needs to execute multiple function modules/BAPIs for testing purpose, at a time, which is pretty common in the case while executing a BAPI. For example, some BAPIs needs a BAPI_COMMIT to be executed just after the execution of the Main BAPI you want to execute.

To execute multiple BAPIs/ function modules at a time in SE37:

 

1. When into transaction SE37, goto Function Module->Test->Test Sequence.

multi_se37.jpg

 

2. Following screen will pop-up. Enter Function Modules / BAPIs in sequence and press OK to execute in sequence.

multi_se37_b.jpg

 

You can also save BAPI/ Function Module sequence and call it again when needed using Get Sequence button on second screen.

Using the output of a Standard/Already Developed ALV report

$
0
0

So Recently, in one of my Objects that a member of my team was supposed to develop an ABAP Report which had to have an output that was exactly same as the one of the standard Transactions(IE05) . 

 

Here's what i ended up doing:

 

  1. We need to call the SET method of the class CL_SALV_BS_RUNTIME_INFO as shown below :
      • cl_salv_bs_runtime_info=>set(

                             EXPORTING

                                 display  = abap_false

                                 metadata = abap_false

                                 data     = abap_true

                          ) .

      •   What this does is to tell the system that the report has to be running with no DISPLAY no METADATA on only get the ALV DATA.                   

 

     2. Z* report where i used the used the SUBMIT Statement so call the standard report .

                              SUBMIT riequi20 AND RETURN .

    • The AND RETURN addition ensures that the the control is returned to the calling program .
    • You can use the various other additions of the SUBMIT statement to pass on the selection screen parameters .

         3. Next use the GetDataRef method of the class CL_SALV_BS_RUNTIME_INFO to get the actual data  into a local object  type ref'ed to DATA.

                        DATA obj_data TYPE REF TO data .

                       FIELD-SYMBOL <fs_data> TYPE any .

     

                        TRY.

                             cl_salv_bs_runtime_info=>get_data_ref(

                              IMPORTING

                                  r_data = obj_data

                                 ) .

                              ASSIGN obj_data->* TO <fs_data>.

     

                        CATCH cx_salv_bs_sc_runtime_info.

                             Write : / data not captured.

                         ENDTRY.

          4. The data from the ALV should now be in the fs_data Field-Symbol. We can now change or do any further validations on it.

     

    Thanks to Glen Simpsons Blog for this, it saved me lot of time .

     

    Oputput Problems

     

    I ran into one tiny little problem. Some of the fields like the System Status and the User Status and others did not have any values in them. This was very Weird as when i Ran the Standard report with the same selection screen parameters the values were populated.

     

    So as mentioned in my SCN discussion.

     

    I had the complete set of data that the Standard report outputs in my internal table and i just the ALV Class to output it to my screen.

     

    PROBLEM:

     

    But after checking the data (100+ fields) in the ALV report my Z program creates, I found that some of the Fields which the Standard report does have values for are not populated.

     

    Debugging:

     

    So, i decided to debug the Standard program so see why i didn't get some of the fields into my output.

     

    Turned out that the internal table that was being fed into the REUSE_ALV_GRID_DISPLAY( Location: RIEQUI20 > MIEQUI20 > MIOLXF14 line 108 of include )  FM in the Standard report also does not have the values for the same fields when the FM for ALV is called. (PFA image of the point where the FM is being called.(in case some of you want to debug it yourselves )

     

    e.g. : the value of the table OBJECT_TAB-STTXT is Empty  when the REUSE_ALV_GRID_DISPLAY is called ,

    but in the final ALV output  the fields System Status (STTXT) has the corresponding values . This was very troubling and as with all such situations it had a very simple solution.

     

    http://f.cl.ly/items/0L3X2H2107043c3G242G/Screen%20Shot%202013-08-03%20at%202.20.54%20PM.png

     

    Solution and Reason


    What was happening was that the there was a default LAYOUT on the ALV screen that was set based on which the standard program did not fetch some of the fields that it did not have to display.

    So i went into the standard Report output, click on the change layout button (Ctrl + F8 ) and create a New Default Layout with all the fields i wanted an output for .

     

    Hope this helps some save some time.

     

    Have a Good day.

    Amarpreet.


    Protecting ABAP code against Directory Traversal Attacks

    $
    0
    0

    as pointed out by Horst Keller in one of his blogs, security is important and nothing which should be an afterhtought. Also it is nothing that can be solved by SAP alone but a topic for each and everyone developing code. However SAP has quite some functionality, that assist you to counter attacks more easily.

    In this blog, I will show you, how to protect access to file against directory traversal attacks.

    Directory traversal attacks often also called path traversal attacks try to abuse insufficient sanitization and validation when taking user input as (part of) filenames. One simple example could be the ability to create a file with some input on the application server. A very simple program to do this could look like shown below:

     

    REPORT Z_UPLOAD_NO_CHECK.
    PARAMETERS: pv_fname TYPE c LENGTH 64 LOWER CASE DEFAULT 'test.txt',
                pv_text 
    type string LOWER CASE DEFAULT 'This is the file contents'.
    DATA        lv_full_name TYPE string.

    AT SELECTION-SCREEN
    .
     
    if pv_fname = ''.
       
    MESSAGE 'You need to specify a file name.' TYPE 'E'.
     
    ENDIF.
      lv_full_name
    = '/tmp/' && pv_fname. "Assume enduser inputs only a relative file name.

    START-OF-SELECTION
    .
     
    OPEN DATASET lv_full_name FOR OUTPUT IN TEXT MODE ENCODING UTF-8 .
     
    IF SY-SUBRC <> 0.
         
    MESSAGE 'Could not open file' && lv_full_name TYPE 'E'.
     
    ELSE.
         
    TRANSFER pv_text TO lv_full_name.
         
    CLOSE DATASET lv_full_name.
         
    Write :/ 'contents was saved to:', lv_full_name.
     
    ENDIF.

    What the program does, is simply asking for a file name and the content for the file. It just assumes, that the file name will be relative (like test.txt) and not absolute (like C:\TEMP\test.txt or /tmp/test.txt) and therefore just concatenate the directory the files shall be placed into and the filename itself. In the end it will open the file for writing and put the input of the user into the file.

     

    What’s wrong with this? Two things:

    • The developer defines the directory where to place the files. If the directory does not exist, the admin can only request a new program.
    • The code does not check, whether the file will really end up in /tmp or somewhere else on the server.

    Let’s have a closer look at the second issue. Let’s assume we use a filename like ../(etc/passwd. What happens? The code will concatenate ‘/tmp/’ and ‘../etc/passwd’ into ‘/tmp/../etc/passwd’. In case the operating system is unix based, the system would understand ‘/etc/passwd’ as the file intended to be accessed. It is obvious, that this was not the intention of the programmer. In fact, the attacker would be able to access many operating system files which definitly should be considered a risk using this program.

    So how can we avoid this. For sure, you can just search for ‘../‘ occurring in the input and remove that part. However if you are on a Windows based OS, this is not ‘../’ but ‘..\’ and also what happens if there are more dots, . In addition, the characters may be encoded for instance using UTF-8 and therefore look even different again. So doing this by searching just for some characters, is not that easy. You can have a look at the Wikipedia article on directory traversal attack to get an idea what is involved to protect your code.

    To acounter such risks, the ABAP application server has capabilities to do this for you. As part of the function group SFIL, there is the transaction file, where you can define logical directories and logical filenames and there are function modules like file_get_name and file_validate_name to use the information captured with file to create filenames or verify, whether they are valid. This functionality is Unicode enabled, OS aware and is able to understand the input and interpret it, like an operating system would do.

    Especially when using file_get_name, you may want to check your SP level, as there have been significant improvments done there. Please check SAP note 1497003 for more details.

     

    The SFil Infrastructure

    The function group SFil provides the functionality to easily handle access to files, by providing  logical filenames to developers and functions to map these logical filenames to physical filenames by the administrator.

     

    Logical Filenames

    Logical filenames in ABAP are patterns used to create or verify filenames used on a server or client system. Logical filenames include information about

    ·         The name to refer to the logical filename

    ·         The pattern for the filename

    ·         A data format (ASCII, Binary, Directory, …)

    ·         Application area

    ·         Optional: a logical path

    The filename portion defined can be absolute (start from a root) or relative. If you want to specify filenames outside the working directory of the app server, I suggest you use the logical directories.

    Filename pattern may include predefined patterns like date, time, OS or patterns based on profile parameters and more. You can even have the program provide his own input to the parameters using the parameters <PARAM_1> to <PARAM_3>. However I would recommend not to make use of these parameters for file name validation.

     

    Logical Paths

    Logical paths are an abstraction to the directories on different operating systems. The advantage here is the ability to specify one directory per OS, even though you only have one common logical directory name. For instance SAP delivers a logical path called ‘TMP’, which already contains the directories to be used to place temporary files on unix and windows operating systems.

    log_path.png

    File_Get_Name

    Using the function module file_get_name, you can create filenames based on definitions in transaction file. You have to provide the logical filename and will get back the filename based on the definition in file. Please note, that the filename will only contain the directory if you request this from file_get_name explicitly.

     

    File_Validate_name

    File_validate_name checks whether a given filename is within a directory specified. You have to provide the filename to be checked and a logical filename to check it against. If you want to check, whether a given file is within a defined directory, you have to define a logical filename of type ‘DIR’ (directory). File_validate_name will not accept logical directories directly.

    If the filename given is not absolute (for instance ‘test.txt’), file_validate_name will make it an absolute one by adding the working directory of the application server (profile parameter DIR_HOME). For this reason, you need to put the intended directory in front of relative filenames before calling file_validate_name.

    File_validate_name will also accept all filenames which are at a deeper level of the hierarchy. This implies that the file/tmp/foo /bar would be a valid file when compared to /tmp in the sense of file_validate_name.

     

    Doing it right

    Getting back to the example above, we have to permit the admin to define where the files are placed and validate the filenames or let the system generate them.

    Let’s first have a look at how generating filenames works. There are two options, how the program can be changed:

    • using a predefined filename for the file to be created
    • verifying the filename provided by the user

     

    Using a predefined filename defined by the admin

    In this case you can create a logical filename like the one below in transaction file. This definition will result in filenames that are valid on unix and windows systems and will contain the date and time of the creation of the filename.

    ZMY_outfile.png

    If we would call file_get_name on 2013-08-06 at 17:35:15, the following filename would be created:

    Operating SystemFile Name
    Unix

    /tmp/test-20130801-173515.txt

    WindowsC:\Windows\Temp\ test-20130801-173515.txt

    Please note, the path on windows is dependent on the profile parameter for temporary files. So the path may look different on your system.

    Using file_get_name and the definition as shown above, we can now create a safe version of the program.

     

    REPORT Z_UPLOAD_FILE_GET_NAME.
    PARAMETERS pv_text  type string LOWER CASE DEFAULT 'This is the file contents'.
    DATA       lv_full_name TYPE string.

    AT SELECTION-SCREEN.

    START-OF-SELECTION
    .* get the filename including the path from the configuration
     
    CALL FUNCTION 'FILE_GET_NAME'
       
    EXPORTING
          LOGICAL_FILENAME             
    = 'ZMY_OUTFILE'
          INCLUDING_DIR                
    = 'X'
      
    IMPORTING
          FILE_NAME                    
    = lv_full_name
      
    EXCEPTIONS
         FILE_NOT_FOUND               
    = 1
        
    OTHERS                        = 4.
     
    IF SY-SUBRC <> 0.
         
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
           
    WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
     
    ENDIF.

     
    OPEN DATASET lv_full_name FOR OUTPUT IN TEXT MODE ENCODING UTF-8 .
     
    IF SY-SUBRC <> 0.
         
    MESSAGE 'Could not open file' && lv_full_name TYPE 'E'.
     
    ELSE.
         
    TRANSFER pv_text TO lv_full_name.
         
    CLOSE DATASET lv_full_name.
         
    Write :/ 'contents was saved to:', lv_full_name.
     
    ENDIF.

    Verifying the filename provided by the user

    In the previous example, the admin has complete control over the files created, however from an application point of view, this may not be flexible enough.

    When the user shall be able to specify a file name, you need to make use of file_validate_name. In this case the admin defines a permitted directory using transaction file.

    Please note, that although you need to specify a directory here, you will have to create this under logical filenames. Also you must specify ‘DIR’ as being the data type for this entry.

    The example again will make use of the predefined logical directory TMP.

    ZMY_outdir.png

    There are some traps you need to get around when using file_validate_name.

    File_validate_name works with absolute filenames only. Therefor you have to make relatives filenames absolute first. Also you must specify the INCLUDING_DIR parameter on file_get_name when accessing filenames of type 'DIR', as otherwise the function will dump.

    A safe version for the program could then look like this:

     

    REPORT Z_UPLOAD_FILE_VALIDATE_NAME.

    PARAMETERS: pv_fname       TYPE c LENGTH 64 LOWER CASE DEFAULT 'test.txt',
                pv_text       
    TYPE string LOWER CASE DEFAULT 'This is the file content.'.
    CONSTANTS   lc_log_fname   LIKE FILENAME-FILEINTERN VALUE 'ZMY_OUTDIR'.
    DATA:       lv_full_name   TYPE string,             " filename
               lv_defaultpath TYPE string.
    INITIALIZATION.* get the path, where the files should be placed from the configuration
     
    CALL FUNCTION 'FILE_GET_NAME'
       
    EXPORTING
          LOGICAL_FILENAME           
    = lc_log_fname
          INCLUDING_DIR              
    = 'X'
       
    IMPORTING
          FILE_NAME                  
    = lv_defaultpath
       
    EXCEPTIONS
         
    OTHERS = 1.
     
    IF sy-subrc <> 0.
       
    MESSAGE ID sy-msgid TYPE 'I' NUMBER sy-msgno
       
    WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
     
    ENDIF.

    AT SELECTION-SCREEN.
     
    IF pv_fname = ''.
       
    MESSAGE 'You need to specify a file name.' TYPE 'E'.
     
    ENDIF.
    * check whether the file name is a relative one
     
    IF cl_fs_path=>create( pv_fname )->is_relative( ) = abap_true.
       
    " file name is a relative one, put the default path before the filename
       
    " we also need to check in this case, as '/tmp' + '../etc/test.txt' is still outside /tmp
        lv_full_name
    = lv_defaultpath && pv_fname.
     
    ELSE.
       
    " file name is already absolute, just use it.
        lv_full_name
    = pv_fname.
     
    ENDIF.

     
    CALL FUNCTION 'FILE_VALIDATE_NAME'
       
    EXPORTING
          LOGICAL_FILENAME           
    = lc_log_fname
       
    CHANGING
          PHYSICAL_FILENAME          
    = lv_full_name
       
    EXCEPTIONS
          LOGICAL_FILENAME_NOT_FOUND 
    = 2
          VALIDATION_FAILED          
    = 1
         
    OTHERS                      = 4.
     
    IF SY-SUBRC <> 0.
       
    IF SY-SUBRC > 1.
         
    MESSAGE ID sy-msgid TYPE 'A' NUMBER sy-msgno
           
    WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
       
    ELSE.
         
    MESSAGE 'The filename >' && pv_fname && '< is not valid, please try again.' TYPE 'E'.
       
    ENDIF.
     
    ENDIF.

    START-OF-SELECTION.
     
    OPEN DATASET lv_full_name FOR OUTPUT IN TEXT MODE ENCODING UTF-8 .
     
    IF SY-SUBRC <> 0.
         
    MESSAGE 'Could not open file' && lv_full_name TYPE 'E'.
     
    ELSE.
         
    TRANSFER pv_text TO lv_full_name.
         
    CLOSE DATASET lv_full_name.
         
    Write :/ 'contents was saved to:', lv_full_name.
     
    ENDIF.

     

    If you need more information on the functions used above to protect against directory traversal attacks, you can allways have a look at the secure programming guide, the documentation for transaction FILE, for the function module file_get_name and for the function module file_validate_name.

    Pictures from MIME Repository in HTML

    $
    0
    0

    This is about embedding a picture that is stored in the MIME repository in an HTML-file. I will show two ways of accessing the picture:

     

    • using an API
    • using the ICF

     

    There are many ways of displaying an HTML file. Again I will show two ways:

     

    • using the SAP GUI Control Framework
    • using the ICF

     

    The methods for accessing the MIME repository and displaying the HTML file can be combined.

     

    The code examples shown in the following partly use ABAP 7.40 syntax. To run on 7.31, 7.03, 7.02, 7.0 you have to replace some expressions with the respective statements.

     

     

    Accessing the MIME Repository with an API

     

    In order to get a picture stored as a node of the MIME repository into an ABAP program you simply use code as follows (before 7.40, you have to declare DATA img TYPE xstring before the method call instead ot the inline declaration):

     

    cl_mime_repository_api=>get_api( )->get(
            EXPORTING i_url = `/SAP/PUBLIC/BC/ABAP/mime_demo/ABAP_Docu_Logo.gif`
            IMPORTING e_content = DATA(img) ).

     

    After this, the xstring img contains the GIF-picture passed to the GET-method.

     

     

    Using the Picture in the SAP GUI Control Framework

     

    After loading the picture into ABAP, you can embed it in an HTML-file shown in the browser control of the SAP GUI Control Framework (CFW). To do so,you must load it into the browser control. Unfortunately, method LOAD_DATA of CFW class CL_GUI_HTML_VIEWER was created in Release 4.6 and does not accept strings that were added to ABAP in Release 6.10. Therefore, you have to convert the above xstring to an internal table first:

     

    TYPES: pict_line(1022) TYPE x,

           pict_tab TYPE STANDARD TABLE OF pict_line WITH EMPTY KEY.

     

    DATA(length) = xstrlen( img ).

    WHILE length >= 1022.

      APPEND img(1022) TO pict_tab.

      SHIFT img BY 1022 PLACES LEFT IN BYTE MODE.

        length = xstrlen( img ).

    ENDWHILE.

    IF length > 0.

      APPEND img TO pict_tab.

    ENDIF.

     

    Now you can load it:

     

    DATA pict_url TYPE c LENGTH 255.

    DATA(html_control) = NEW

         cl_gui_html_viewer( parent = custom_container ).

    html_control->load_data(

      EXPORTING

        url          = 'picture_url'

        type         = 'image'

        subtype      = '.gif'

      IMPORTING

        assigned_url = pict_url

      CHANGING

        data_table   = pict_tab ).

     

    The URL returned by that method in pict_url can be used in an HTML-File loaded into the same browser control:

     

    DATA(html_tab) = VALUE html_tab(

      ( '<html><body><basefont face="arial">' )

      ( 'Picture with CL_GUI_HTML_VIEWER<br><br>' )

      ( '<img src="' && pict_url && '">' )

      ( '</body></html>' ) ).

    html_control->load_data(

      IMPORTING

       assigned_url = html_url

      CHANGING

        data_table   = html_tab ).

     

    html_control->show_url(

       EXPORTING

         url = html_url ).

     

    Before Release 7.40 you have to APPEND the lines to html_tab of course.

     

    Since Release 7.02 there is also the convenience class CL_ABAP_BROWSER, that encapsulates CL_GUI_HTML_VIEWER and does the loading for you:

     

    DATA(ext_data) =

      VALUE cl_abap_browser=>load_tab( ( name = 'PICT.GIF'

                                         type = 'image'

                                         dref = REF #( pict_tab ) ) ).

     

    DATA(html_tab) = VALUE cl_abap_browser=>html_table(

          ( '<html><body><basefont face="arial">' )

          ( 'Picture with CL_ABAP_BROWSER<br><br>' )

          ( '<img src="PICT.GIF">' )

          ( '</body></html>' ) ).

     

    cl_abap_browser=>show_html( html        = html_tab

                                         data_table  = ext_data ).

     

     

    You only have to pass a reference to the picture table to method SHOW_HTML that is the assigned the same name as it is used in the HTML-File.

     

    Using the Picture in ICF

     

    In order to display an HTML-file using the Internet Connection Framework (ICF), you can create an HTTP service in transaction ICF and provide the HTML-file in the handler class of that service. The following  method implementation sends data depending on the form field pict_flag of the URL. If pict_flag is not X, an HTML-file is sent, where the address of the picture is the current address concatenated to the form field pict_flag with value X. If pict_flag is X, the picture in our xstring img is sent. With other words, we use the same HTTP-Service to send the HTML as well as the picture embedded in the HTML.

     

    METHOD if_http_extension~handle_request.

      DATA(pict_flag) = server->request->get_form_field( name = `pict_flag` ).

      IF pict_flag <> abap_true.
        DATA(picture) =
          get_address( server = server
                       application = `/sap/bc/abap/demo_mime` )  && `?pict_flag=X"`.
        DATA(html) =
          `<html><body><basefont face="arial">`     &&
          `Picture from API<br><br>`                &&
          `<img src="` && picture&& `">`            &&
          `</body></html>`.
         server->response->set_cdata( data = html ).
      ELSE.
        server->response->set_data( data = img ).
      ENDIF.

    ENDMETHOD.

     

    The helper method get_address looks as follows:

     

    METHOD get_address.

      cl_http_server=>get_location(

         EXPORTING

           server      = server

           application = application

         IMPORTING

           host         = DATA(host)

           port         = DATA(port)

           out_protocol = DATA(protocol) ).

      IF host IS NOT INITIAL AND port IS NOT INITIAL AND protocol IS NOT INITIAL.

        address = protocol && '://' && host && ':' && port && application.

      ENDIF.

    ENDMETHOD.

     

    Accessing the MIME Repository with ICF

     

    As Sandra Rossi pointed it out: If a path in ICF is built in the same way as a path in the MIME repository and if an HTTP-service in ICF is handled by CL_HTTP_EXT_WEBDAV_PUBLIC, you can directly use the URL of that service to address the corresponding MIME objects (with other words, the predefined handler sends the contents of the MIME object as we have done in our own method above).

     

    Accessing ICF from CFW

     

    If you have such an ICF node addressing a picture, you can use it in HTML-files shown in CFW.

     

    DATA icf_node TYPE string.

    CONSTANTS path TYPE string VALUE `/sap/public/bc/abap/mime_demo`.
       
    cl_http_server=>get_location(
      EXPORTING
        application = path
      IMPORTING
        host         = DATA(host)
        port         = DATA(port)
        out_protocol = DATA(protocol) ).
    IF host     IS NOT INITIAL AND
       port     IS NOT INITIAL AND
       protocol IS NOT INITIAL.
      icf_node = protocol && '://' && host && ':' && port && path.
    ENDIF.


    DATA(html) =
      `<html><body><basefont face="arial">`                &&
      `Picture from ICF<br><br>`               &&
      `<img src="` && icf_node && `/ABAP_Docu_Logo.gif">`  &&
      `</body></html>`.

    cl_abap_browser=>show_html( html_string = html ).

     

     

    Accessing ICF from ICF

     

    Of course and last but not least you can embed a picture addressed with ICF in an HTML sent by an HTTP-handler in ICF.

     

    METHOD if_http_extension~handle_request.

      DATA(picture) =
        get_address( server = server
                     application = `/sap/public/bc/abap/mime_demo` )  &&
       `/ABAP_Docu_Logo.gif"`.

        DATA(html) = `<html><body><basefont face="arial">`     &&
                     `Picture from ICF<br><br><br><br>`        &&
                     `<img src="` && picture&& `">`           &&
                     `</body></html>`.

        server->response->set_cdata( data = html ).

    ENDMETHOD.

     

    The helper method get_address is the same as above.

     

     

    I guess, you have to play around with that a bit.

     

    The working examples I copied from above will be delivered with 7.40, SP05 and the output always looks like something as follows:

     

    pict.gif

     

     

     

    PS:

     

    As a third state of cruelty you store also the HTML-file in the MIME repository and access it either by the API or by ICF.

     

     

     

     

    Stop writing Technical Documentation nobody will ever read

    $
    0
    0

    If you're an ABAP developer, answer me: how many times do you really read the technical documentation of a Z program you're about to change? And for the times you did read the documentation, answer these: was it of any help in understanding what the code is doing? Was the documentation up to date with the source code?

     

    In this blog, I'll try to tell you why I think we should get rid of poorly created Technical Documentation (I'll refer to them as "TDs" in this article), and change to a better approach. Many projects I've been in the past can SHIFT+DEL ALL of their TDs, and nobody would ever notice. Here's why.

     

    ------------------------------------------------------------

     

     

    TDs with 10 pages for 500 lines of code

     

    First of all, I hate documentation templates. I know why it was created in the first place, but most times that "old word template" is made by someone who knows nothing about code documentation.

     

    Why do I have to add field name, description, type and length for every single field of a Z table I created inside a word document? Why do I have to specify all selection screen fields? Why do I have to copy things over from the Functional Specification?

     

    Once upon a time I was in a project where we had to create a huge set of Z tables. Me and my ABAP friends had to write down in a word document every single field, description, data type, length, data elements, domains, etc, for every table we created. A huge amount of time lost writing a document that will be out of date as soon as a small field description is changed. And if we missed something, a reviewer would blame us for making poor documentation.

     

    Due to those crazy and stupid templates, we end up having small source codes for simple processes with huge documentations. Documentations nobody ever care to read.

     

     

     

    Coding ABAP in a Word Document

     

    This one is classical. Some ABAP developers just don't care at all about code documentation. They don't write comments in the source code, and whenever they get a change they open a new word document, copy-paste the abap code from se80, name the file "SD.001 - My Program - TD" or something and consider they development is finished.

     

    CTRL+C CTRL+V from ABAP to a Word Document.... JUST DON'T. It would be better if those guys doesn't even started making the "filler" file. The funny fact about it is that some reviewers consider this outrageous thing as something completely "legal".

     

    It's all about the package: The project want to have the TD file; it doesn't matter if it's a piece of garbage. And I've seen a "CMMI level 5" software factory doing that. Way to go buddies...


     

     

    Creating a DUOBM (Document Understandable Only By Me)

     

    Ok, so the guy doesn't have to follow a stupid template, nor intend to make it a carbon copy of se80. But guess what: he also doesn't care about explaining to another developer how his code works.

     

    The whole point about having a software documentation is so other developers can understand the software. If one fail in writing a good documentation he's also failing in delivering useful information about his creation. That development is a great candidate to become an "old and ugly Z monster nobody knows what is doing".

     

    One of my favorite SAP technical documents of all time is the explanation of the good old iXML library. Take a look at this: http://help.sap.com/saphelp_nwpi71/helpdata/de/86/8280c012d511d5991b00508b6b8b11/content.htm . It's fun to read, it's well organized, and the writer knows he's explaining things to another developer. That's a major issue with software documentation in SAP projects: almost nobody cares about who's coming next. Let's just deliver everything until Go Live, make a Happy Hour and move to new projects. G-R-E-A-T.

     

     

    ------------------------------------------------------------

     

    See? These are things me and my ABAP friends faced tons of times in Brazilian and International projects. Many gigabytes of word documents created because the project methodology said they must exist before software can pass through the homologation process. A sad truth.

     

    Hopefully now you're not thinking I'm nuts by saying we should get rid of those documents. But don't get me wrong: I do like the idea of having a document explaining the software. Maybe not in the form of an word file: it can be an document created inside the SAP system, some entry in a CMS or even a small HTML file created with ASCIIDOC . But I strongly think we should be making things differently.

     

    Therefore, I know a couple of things that can help making software documentation a relevant piece of information. Turns out they are very simple things people tend to ignore.

     

    ------------------------------------------------------------

     

     

    What would you like to read in a Technical Documentation?

     

    Get in front of a mirror and ask yourself: What you like to read in a TD? A lot of technical junk you could easily find by going to the relevant transactions, or something that helps you understanding the technical approach of that code?

     

    Why you choose to add parallelism? Why did you have to use that complex recursive logic? A call transaction over a BAPI for VA02... why did you choose to do that? How your objects communicate with each other? Why that small functional process described in the functional specification turned out to be 5000 lines of code?

     

    Answer questions like these on your TDs. Your ABAP colleagues will thank you for that.

     

     

     

    Don't get too much "techy"

     

    This may sound odd at first: if we're doing the Technical Documentation, why can't we go deep down into technical stuff? Because you should explain these things using comments. I've seen a lot of TDs trying to explain small little pieces of coding techniques inside the documentation, but I strongly believe these are things that should have been added as comments in the source code.

     

    Example: "no read binary search on table X - can't sort it with this key because of <something>". That has much more value as a commentary instead of going inside the TD. People forget that comments are also a way of documenting what you're doing. Most times when we're trying to correct a small issue, we go directly to the debug screen, trying to solve the issue. Small and relevant comments can be extremely helpful in those situations.

     

    Oh, and I'm yet to see a developer asking for the TD when his boss starts screaming on him about a bug in an old production code...

     

     

     

    If you can't drop the template... what about a new one?

     

    Technical Documentation templates were probably created by someone that though those were the relevant information they would like to see in the future. But sometimes those people are not experienced developers, so how can they know what really has to be in there?

     

    If you're in a place where you can't stop using a "closed" template, make suggestions to remove the useless stuff and add some guidelines to help others adding value to that document. I bet you managers and leaders will change if it's for the best.

     

    I had the experience of completing changing a project template once, and everybody loved. Even a functional consultant friend of mine was always saying about how he could read my TDs to help him understanding the programs from a technical perspective.  "A functional consultant reading a TD"? Believe, it's true!

     

     

     

    Starting reading some TDs!

     

    I didn't realize these tips out of nowhere. When I was a very young ABAP n00b, I believed in unicorns, fairies, dragons and also in TDs. Yes, everytime I had a problem I tried to read the TD first, to see if it could give me a clue about the code. However, most times they failed miserable.

     

    As time passed by I started debugging the code without reading anything at all. People wasted time doing TDs, but I didn't want to waste my time reading them.

     

    It happens that old habits die hard, and even today I do like to take a sneak peak inside TDs. And yes, they've been the same in ABAP projects since 2006. I found cool documentations throughout these years, and they were the ones that opened up my eyes and made me change the way I wrote documentations.

     

    Start reading some, and change too.

     

     

    ------------------------------------------------------------

     

     

    I think that's everything I have to say about code documentation for now. I wrote about them in the past, but I thought this was a good time to raise the topic once more (this blog motivated me).

     

    Please, share your experiences with ugly/cool documentations on the comments section. Let's debate and change this old "non-documentation" process.

     

    Thanks very much for reading!

     

    Best Regards,

    Mauricio Cruz.

    Where Used List for Adobe Form Objects

    $
    0
    0


    There is no standard  Where-Used List option for Adobe form & interface available in transaction SFP. So I have developed one program for ‘Where-Used list for Adobe Form objects’. This program will help you finding where used objects related to adobe form & interfaces.

               transaction SFP.jpg

    Below are brief specifications about this program:

    • Gives where used list for selected object used in:
      • Interface
      • Output types
      • Program & routines
      • PP related config with program name & routine.
    • For Interface, gives where used adobe form list
    • Program also does global search for hard-coded adobe form text

     

    Steps To use this Program

     

    • Download below program and upload it on your system. Upload text element list also.
    • Run this program. Below selection screen will appear.

              input screen.jpg

    • Input selection :
      • Select Adobe form, if you want to search where used list for Adobe form. Give Adobe form name as input. You can use F4 search help.
      • Select Interface, if you want to search where used list for Interface. Give interface name as input. You can use F4 search help.
      • If you tick Global search check box, program will do global search for given name as a hard coded text in all ‘Z*’programs.  It will then show list of objects where it find hard code text.

     

    Output

     

         Sample input :

    input screen1.jpg

         Output for above input:

    output.jpg

     

        

    Import Reports for Projects.

    $
    0
    0

    Import Reports for Projects.

     

    Sometimes we try to use reports of Module Cost Object Controlling (CO-PC-OBJ) but we get error saying “Transaction XXXX does not exist”.

    Here we can say transaction 7KVD for Actual Costs.

     

    SDN1.JPGReport 7KVD is missing here.

     

     

    However these reports are available in the system but in client ‘000’, to import these reports use Transaction Code OKSR.

    You can also follow the below path to access this transaction code:

     

    SAP Ref. IMG -> Project System -> Information System -> Costs/Revenues Information System -> Cost Element Analysis -> Standard Reports -> Import Reports.

     

    SDN1.JPG

     

    Once you execute the transaction, you will get list of all available reports, It is only relevant to click on the missing reports which you need to import from the repository.

     

    Select Actual Cost Report (Techn. Name 7KVD).

     

    SDN1.JPG

     

    As a result the report has been imported from client 000 to client 100

     

    SDN1.JPG

     

    In order to create a transport order, switch to the report writer maintenance. Or   it would be also possible to download and upload the reports, but prefer to Create transport orders. 

    SAP Ref. IMG -> Project System -> Information System -> Costs/Revenues Information System -> Cost Element Analysis -> Custom Reports -> Maintain Libraries.

     

    SDN1.JPG

     

    You can also use it using transaction code GR22. Select Change Library Option.

     

    SDN1.JPG

     

    Now follow the steps shown in the screen shots.

    SDN1.JPG

    The report group with dependent objects has to be transferred.

    SDN1.JPG

    Then execute it and add it in a Transport Request.

     

    So, Now you have transaction code 7KVD Actual Cost Report available in your client.

     

     

    Regards,

    Sujeet Mishra

    ABAP Objects - I Want to Believe - Part 02

    $
    0
    0

    ABAP Objects is the Way Forward – I Want to Believe – Part Two

     

    http://scn.sap.com/community/abap/blog/2013/07/04/abap-objects--i-want-to-believe

     

    The above blog – first part of this series - can be summarised as follows:-

     

    ·         I want to prove that writing new programs in OO really is better than the “old” way

     

    ·         I have a real life project which allows me to do just that

     

    ·         I am going to try to document how I go on this step by step

     

    ·         The example will be silly, but based on the real project

     

    ·         I am using test driven development, so I am starting with the tests

     

    I got as far as writing one test, which does not even compile yet. The next steps are as follows:-

     

    ·         Try and create my unit tests properly

     

    ·         See if I can convince my colleagues that unit testing is a Good Thing

     

    ·         Develop the program with regular user feedback

     

    ·         See if anything I develop in this project can be re-used in subsequent projects

     

     

     

    I apologise I advance, this is far too long, as usual, and I go off topic all the time, also as usual.

     

     

     

    Why am I doing this in the first place?

     

     

     

    I am now stuffed full of new concepts from reading assorted OO programming books, and am only half way through Robert Martins “Clean Code”, so a nice big new programming project gives me ample chance to try and see if any of this can be applied in real SAP life.

     

     

     

    If I write blogs all through writing this monster application, then I am forced to explain what I am doing, and often if you try to explain what you are doing, it makes you think about what you are doing, and that in turn sometimes leads you to think “WHY am I doing that? I must be a madman”, and then a better way may suggest itself.

     

     

     

    If I publish my reasoning on the SCN then chances are a better programmer than me will read this and tell me where I am going wrong and point me in the right direction. Conversely if a newcomer reads this then they might get some helpful hints on how to things, and as I said even if I am wrong then the comments should hopefully correct the myriad mistakes I make.

     

     

     

    As anyone who has read any of my prior blogs will know, I am also going to continually wander off the subject and then slap myself round the face with a fish to get back on topic.

     

     

     

    So, off we go, let’s talk about UNIT TESTS.

     

     

     

    UNIT Tests

     

    2.01 Unit Tests.png                      

     

    Figure 2.1 Unit Tests

     

     

     

    It is time to talk about the scope of the unit tests. When I published the last blog, lots of people said you should not test private methods. If you look on the internet you can see a lot of debate about this with people very passionate about this, some say yes, some say no, though I get the feeling the consensus is “no”.

     

     

     

    The argument seems to be that if you test the public method, then if one of the underlying private methods breaks then that failure will propagate itself to the public method, so your test of the public method will then fail.

     

     

     

    That way you still know instantly if your change has broken anything, and then you can change the implementation of the public method (i.e. refactor it) as much as you want without having to change lots of low level tests. That logic sounds good I have to agree.

     

     

     

    I am not trying to give away too much about what I am doing in real life, but it is going to become obvious it is all to do with the SAP Variant Configuration module. In my example I am building a monster for Baron Frankenstein based on various desired monster attributes, in real life my application is going to be a bit of a monster also.

     

     

     

    I have one massive unit test, what I call a user acceptance test. This takes the desired characteristics and the output is a bill of materials from which to build the monster.

     

     

     

    The basic structure is one public method, which under the hood will call about a dozen private methods, each of which represents a square on a VISIO flowchart. Each “square” in turn will call about ten other private methods.

     

     

     

    A Finger of Fudge is Just Enough

     

     

     

    From reading the assorted literature about test driven development it seems there are three rules, and you are supposed to go around in a really small circle, a circle Robert Martin says should take only a few minutes.

     

     

     

    ·         No code can be written until you have a failing Unit Test.

     

    ·         Only write enough of the Unit Test to fail.

     

    ·         Write just enough code to make the Unit Test pass.

     

     

     

    OK, so I have a failing unit test, my very high level monster making user acceptance test. I know the inputs and expected outputs.

     

     

     

    I need to actually define the implementation of the class under test and the main method which is being tested. I can create an empty implementation of this main method, and then in my test class I have a test method which sets up the inputs (GIVEN) calls the main method of the class under test with the correct signature (WHEN) and then does some assertions to make sure the output is correct (THEN).

     

     

     

    Everything now compiles, I can get as far as doing the TEST -> UNIT_TEST from the ABAP editor, and get a screen showing me a red light because all my assertions fail. I have now finished the section part of the TDD cycle, I have written JUST ENOUGH for the test to fail.

     

     

     

    I now need to write just enough production code to make the test pass. Hang on, that is ALL OF IT, all one hundred odd private methods. Somehow I don't think I am going to be able to do this all in one go, and not in under a minute.

     

     

     

    The only way I am going to be able to do this in a way that attempts to follow those TDD rules is to start with tests for the smaller methods – which are all private – and work my way up.

     

     

     

    As I say repeatedly I have a big VISIO process diagram, and for each square I have an equivalent part of a spreadsheet, and I know what values go in and what values are supposed to come out. I will start doing a unit test for each square, and after creating each test I will write the production code. “That’s the way you do it!” as Mr.Punch would say. He was a big fan of test driven development, when he wasn't stealing sausages.

     

     

     

    ABAP Unit – Sharing is Caring

     

     

     

    The other day in my company we had our annual programmers get together where we take a day away from sorting out the users problems and focus on technical things. Ten years ago when we started this we mainly focused on what SAP would describe as “customer program optimisation” where you look at all your Z programs for performance problems.

     

     

     

    As the years go by our relentless focus on this matter means this is no longer a problem in the slightest, so now I have moved the focus to looking at the myriad new technologies available to us with the advent of ECC 6.0 and similar.

     

     

     

    Since I had done quite a few programs with unit tests in them by this stage I thought I would explain to my colleagues what this was all about, as I knew for a fact I was the only one using this tool (ABAP Unit).

     

     

     

    I had been so impressed by the – to me – obvious benefits of an automated testing framework that I thought this would sell itself. However this was the reaction:-

     

    2.02 Unit Test Reaction.png

     

    Figure 2.2. Unit Test Reaction

     

     

     

    I had, in my audience:-

     

    ·         My boss

     

    ·         A BASIS guy, coming up to retirement age, who nonetheless I not happy unless we have the absolute latest version of every single SAP product

     

    ·         A programmer who always uses OO programming for everything and is much further down the path than I am

     

    ·         A programmer who started off using punch cards, and would rather set himself on fire than use object orientated programming, and has called for it to be banned

     

    ·         A programmer who is desperate to learn about all new SAP things, who got confused when I talked about the difference between a static and instance method, and the gung-ho OO programmer then explained that difference

     

    ·         A programmer who might have walked out of the description of ABAP programmers in Graham Robinsons blog “a call to arms”

     

     

     

    To summarise, quite a mixed bag, all of whom had at least ten years SAP experience. None had heard of ABAP unit.

     

     

     

    I like to think I can explain something well when I put my mind to it, and I showed various programs I had written with unit tests, and wrote some lovely pretty pictures on the whiteboard like the consultants do. My boss said I had explained it well, so I thought this was going swimmingly.

     

     

     

    Then the questions started. No-one expects the Spanish Inquisition!

     

     

     

    So…..

     

    ·         No, this test driven development / unit test business wasn’t something I had invented myself

     

    ·         No, this wasn’t something I had got off the internet like ABAP2XLS

     

    ·         Yes, it’s actually a part of standard SAP, a part of SE80

     

    ·         Yes, it does mean you write twice as much code, takes twice as long to write something

     

     

     

    I thought I could get around that last one, by doing another consultant trick and drawing a pie chart. Consultants can convince anybody of anything my drawing a pie hart or dividing a white board into four and writing the option they want into the top right hand square.

     

    2.03 Consultant Diagram 1.png

     

    Figure 2.3 Consultant Diagram 1

     

     

     

    I have seen that technique used millions of times, it usually works, it didn’t work for me - so I tried a pie chart. This time I actually had a bit of logic on my side.

     

    2.04 Consultant Digram 2.04.png

     

    Figure 2.4 Consultant Diagram 2

     

    The point I tried to make is that since 95% of the effort expended on a program is on maintenance, then doubling the time spent on development does not matter that much in the grand scheme of things, if it makes the other 95% of the life cycle faster and more stable.

     

     

     

    I am so lucky where I work. My boss has an open mind. Initially the idea that most of the effort on a program was maintenance came like a bolt out of the blue to him, but when he asked the other programmers if this could possibly be true, and they all nodded, he got it straight away.

     

     

     

    However he raised the obvious point that how can you convince a business manager that something they want right now will take twice as long to delivery initially, because in the long run they will be better off. Most human beings do not care at all about the long run, just what they can get right now, right this second.

     

     

     

    There was a cartoon where Charlie Brown had to go away for a few days and he left Snoopy with three bowls of dog food, and told him not to eat them all at once, but one per day, otherwise he would go hungry. Snoopy ate the first one, and then got more and more agitated and the dive on and ate the other two, and then led back and said “I’m glad I did that – what if tomorrow never came?”

     

     

     

    So, I don’t think management are going to go for this in a big way, and I am fairly certain none of my colleagues are going to start using unit tests.

     

     

     

    However, my boss asked me “have you any proof that this works?”.I replied that I had stuffed a procedural program full of unit tests, and once the program was in production the requesting manager had never once complained, and for the last ten years he had ALWAYS complained that what we wrote was never good enough and always came back half a billion times with corrections to be made.

     

     

     

    Maybe if I make a go off this, it might encourage others….

     

     

     

    Waterfall Am I

     

     

     

    Talking about end users, I have a highly nervous user base, some of whom have grave doubts whether this project (which I am working on and is the subject of this blog, not that you can tell this as I keep diving off down rabbit holes) can be achieved at all. The traditional method of dealing with an enormously complicated SAP project like this this was to take the original user requirements, go and lock yourself in a room for two years to build something, and then give the finished product to the user who wrote the original requirements and be really shocked when they say “this is not what I wanted at all” and then you have to tell them ‘sorry this is what you’re getting, the projects run out of money, we’re doing a new one next week”.

     

     

     

    This is the “waterfall” method and it is how most of the major SAP implementations I have observed have worked. A few years either side of the year 2000 a lot of consulting companies made all the money in the world using this method. The secret to their success was they could hand over the finished product and then run out the door.

     

    2.05 Waterfall Projects.png

     

    Figure 2.5 Waterfall Projects

     

     

     

    If you look on the internet you would think that this is a thing of the past – nowadays everyone uses extreme programming / agile / scrum” type methodologies in the same way all ABAP programmers use OO programming.

     

     

     

    Just two weeks ago a colleague of mine from America asked me what in the world “scrum” meant in an IT context, and I gave a simplified explanation which revolved around showing a working prototype to the users every two weeks which just the functions you have built thus far, as opposed to showing them everything after two years.

     

     

     

    He said that sounded great but it “probably wouldn’t work on a massive SAP project”. “Plus Ca Change” as the French say. I wonder how many “waterfall” projects are being done on SAP systems worldwide at this very instant. Probably enough to make the authors of the “agile manifesto” wonder why they bothered.

     

     

     

    The End User is Nigh

     

     

     

    I was dancing around the room with joy today when in the weekly ABAP meeting one of my colleagues said that Michael Bubble was really happy with my colleague’s new SAP custom development. I thought that was great that he could take time off singing to test our programs, but it turns out this was a different Michael Bubble, this one was an end user.

     

     

     

    It turns out the decision had been made to go live with this development but only let one or two users have access to it, and then they would come back with a non-stop stream of bug fixes and enhancements until the development was fit for a human to use. Then everyone else could have it. You might think one or two users is not enough of a broad base to be representative, but it is a hell of a lot better than zero users looking at it before it went live for the whole company, as appears to be generally the case according to anecdotal evidence from all over the world.

     

     

     

    The method above is still a waterfall pig with some agile lipstick on, but how much better would it be to be able to show the end users something every two weeks, or more likely to be able to sow the constant stream of visitors from assorted areas of the business what we have so far, as and when they arrive. I am going to be allowed to do this, it helps that I know a load of the end users, having been in the company for a long time.

     

     

     

    As I am going to break down the development into bite size chunks, one VISIO square at a time, it is likely that each week I will have one or two squares each week finished. However a unit test is a bit of an esoteric thing to show somebody, especially given that if the test passes you see nothing at all except a blue line at the bottom of the screen. Strangely enough, that does not blow the socks off the end users and make them say “my god I am impressed, all my worries have melted away”.

     

     

     

    Simulate, late, breakfast show

     

     

     

    My idea was to have an executable program that showed the sample input data on a selection-screen, and then call all squares thus far written one after another and use the application log to tell the user in exquisite detail what is going on, so they can see the logic for themselves and if they don’t like it, start arguing with the guy who wrote the specification, literally over a year before it is likely to reach its final state and be foisted upon them.

     

     

     

    Here is a great SDN article about using the application log to display complicated information:-

     

     

     

    http://wiki.sdn.sap.com/wiki/display/profile/2007/07/09/Message+Handling+-+Finding+the+Needle+in+the+Haystack

     

     

     

    I could not find a practical application for this until now, this is a perfect fit for what I want.

     

     

     

    Break Down and Cry

     

     

     

    I am going to break down my monster making process as follows:-

     

    ·         Each square is a “main process” – it will have it’s own unit test

     

    ·         That square is usually a series of sub-processes. If that process is not utterly basic (like adding two values together) than that gets its own method

     

    ·         Each sub process is a series of process steps, in which you either get some data from the database, or do some sort of calculation on that data. Since I am just working towards building a BOM based on a set of characteristics those are the only two things I have to worry about.

     

     

     

    My simulator program will just call all the squares thus far written one after the other and then display an application log in a nice tree format, so a user can drill into the bits they are interested in.

     

     

     

    How you break up methods seems to be the subject of a fierce debate in the OO world, with people burning each other at the stake for heresy if they have an opposing view on this subject. What is this argument?

     

     

     

    You’ve got that ONE THING

     

     

     

    Robert C.Martin says that a method should do one thing only and do it well. In procedural programming it is not uncommon to see a FORM routine ask the user something, then go off to the database and fill up an internal table, and then loop over that table doing assorted things to the data. If you are REALLY lucky the call to the ALV (or WRITE statements if you are where I used to work) is in another FORM routine.

     

     

     

    How often have you seen this:-

     

     

     

    START-OF-SELECTION.

     

     

     

    PERFORM GET_AND_TRANSFORM_DATA.

     

     

     

    END-OF-SELECTION.

     

     

     

    PERFORM DISPLAY_DATA.

     

     

     

    It’s a good job that virtually nobody understood what END-OF-SELECTION really meant, otherwise instead of two FORMS there would be just the one (in case you are wondering END-OF-SELECTION is only meaningful if you are using a logical database in your program).

     

     

     

    I’ve noted before that many people have not even made the leap to procedural programming yet; they still write everything in one big list after START-OF-SELECTION. That is the opposite of what Robert Martin is looking for.

     

     

     

    He once wrote a blog called “extract till you drop” where he took a Java program and broke it down into smaller and smaller chunks. That got a load of arguments from both sides as to whether this is a good thing or not.

     

     

     

    The ABAP programming guidelines book from SAP Press says “modularise don’t atomise: and when the following blog was published:-

     

     

     

    http://scn.sap.com/community/abap/blog/2013/07/09/why-should-we-write-clean-code

     

     

     

    you will note the very first comment says that “light weight” classes i.e. classes or methods that don’t do very much, are more suited for Java than for ABAP.

     

     

     

    Well I don’t know the answer, I am still a beginner, I am going to split things up in a way that seems right. Everything is going to be a local class / method inside one Z program to start off with, hopefully the more I get into this the more obvious the correct way to split things will become.

     

     

     

    It has been said that is one of the benefits of test driven development – it forces you into having the correct structure. We shall see….

     

     

     

    Last of the Cohesions

     

     

     

    I find that often when I read the reams of material available about how to write object orientated programming you get seemingly contradictory instructions. Whilst that is frustrating on the face of it, the good thing is it forces you to think about both ways to do something and make your own mind up. It is better to have two options than to have no clue at all as to what to do.

     

     

     

    As an example, I mentioned earlier the idea of “high cohesion” which says that if a variable gets used in all the methods of a class then you should make it a “member” variable (sort of like a global variable but only within one instance of a class) as opposed to constantly passing it backwards and forward in the signatures of all the methods. This would make the signature simpler.

     

     

     

    My gut feeling however was to stick with the big signature as it made it obvious exactly what a given method needed to do its work, and what values it defined or changed.

     

     

     

    There is a saying in some places in the world that if you don’t like the weather just wait a few hours until it changes. It seems to be like that with the OO books I read, if I decide to do something then sooner or later I come across an argument which justifies my opinion.

     

    In this case we have the idea of “temporal coupling”. This says that it is a Bad Thing if you have two methods, and if you change the order in which they are called then the program behaviour changes unexpectedly in a way that is difficult to debug.

     

     

     

    I am making no secret that the area I am working in at the moment is variant configuration, and I have a series of methods which correspond to VISIO squares and the point is that it is highly likely the flow chart will change and then the squares will get called in a different order. They say that a lot of the art of programming I making a guess as to what my change in the future so you can prepare for it, and to my mind the order of the squares in the flowchart changing is a virtual certainty. In a previous project I am aware of a similar flow diagram changed twenty seven times before everyone was happy with it.

     

     

     

    In conclusion, I think I am going to stick with having big signatures in my methods until such time as I find a reason to reverse my position even stronger than the argument that made me choose that position. This might well happen, that is what is so good about learning new things, you can’t be like the sheep described by the Housemartins– “they never questioned anything, they never disagreed, sometimes I think they must have wool in their ears”.

     

     

     

    In unit tests however, I have almost everything as member variables, so I can make the code look like English sentences with virtually no signatures at all. Those methods always run in the same order GIVEN – WHEN – THEN so there is much less danger of “temporal coupling” errors.

     

     

     

    The Revenge of Domain Specific Languages

     

    2.06 Domain Specific.png

     

    Figure 2.6 Domain Specific Language

     

     

     

    Here’s a little blog I wrote, you might want to sing it note for note:-

     

     

     

    http://scn.sap.com/community/abap/blog/2013/01/08/domain-specific-language-in-abap

     

     

     

    The idea of a “Domain Specific Language” is that a business user could look at your code and understand what was going on at first glance, because everything was couched in business terms.

     

     

     

    I was going all out to try and achieve this, and had extracted methods for each line in the spreadsheet so that the sub process methods consisted of lines like DO_SUCH_AND_SUCH( ).

     

     

     

    I copied the names from his spreadsheet. Then when he asked to look at the code I thought he was going to be pleasantly surprised but he looked and said “I don’t understand a word of this”.

     

     

     

    That is because I had still kept some ABAP type words in the code e.g. INITIAL which no-one would understand, and also because I had used the same abbreviations as he had in his spreadsheet. I should really have expanded them back out again to their full English words, we have 30 characters in ABAP - I like to use as many as I can.

     

     

     

    So, I went back and tried again. It can be done – here is a great blog on the use of macros…

     

     

     

    http://scn.sap.com/community/abap/blog/2012/10/28/use-macros-use-them-wisely

     

     

     

    and with a mixture of them and small methods named like English phrases, and then you can have code that a business user can read.

     

     

     

    You might think that is a pointless goal, but I have seen my fair share of business analysts debugging, and one (in Germany) even told me “I can follow whatever you write as long as it is not that object orientated ****”.

     

     

     

    Just as an acid test, if the business user who wrote the specification could read your code, and understand it, and say “yes, that it just what I meant” that would be a good thing, would it not?

     

     

     

    I am sure some people may say “I don’t want users being able to understand my code, if they understand it, then I am out of a job, that is why it is called CODE so no-one can understand it!”.

     

     

     

    Hoots Mon! There is Re-Use, Loose, about this Hoose!

     

    2.07 Hoots Mon.png

     

    Figure 2.7 – da dadadada, da dadadadadaetc

     

     

     

    I keep plugging the SAP Press book by Igor Barbaric called “Design Patterns in Object Orientated ABAP” because that is what got me going into this area in the first place. He said that the first time he did a major application in an OO fashion he ended up with a whole bunch of components that could be re-used in subsequent projects.

     

     

     

    A cynic would say you could do that with function modules, but I am trying to keep an open mind. Also, this is rather like the Moon Walking Bear – you don’t look for it unless you know it could be there. I have to say that even after a short while I am finding things that could be potentially split off into their own Z classes and then re-used elsewhere.

     

     

     

    Since OO design, and unit testing in particular, forces you into the “separation of concerns” where different things are in their own classes, it soon becomes apparent that some classes are clearly specific to the application at hand whereas others are far more generic.

     

     

     

    I never knew there was so much in it

     

     

     

    Naturally if I can find an existing artifact to do want I want I can re-use it. However, one of the “problems” of SAP is that if you have a programming problem to solve, it is almost certain someone has been there and done that and got the t-shirt, and that there is a standard class / method / function module that already does what you want.

     

     

     

    The problem is finding it.

     

     

     

    There are more function modules in the standard SAP system than there are stars in the sky, and more recently a lot of classes / methods as well, though it will take time for them to catch up numerically due to the vast amount of time when OO things were not available in ABAP.

     

     

     

    It is my horrible suspicion that hundreds if not thousands of ABAP programmers spend their day writing functions that are exact copies of things that already exists in the standard system, or creating user exits which achieve functionality which either exists in enhancement pack business functions which have not been activated in their system, or even for things that can be achieved by customising.

     

     

     

    Even worse I think the same thing happens within SAP itself. When I have searched for standard function modules to achieve XYZ I usually get no results or five or six functions doing exactly the same thing.

     

     

     

    When I was reading the book “Thinking in Java”  http://en.wikipedia.org/wiki/Bruce_Eckelsaid the if you did not know the name of a method in the Java GUI “swing” framework you could guess what it was called because the naming conventions were so strongly followed. That does not seem to be case in SAP, if anything there is an utter lack of naming conventions in standard SAP repository objects.

     

     

     

    Even the BAPI naming is all over the place, one of the four principals for BAPIS was supposed to be consistent naming, along with meaningful documentation, he hehe.

     

     

     

    You end up with names containing assorted naming conventions for creating a new business object of some sort.

     

     

     

    With other functions, even if the function at hand is the sort of thing that is re-usable in many contexts, the SAP programmer names it after the project they are currently working on, so you get class names like JAPANESE_MICE_RACING_MATHS_FUNCTIONS which contain many useful mathematical functions which could be used in many applications which are unrelated to mice, or racing, or Japan.

     

     

     

    I don’t like to call a function module with a name like that, as it would confuse the hell out of any casual reader of the code.

     

     

     

    In the end very often we create our own function module or class, and then later on we might accidentally stumble on an identical one in standard SAP.

     

     

     

    Going back to my example, in the spreadsheet was the EXCEL function MAX. I thought there must be one in standard SAP that does the same thing – as indeed there is – but I couldn’t find it for love nor money. A load of Google searching did not help, I searched for function modules and found BELGIAN_TRUFFLE_GROWERS_MAX_VALUE which was almost OK but had a few odd mandatory import parameters.

     

     

     

    In the end I wrote my own method to do this, and then every so often I did another Google search using different parameters – the term “BUILT IN FUNCTION” did not help much for example – and in the end I discovered the standard function is NMAX.

     

     

     

    You are probably thinking “oh my god, what a whinger and complainer he is, always talking about how hard things are to do in SAP”.

     

    Well, I’ll tell you, I never wanted to be an ABAP programmer in the first place!

     

    I...  I wanted to be... A LUMBERJACK!

     

    (piano vamp)

     

    Leaping from tree to tree!  As they float down the mighty rivers of British Columbia!

    With my best girl by my side!
    The Larch!
    The Pine! 
    The Giant Redwood tree! 
    The Sequoia! 
    The Little Whopping Rule Tree! 
    We'd Sing!  Sing!  Sing! 

     

     

     

    I’m a Lumberjack and I’m OK

     

     

     

    As mentioned earlier, when it comes to logging I want to make re-use of CL_RECA_MESSAGE_LIST to handle showing error messages to the user and the application log in general. Great as this is, I am never happy, so naturally I sub classed this and added assorted things of my own.

     

     

     

    For example, sometimes I just want to add a free text message and do not want to have to clutter up the code passing in the message number and type and what have you. This is like the ABAP statement MESSAGE ‘something’ TYPE ‘I’. So I redefine the ADD method and let it except just a text string and the message type and then pass in suitable generic values for the message class and number.

     

     

     

    This is just an example, and probably not a very good one, the point is every time I feel the lack of some sort of function to do with logging I will add it to be Z message handling class, and this is bound to be re-usable in future applications. OO people keep on and on about how you will end up with a library of re-usable components you can share with your colleagues – or the SCN in general – and maybe they are right. That is after all the purpose of the code exchange, with ABAP2XLS being the best example.

     

     

     

    Local Hero

     

     

     

    That logging functionality will clearly be a Z class as I can be virtually certain myself or someone else will make use of it in the future in another application. However generally, most of the code in a given application will be specific to the application itself.

     

     

     

    So the question is – and this will be the subject of the next blog – do you do your prototype mainly as a Z class, or as a local class, and what are the drawbacks and advantages of both approaches?

     

     

     

    Cheersy Cheers

     

     

     

    Paul

     

     

     

    2.08 Until Next Time.png

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    Embedding Flash content in SAP GUI

    $
    0
    0

    Embedding Flash content in SAP GUI

     

     

    We as ABAP Developers are always interested in making SAP more and more interesting as well as take things to the extreme. In this post I will try to embed a Flash animation in the SAP GUI.

    Embedding Flash animations, unlike images, cannot be done by uploading content in SWO0 and then using a function module to fetch the content. Instead, the content needs to be displayed in a container which will somehow support flash content. We know that flash content is easily displayed in web browsers and thus can be displayed in SAP GUI as well if we are able to create a container for HTML content. There is a simple report available in SAP which helps us create a container for HTML in SAP GUI. You can go to SE38 or SE80 to check the report SAPHTML_DEMO1. This is a good example of cl_gui_html_viewer.

    The report is quite simple to understand for an ABAPer and we can copy the report and screens and then customize the container using screen painter.

    Given below is an example on a demo I made for test purposes.

     

    gif.gif

    (link: http://cdn.makeagif.com/media/8-01-2013/Cjh2Qa.gif)


    Here, instead of linking the container's HTML content to a web page, I linked it to the swf object in a local drive. However, the flash object can be placed in

    banner.jpg

    a web server or an FTP server so that the content is available to all users. You may also upload the swf file in the MIME repository of a BSP application from where you can directly access the file.

     

     

    The benefits of embedding a flash animation in SAP are many. For example, the customer might be intrigued by the idea that there exists a dynamic content in a particular SAP transaction where the user can view a demo or presentation. Interactive Flash animations can also serve many more purposes and extends the capabilities of SAP.

     

    I know that you would like to try this for yourself, so check the above mentioned demo report or the code below. To get the report working you need to draw a custom container named 'HTML' in screen 100 of the report and a use the menu painter to enable the back button.

     

     

     

     

     

     

     

     

     


     

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

    *& Report  ZTEST_GAURAB_01

    *&

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

    *&

    *&

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

     

     

    REPORT ztest_gaurab_01 MESSAGE-ID z1.

     

     

    DATA: html_control TYPE REF TO cl_gui_html_viewer,

          my_container TYPE REF TO cl_gui_custom_container,

          fcode LIKE sy-ucomm,

          edurl(2048),

          alignment TYPE i.

     

     

    SET SCREEN 100.

     

     

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

    *&      Module  STATUS_0100  OUTPUT

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

    MODULE status_0100 OUTPUT.

      SET PF-STATUS 'TESTHTM1'.

      SET TITLEBAR '001'.

     

     

      IF my_container IS INITIAL.

     

     

        CREATE OBJECT my_container

            EXPORTING

                container_name = 'HTML'

            EXCEPTIONS

                others = 1.

        CASE sy-subrc.

          WHEN 0.

    *

          WHEN OTHERS.

            RAISE cntl_error.

        ENDCASE.

      ENDIF.

     

     

      IF html_control IS INITIAL.

        CREATE OBJECT html_control

             EXPORTING

                  parent    = my_container.

        IF sy-subrc NE 0.

          RAISE cntl_error.

        ENDIF.

     

     

        PERFORM load_home_page.

      ENDIF.

    ENDMODULE.                             " STATUS_0100  OUTPUT

     

     

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

    *&      Module  USER_COMMAND_0100  INPUT

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

    MODULE user_command_0100 INPUT.

     

     

      CASE fcode.

        WHEN 'BACK'.

          IF NOT html_control IS INITIAL.

            CALL METHOD html_control->free.

            FREE html_control.

          ENDIF.

          IF NOT my_container IS INITIAL.

            CALL METHOD my_container->free

              EXCEPTIONS

                OTHERS = 1.

            IF sy-subrc <> 0.

    *         MESSAGE E002 WITH F_RETURN.

            ENDIF.

            FREE my_container.

          ENDIF.

     

     

          LEAVE PROGRAM.

     

     

        WHEN OTHERS.

          CALL METHOD cl_gui_cfw=>dispatch.

     

     

      ENDCASE.

      CLEAR fcode.

    ENDMODULE.                             " USER_COMMAND_0100  INPUT

     

     

    * Homepage form

    FORM load_home_page.

      DATA: doc_url(80).

     

     

        doc_url = 'U:\Desktop\banner.swf'.

        CALL METHOD html_control->show_url

             EXPORTING

                  url       = doc_url.

     

     

    ENDFORM.                               " LOAD_HOME_PAGE



    Trigger ALV data_change event manual

    $
    0
    0

    As we know, when we changed something in the alv grid, event data_changed will be triggered, and we can do some custom check.

    but do you face this situation, after you changed this alv and push on some user command, like 'SAVE', the data_changed event will not be triggered again, because no cell is changed in alv grid, but actually, you want to trigger it and do something you want.

    below i will give you 1 solution to trigger it by compulsion.

     

    in PAI, use method IF_CACHED_PROP~SET_PROP of class CL_GUI_ALV_GRID to set property 'GridModified' as modified, then call CHECK_CHANGED_DATA of CL_GUI_ALV_GRID, data_changed event will be triggered.

     

    1.add code in PAI

    图像 001.png

    2.Run your program and update data, then save.

    图像 007.png

     

    图像 010.png

    3.Push 'SAVE', event will be triggered.

    图像 003.png

    图像 004.png

     

    This is my first time to write blog, please give your comment if you also have some experience on this topic. Thanks.

    Pricing Routines Coding in RV64A*

    $
    0
    0

    Well Friends,

     

    I have written pricing routines quite some times and have been able to deliver things which were simpler of-course with quite ease.

     

    In my current assignment I faced an issue which was quite similar to my knowledge but I was unable to re-collect the solution or even the root cause for the same.

     

    Problem :

     

    The pricing routine written to calculate the rebate value with respect to some quantity base calculation with lot of if and but's not giving appropriate output.

     

    Analysis :

     

    Well, to my surprise when I do it outside the routine passing the same parameters it does not seems to work.

     

    Closer analysis dictates SAP has not yet made the "Fixed Point Arithmetic" flag for the main program and is still using a very old methodology to convert values in appropriate decimals.

     

    If outside the program I set the flag in the attributes of the program and run it, it works just as I want it to.

     

    Key Issue :

     

    Don't want to take the key "Fixed Point Arithmetic" flag for the main program

     

    Reasons:

     

    1. Don't want to modify the main program

    2. In doing so may be... just may be I could affect a lot of things which could result in a bigger disaster.

     

    Solution and Learnings :

     

    Well, I have learned if I want to d write routines in my future projects:

     

    I will create a new Function Group / Class and "Fixed Point Arithmetic" flag for the main program

     

    Create Function modules / methods with passing values as parameters and returning parameters with the value needed.

     

    Embed all calculations inside this FM to have appropriate calculations.

    HOW I DO IT: Purpose and the Creation of a "Deletion Transport"

    $
    0
    0

    Problem Description

     

    When we have a Package which contains a "lot" of sub objects and we want to delete entire Package or bunch of objects under the package.

     

    The problems we might face are:

     

          A) Manual Deletion of objects requires lot of time and we need to delete all the sub objects, release the transport and then delete the Package .

     

         B) Deletion of package in a non development system becomes a problem as we need to delete them in the development system manually

         and  then move the transport across the landscape. And if we want to delete only in a Q system requires complex strategy.

     

    So these problems can be simplified if we have a Deletion transport which would just delete the objects where we want.

     

    Definition of a Deletion Transport:

     

    Basically the definition of a deletion transport in our context is a transport in which all the objects are listed and marked for deletion & When we import this transport into any system the listed objects are deleted.

     

    Situations:

     

    When we talk about situations , it could be of a need when we are implementing a short term 3rd party solutions ( e.g smartShift's smartUpgrade tool) , System Maintenance or a POC project etc.

     

    Lets say

     

    1) You have done a POC in a system and at the end you want to delete all those objects ( say from an IDES system ) .

     

    2) You want to delete the objects in a quality system for some reason, but you dont want these objects to be deleted in the development system .

     

    3) You are doing a maintenance of the development system and want to clean up the list of test objects.

     

    Solution :

     

    There is a field OBJFUNC in E071 table ( Object list of a Transport ). When OBJFUNC is 'D' the activity of the transport on this object would be "Deletion".

     

    But mere setting of this flag in the transport data wont convert a transport into a deletion transport.  The D indicator works only when the objects are not present in the system ( See below screen shot and short text of the field ) .

     

    e071-D.png

     

    So we need a dummy system where our objects are not present and we create a transport in that system with Deletion indicator . This is explained in detail in further section.

     

    What you need :

     

    1) First thing you need is "The problem" itself, Only when you really have this problem then this post makes some sense to you.

     

    2) A Dummy system where none of these to-be-deleted-objects  exist. ( Say IDES or any Other development system than your main development system )

     

    3) Some basis authorization who can help you in Create / Release / Download the K , R files ( In case you dont have the authorization ) .

     

    Steps :

     

    A) From the main system,( Where the objects actually exist) Download the object header data from TADIR into a tab delimited text file   , The first 3 fields are the only required data ( i.e The fields PGMID , OBJECT , OBJ_NAME of the TADIR table ) .

     

    Excel-Data.png

     

    We use this data to create the  TADIR entries in the dummy system. A TADIR entry is mandatory to add the object to a transport.

     

    Caution: Review your object list once it is downloaded. Make sure only those objects which you wanted to delete are present

     

    B) Create the below report program in the Dummy System where we Generate the transport.

     

    Program specification is as below:

     

    B1)  Create a Selection screen parameter P_FILE to read the object list file.

           Create a Selection screen parameter P_TRKORR , for the "Deletion Transport"

           Create a Selection screen parameter P_DEVC for entering a Z dummy devclass

     

     

    Selection Screen.png

    B2) Read the file into an internal table IT_TADIR

     

    B3) Process the IT_TADIR to 1) Create a Dummy entry into TADIR 2) Create an entry into the transport

     

    B4) Sample Code snippet

     

         DATA: W_TABIX  TYPE SY-TABIX.

         CLEAR W_TABIX .

     

         LOOP AT T_TADIR INTO W_TADIR.

     

                W_TABIX = W_TABIX + 1.

     

         *Step1 Create a Dummy Entry into TADIR ,

                W_TADIR-DEVCLASS = P_DEVC.   " Any dummy development class other than $TMP

                MODIFY TADIR FROM W_TADIR.

     

         *Step2 Create an entry into the transport object list , E071

     

                W_E071-OBJFUNC = 'D'.                 " Indicates Deletion

                W_E071-TRKORR = P_TRKORR.     " The input deletion transport

                W_E071-AS4POS = W_TABIX .        "Sequence of the object within the transport

     

                MOVE-CORRESPONDING W_TADIR TO W_E071. " Header data of the object

                MODIFY E071 FROM W_E071.         " Update the standard table E071 for transport

     

           ENDLOOP.

     

    C) Once the program is ready, then Create a Workbench transport with a Target System ( Can be a Virtual System, just to get the transport files ) and a Dummy Development Class.

     

    Execute the program in the dummy system with mandatory input as object list file , deletion transport , and the dummy devclass.

    Selection Screen.png

     

    After the execution is complete, The transport will be loaded with the objects with Deletion Indiactor and the object list looks like below :

    Deletion TR entries in SE01.png

     

    D) Release the transport and Download the K (\usr\sap\trans\cofiles\ ) and R (\usr\sap\trans\data\ ) files of the transport.

     

     

    E) Your "Terminator" transport is Ready!!!  Import the deletion transport into the required system where you wanted those objects to be deleted.

     

    Sample Diagram of the Steps and Process

     

    process.png

     

    Note:

     

    The development class you use in the Dummy system doesn't have any affect . And it need not be same as the original development class in which the real objects are in.

     

    The deletion transport should have a target assigned so that it generates the K and R files when it is released.

     

    !caution! Make sure you are Importing this transport into "Required" systems and remove it in the import Q once it is imported.!!

    Share and share alike

    $
    0
    0

    invest_in_sharing.jpgSharing your toys

    When you grew up I am sure that you were taught to share your toys with your siblings and your friends. It is certainly a value to that I am keen to instil into my children.

     

    When we share we get access to what we could not have done ourselves. It broadens our experience and gives us exposure to things that we might not have come across ourselves.

     

    This goes for algorithms and implementation as well as the latest kitteh movie you found on youtube.

     

    Being exposed to a varied approaches to development can only improve our abilities as coders. A great way to be exposed to other code is to read books with code samples that are annotated and explained or blogs or open source software.

     

    Github has become of late the goto repository for such projects. It is a great place to discover and learn and also contribute.

     

    Having said this it is sad to hear and read about SAP's approach to such sharing. In response to community enquiry SAP promoted Codexchange based on the SVN source control system and available to developers working on a specially licenced version of the ABAP Netweaver Stack. Codexchange has an uncertain future - it seems to be stuck and not moving forward. The answer to such a problem is simple - use github.

     

    What is the problem with sharing our code on Github? How is it different to adding source code to a blog here on SCN or on another technical site or even in a book?

     

    Github lowers barriers to entry and because all the hip kids hang out there it may even encourage people to get with the grey haired abap gang.

     

    To innovate you need to change and although the ABAP language is changing and introducing new features SAP's approach to sharing is not.

     

    Thoughts?

     

    Thanks to Toban Black for the image


    Tips from an ABAP Instructor

    $
    0
    0

    Calling all ABAPpers!

     

    Veteran SAP Education instructor Peter Walters has just published a series of blogs covering what's new and noteworthy in ABAP, and which courses you might want to take to beef up your skills in those areas:

     

     

    And check out our growing list of blogs from SAP Education’s Instructors, covering an ever-widening range of topics – from SAP HANA to SAP Solution Manager and more.

     

    Happy reading!

    Sarah

    Viewing all 943 articles
    Browse latest View live


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