1 6 7 8 9 10 52 Previous Next

ABAP Development

772 Posts

What has been missing so far

In one of my last blog posts, I showed you how mock objects can be easily created. I also showed you how mock object's method calls can be counted and how verifications can be implemented, to ensure that a mocked object's method has been called.

Up to now, it was not possible to check, which parameters have been passed.

 

Ensure, that a mocked object has been called with certain parameters

In the current build, I also included the possibility to verify the parameters that have been passed to a mock object's method.

This is how it works:

First of all, you need to keep track of the mocker object of type ZIF_MOCKA_MOCKER (which means, please do not throw it away ;-) )

By utilizing this mocker object, you can get data about your mocked methods, such as if it has been called with certain parameters or not:

 

DATA lv_has_been_called TYPE abap_bool.
lv_has_been_called = lo_mocker->method( 'get_delay' )->has_been_called_with(
     i_p1             = 'LH'
     i_p2             = '300'
     i_p3             = sy-datlo
).

For further details, please see report ZMOCKA_DEMO that is shipped with the current release.

 

Limitations

Only IMPORTING parameters are supported so far, this means no CHANGING parameters can be verified yet.

It's getting repetitive

It's getting repetitive. Let me say it again. It's getting repetitive...

 

I keep rejecting the same kinds of contributions again and again - often from the same people, for the same reason.

 

It's getting repetitive.

 

So, as it's getting repetitive, I thought I'd mention here my (un)favourite list.

 

1) SMS type spelling

Do u no wht I mean?

 

This is supposed to be a site for professionals. Imagine your writing to your next boss. Would you use such a lackadaisical form of communication? Thought not. The fact is though, if you're applying for a job, your prospective employer might well have a quick scan to see of your contributions on SCN. Do you really want to make a bad impression?

 

There's another side as well. English is not the mother tongue of many contributors here. If you start using SMS (that's "Short Message Service") type abbreviations, then you make it really hard for those people to understand what you're whittering on about.

 

2) Posting links

I hate it when I see a post that just says

"link" - hope it helps.

 

Or

link

link

link

Try these.

 

At best all it shows is that the original poster could have searched for themselves. At worst, it's a really lazy answer. "Hope it works. Not sure, I didn't really look too closely, but I put some keywords into AFSE (A Famous Search Engine) and these were the first results. Maybe I'll be lucky and they're right and I'll get some points".

 

3) Use FOR ALL ENTRIES instead of INNER JOIN

 

How can I put this succinctly?

 

No. No.

No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No No

 

That's it. No more discussion.

 

4) Binary search

 

Look. We all know (or should know) that if we're reading a STANDARD table then we might want to sort it and read it using BINARY SEARCH. But come on. Fifteen years ago an alternative became available - HASHED and SORTED tables.

 

Yet I keep seeing the same tired old responses "Use BINARY SEARCH with SORT".

 

No - use a properly designed, properly typed table, and you won't have to. They've only been around for fifteen years - why do people keep promoting this old technology! Or is half the world still on 31H?

5) SO_NEW_DOCUMENT_SEND_API1

 

Another very popular bit of ABAP. But again, it was replaced years ago with the CL_BCS set of classes. They're so much more powerful and so much more easy to use, if you'll put in some effort. And there's so many examples...

 

Here's a great blog about these classes, from Eddy De Clercq - Unknown thus unloved? Again, thanks to Jelena Perfiljeva for the reminder.

 

6) Spec dumping

 

Thanks to Jelena Perfiljeva for reminding about this one. Spec dumping. That's when someone, often a newbie (which makes you wonder how they got the job) have a report or some functionality. Instead of putting in some effort and applying the training they received (they did receive training didn't they? I mean, no-one, surely, would pretend to have experience when they haven't, would they...), they just dump the spec into the questions list.

 

So we get the stuff that should be within the grasp of anyone who didn't sleep through the introductory ABAP course

"Dear Sir. I am a newbie. I have to write a program that will output "hello world" to the screen. Please share sample code".

 

or the stuff that's way beyond their capabilities, should never have been given to a newbie, and you wonder why they were assigned the task in the first place.

 

"Dear Sir. I am a newbie. I have to write a program that will be used by mission control to launch and track a superluminal probe, destined for the Frogstar. I'm told it must be written in ABAP Objects. Please can someone teach me what the DATA statement means...  rwds to good answers..."

 

If you've got a specific question, then we'll all be glad to pile in and help - assuming it's not a basic Frequently Asked Question easily answered by doing just a little research. But expecting us to do your job for you? Come on. I get paid by my employer to write programs for them. I should write programs for free for your employer? They might be a competitor!

 

7) Blogs and documents... that aren't

 

Please. Before posting a blog or a document, make sure that a) it hasn't already been covered elsewhere and b) it's not just a program. Here's a clue. If your content is 90% ABAP, then it probably isn't suitable for a blog or a document. If it is a step-by-step guide, even with screen shots, likewise. Both these cases assuming the content isn't already covered are far more suited to the wiki.

 

There are some exceptions to this. This blog A complete guide to OpenSQL statements - Step-by-step tutorial with screenshots doesn't say anything ground-breakingly new. However, I felt it was so well written and so comprehensive, that it did add real value to the community.

 

But there was nonetheless a risk - taking into account a) and b) above. You need to be aware that rejection of blogs and documents now carries a penalty! Not only do you lose any points you got from the content - including those from likes and four or five stars, but according to how many you've had rejected, you get a penalty of 1-80 points! Because I'm not really a grumpy old man, if you're unsure, feel free to drop me a line before publishing your content, and I'll have a look. That way, if it isn't up to scratch, I can tell you, and you won't lose points for simply trying to contribute. You can get my contact details from my profile.

 

8) I'm a newbie so...

 

  1. The rules don't apply to me
  2. I don't have to do any research before posting
  3. This is my spec - please do my work for me
  4. You are obliged to help me... I'm a newbie!

 

OK, partly covered by 6), but I thought it merited it's own section. Yes, we were once all newbies. And I don't really mind basic questions, so long as they're not Frequently Asked Easily Searchable Questions (FAESQs). What I do mind is laziness. Come on - do a bit of research; show you've put some effort into it.

 

It's a bit like in the career corner, where people seem to insist that companies are obliged to give "freshers" without experience jobs, simply because they're "freshers".

 

9) Posting the same thing that just got locked or rejected by a moderator

 

Nobody has a right to post whatever they like. Posting the same content that you got rejected or locked, hoping the moderators won't notice is not only sneaky and rather disrespectful, it's also an action that can, in extremis, lead to your account being deleted and that would make me sad .

 

10) Not sharing all the relevant information - or sharing too much!

 

"I'm doing x, y, z and I'm getting an error. This is my source code, these are my resources. Can someone fix this for me?"

 

Yes, I'd be delighted to. IF ONLY YOU'D TELL ME ***WHAT*** THE ERROR MESSAGE IS!

 

What are we? Telepaths!? Don't you think that perhaps this is vital piece of information' And it's not just errors, it's all kinds of questions where you have to drag the information out of the poster. It's almost as if they don't want any help - as though they're doing you a favour by posting their question.

 

Of course, the flip-side is those who post the complete text of all thirteen books of Lemony Snicket's "A Series of Unfortunate Events", plus the unauthorised autobiography... instead of concentrating on providing the information that's actually relevant. And as for people who post all 20'000 lines of their program code and can't even be bothered to removed the 19'900 lines that are commented out...

So there you have it

 

My bottom five six seven eight nine ten types of posts. If I see this kind of content in the ABAP space, don't be surprised if it gets rejected... I'll try not to leave a sarcastic note, but sometimes it is so hard not to!

There was a issues on my PO print out which unable to find solution using sap forum also.

 

  • Issue is in address field contain values but not shown in the printout.

          There I have set tabs in paragraph format. Then write scripts like below to get address.

 

               &LFA1-NAME1& ,, &W_BUDNO& ,,&EKKO-EBELN&

               &LFA1-NAME2&  ,, ,,

               &LFA1-NAME3& ,,&W_ANGNR& ,, &EKKO-BEDAT&

 

 

            In here for some fields have values and when i debug the script also i can see the value but when print preview shown that value not display.

            As identified this happen when value is a single word.

 

          Solution


I found two ways to solve the problem.


     1.   Introduce control command ADDRESS ENDADDRESS to the script. And then all values are shown correctly.

         

                        

/:ADDRESS PARAGRAPH V1
/*  TITLE    &LFA1-ANRED&
/:  NAME     &LFA1-NAME1&, &LFA1-NAME2&,&LFA1-NAME3&, &LFA1-NAME4&
/:  STREET   &LFA1-STRAS&
/:  POBOX    &LFA1-PFACH&  CODE &LFA1-PSTL2&
/:  CITY     &LFA1-ORT01&, &LFA1-ORT02&
/:  POSTCODE &LFA1-PSTLZ&
/:  COUNTRY  &T005T-LANDX&
/:  REGION   &LFA1-REGIO&
/:  FROMCOUNTRY &T001-LAND1&
/:ENDADDRESS

 

     2. Remove tabs and keep &SPACE(10)& to get output.

 

Hope this will help u.

 

Thank u.       

Pavithra

As a utility firm, we are engaged in sending mails to many a customers and vendors of various aspects, and details. Some mails are with extensive graphics and URL links, and some are simple, with attachments. There have been many instances, fellow folks were struggling in formatting the mail body. Reading the content from Text elements, Standard texts, and adopting with huge formatting.

 

     Using the standard texts (SO10) for storing the mail body is not a new concept, But when we get the standard Text thru READ_TEXT function module, the later falls a hectic part in formatting the mail to the desired output.

 

     Yet, the advantage is, SO10 comes with the option of uploading the text with '.rtf'  Rich Text files.

 

Below are three standard texts. This will preserve the mail body, and appears with similar format of that of the uploaded file '.rtf' in SO10.

 

Frame Work Adapted

  • Created three standard texts for header, footer and body.
  • The Header and footer standard texts can be used for complex HTML design formatting.
  • The body standard text is used to send mail body of intended scenario.
  • All texts are appended to an internal table, and sent to a utility class for formatting to CL_BCS_SEND mail content format.
  • Function modules READ_TEXT and CONVERT_ITF_TO_STREAM_TEXT is used to convert the standard text to required format.
  • The returned internal table 'RT_MAIL_BODY' is now a formatted mail content of HTML type derived form standard texts.

 

 

Standard Text.png

The main body texts, which can be changed dynamically based on the scenario.

Standard Text body.png

 

Standard Text Footer.png

 

The Header and footer above can be replaced by complex HTML formatting to send the mails to Customers / Vendors with brand image and extensive URL Links. This will ensure the centralized maintenance of mail formatting and secure source for the HTML source data.

 

Advantages : No additional mail formatting is necessary while drafting mail data.

 

Below snap shot shows the e-mail source code that was adapted.

 

Here, all the standard texts as in above snap shots are appended to a internal table, and passed to a utility class to get the mail body required.

TRY.
  
CLEAR lt_thead.
  
lv_thead-tdobject = 'TEXT'.
  
lv_thead-tdname = 'Z***_HTML_HEADER'.
  
lv_thead-tdid = 'ST'.
  
lv_thead-tdspras = sy-langu.
  
APPEND lv_thead TO lt_thead.
  
CLEAR lv_thead.
  
lv_thead-tdobject = 'TEXT'.
  
lv_thead-tdname = lv_mailbody.
  
lv_thead-tdid = 'ST'.
  
lv_thead-tdspras = sy-langu.
  
APPEND lv_thead TO lt_thead.
  
CLEAR lv_thead.
  
lv_thead-tdobject = 'TEXT'.
  
lv_thead-tdname = 'Z***_HTML_FOOTER'.
  
lv_thead-tdid = 'ST'.
  
lv_thead-tdspras = sy-langu.
  
APPEND lv_thead TO lt_thead.
  
CLEAR lv_thead.
*
  
CALL METHOD cl_sd_util->build_mail_body_from_itf
  
EXPORTING
  
im_thead  = lt_thead
  
RECEIVING
  
rt_content_txt = rt_mail_body.
************

 

Reading the standard text, and converting to 'BUBAS_T_MAIL_CONTENT' Table with Mail Content format .

 

METHOD build_mail_body_from_itf.
*
 
DATA : lt_lines TYPE STANDARD TABLE OF tline,
  
lt_lines_final TYPE STANDARD TABLE OF tline,
  
lv_string TYPE string_table,
  
ls_thead TYPE thead.
*
 
LOOP AT im_thead INTO ls_thead.
*
  
CALL FUNCTION 'READ_TEXT'
  
EXPORTING
*  CLIENT = SY-MANDT
  
id  = ls_thead-tdid
  
language  = ls_thead-tdspras
  
name  = ls_thead-tdname
  
object  = ls_thead-tdobject
  
TABLES
  
lines  = lt_lines
  
EXCEPTIONS
  
id  = 1
  
language  = 2
  
name  = 3
  
not_found  = 4
  
object  = 5
  
reference_check  = 6
  
wrong_access_to_archive = 7
  
OTHERS  = 8.
  
IF sy-subrc EQ 0.
  
APPEND LINES OF lt_lines TO lt_lines_final.
  
CLEAR lt_lines.
  
ELSE.
  
RAISE EXCEPTION TYPE zcx_exc_class_wdobjectsk
  
EXPORTING
  
textid = zcx_exc_class_wdobjectsk=>zcx_nodatadata.
  
ENDIF.
*
 
ENDLOOP.
 
IF sy-subrc EQ 0.
*
  
CALL FUNCTION 'CONVERT_ITF_TO_STREAM_TEXT'
  
EXPORTING
  
language  = sy-langu
  
lf  = ' '
  
IMPORTING
  
stream_lines = lv_string
  
TABLES
  
itf_text  = lt_lines_final
  
text_stream  = rt_content_txt[].
 
ELSE.
  
RAISE EXCEPTION TYPE zcx_exc_class_wdobjectsk
  
EXPORTING
  
textid = zcx_exc_class_wdobjectsk=>zcx_nodatadata.
 
ENDIF.
ENDMETHOD.

 

The method returns RT_MAIL_BODY of type BUBAS_T_MAIL_CONTENT, which can be exported to  cl_document_bcs to send the mail in HTML format.

 

 

  document = cl_document_bcs=>create_document(
  
i_type  = 'HTM'
  
i_text  = RT_MAIL_BODY[]
  
i_importance = '1'  "changes to make priority low
  
i_length  = lv_size
  
i_subject = document_data-obj_descr ).


 

Mail received in HTML Format.

MAIL.png




As a result, Many a complex scenarios with extensive HTML designs can be sent as e-mails with varied body context. The single framework can be adopted with various contexts to suit the scenario.


Tried and tested below generated customer notification mail with the above frame work. For illustration.

MAIL HTML.png



Please comment, reply for any suggestions and alterations to the post.


Thanks.

Hello SCN,

here is quick tip on how to "pinpoint" trace (SQL, performance etc..) in New ABAP Debugger.

 

There is new debugger tool named "Trace (SE30/ST05)". You can add it to your debugger desktop like any other tools.

By icons on right side of current tools - either New tool or Replace tool. It is in "Special Tools" folder.

By the way you can save your customized debugger desktops

 

Tool can be found from about ECC SAP_ABA release 702 (it is not in SAP_ABA 700...).

 

Here is how it looks and which traces it offer:

abap-debugger-trace.PNG

 

Usage is very easy:

For example stop on SELECT statement

  • double click on activate (on/off) SQL Trace
  • run SELECT (F5 or so)
  • deactivate SQL trace
  • there will popup TraceFile icon on the left, which you can immediately investigate

Normally, when I backup my ABAP codes, I just COPY-PASTE it in a notepad or in a word document. This technique is ok. But now I want to have
a PDF file so I can save it into my mobile phone in order to view it anywhere at any given time.

 

Well, this is now the solution I discovered which I want to share to everyone.

 

 

Steps:

  • At the lower right part of the ABAP editor, you will see this button in yellow. That button is below the vertical scroll bars.
    Click this button to view the different options. Click button found at the bottom right of the editor. (Highlighted in following screenshot)

 

          1.png

  • From the options, click keyboard. Then select File.ExportPDF from the command list. Please refer from the screenshot below.

          2.png

  • On the input box, New Shortcuts, type SHIFT+BACKSPACE. Then click the button Assign. By the way, the combination of the keys can be
    different from yours as long as it is available. It so happened that this key combinations are available so I used in this tutorial. After clicking the
    Assign button, you will see the keys reflected in the Shortcuts for selected commands textbox. Then click the Save button afterwards.

          3.png

  • Once you save the settings you did above, you will be back into your ABAP editor. Now, in your editor, pressed the key combination you set. In my case, I will press SHIFT+BACKSPACE. Immediately, the Save dialog box will be prompted like this one. Type the filename of your file and locate the directory where you want to save. Finally, click the Save button to create the PDF file.

               4.png

 

 

PDF output:

5.png

 

 

I want to mention the nice feature of escaping string characters in ABAP. There is predefined function escape available with all options (HTML, XML, JS, JSON, XSS, URI, etc.) when you are using SAP_BASIS >= 731.

 

 

Function definition

Calling of the function is in this format:

escaped_string = escape( val = unescaped_string format = format )

 

 

Use cases

There are several use cases when you can use it such as:

  • Encoding URL / URIs
  • Escaping XML / HTML content, even HTML with Javascript
  • Encoding file name in HTTP header response as described in my other blog post

 

 

Documentation

There are two nice documentation sites:

 

 

This escape function should provide complex way in order to escape everything. I hope you enjoy it.

It was impossible to open attachment in JAVA SAP GUI in Solution Manager.

 

To solve the problem  you should required access key for the program and FM.

 

FM SKWV_KWUI_DOC_DISPLAY


Step 1

Go to line no. 112 after  ls_filename = l_aliasname.


Add below lines


data: lv_plat3     type char2.  

CALL METHOD cl_gui_frontend_services=>get_platform
   receiving
     platform             = lv_plat3
   EXCEPTIONS
     error_no_gui         = 1
     cntl_error           = 2
     not_supported_by_gui = 3
     others               = 4.

if lv_plat3 = '8'.
ls_temp_dir = '/home'.
   CONCATENATE ls_temp_dir '/' ls_filename INTO ls_download_filename.
   ls_fullpath = ls_download_filename.
   CONCATENATE 'file://' ls_download_filename INTO ls_url_dest.
   ls_url_source = ls_phio_url.
else.


Go to line no.138  after ls_url_source = ls_phio_url.


Add below single line


endif.



PROGRAM : LSKWV_KWUI_DOCUMENTF02


Step 2

Go to line no 356 after

concatenate ls_temp_dir p_phio-objid into ls_work_dir
separated by c_separate_path.


Add below lines


data: lv_plat     type char2.

CALL METHOD cl_gui_frontend_services=>get_platform
   receiving
     platform             = lv_plat
   EXCEPTIONS
     error_no_gui         = 1
     cntl_error           = 2
     not_supported_by_gui = 3
     others               = 4.

clear ls_temp_dir.
if lv_plat = '8'.
ls_temp_dir = '/home'.


concatenate ls_temp_dir p_phio-objid into ls_work_dir
              separated by '/'.
endif.


Step 3

Go to line no 520 after clear p_asynchronous.


Add below lines.


if lv_plat = '8'.
CALL METHOD cl_gui_frontend_services=>execute
          EXPORTING: document               = ''
                     application            = 'open'   or you can also add command 'xdg-open'    <- The OS will open the document with the default program for the specified file.
                     parameter              = LS_FILENAME
                     maximized              = ''
                     minimized              = ''
                     synchronous            = ''       
          EXCEPTIONS: cntl_error             = 1
                      error_no_gui           = 2
                      bad_parameter          = 3
                      file_not_found         = 4
                      path_not_found         = 5
                      file_extension_unknown = 6
                      error_execute_failed   = 7
                      synchronous_failed     = 8
                      not_supported_by_gui   = 9
                      OTHERS                 = 10.
else.


Go to line 560 after

exceptions
       cntl_error             = 1
       error_no_gui           = 2
       bad_parameter          = 3
       file_not_found         = 4
       path_not_found         = 5
       file_extension_unknown = 6
       error_execute_failed   = 7
       synchronous_failed     = 8
       not_supported_by_gui   = 9
       others                 = 10.

Add single line

endif.



Step 4


Go to form execute_phio after  ls_filename = p_fullpath.


Add below lines


data: lv_plat3     type char2

CALL METHOD cl_gui_frontend_services=>get_platform
   receiving
     platform             = lv_plat3
   EXCEPTIONS
     error_no_gui         = 1
     cntl_error           = 2
     not_supported_by_gui = 3
     others               = 4.

if lv_plat3 = '8'.
CALL METHOD cl_gui_frontend_services=>execute
          EXPORTING: document               = ''
                     application            = 'open'   or you can also add command 'xdg-open'    <- The OS will open the document with the default program for the specified file.
                     parameter              = LS_FILENAME
                     maximized              = ''
                     minimized              = ''
                     synchronous            = ''        "note_919764
          EXCEPTIONS: cntl_error             = 1
                      error_no_gui           = 2
                      bad_parameter          = 3
                      file_not_found         = 4
                      path_not_found         = 5
                      file_extension_unknown = 6
                      error_execute_failed   = 7
                      synchronous_failed     = 8
                      not_supported_by_gui   = 9
                      OTHERS                 = 10.
else.

Go to

call method cl_gui_frontend_services=>execute
     exporting
       document               = ls_filename
     exceptions
       cntl_error             = 1
       error_no_gui           = 2
       bad_parameter          = 3
       file_not_found         = 4
       path_not_found         = 5
       file_extension_unknown = 6
       error_execute_failed   = 7
       others                 = 8.


Add single line.


endif.



Step 5.

Go to form get_content after

concatenate p_path p_filename into ls_file  separated by c_separate_path.


Add below lines

data: lv_plat2     type char2.  

CALL METHOD cl_gui_frontend_services=>get_platform
   receiving
     platform             = lv_plat2
   EXCEPTIONS
     error_no_gui         = 1
     cntl_error           = 2
     not_supported_by_gui = 3
     others               = 4.
 
if lv_plat2 = '8'.
clear ls_file.
concatenate p_path p_filename into ls_file
       separated by '/'.
endif
.


Step 6


go to root

# cd /

# chmod 777 /home        <- all file will be download /home path

 


SHARED MEMORY

 

As you already know there is often cases that we need to share common data across programs.

This is a result of business requirements for the purpose of this blog i like to call it as Buffer.

The meaning i use here is not the shared buffer concept in abap which is also another topic.

 

So we need to store in a place like buffer and share the memory.

 

As an example: In the latest project i was working on there was a requirement where i needed to store all the data that user has entered inside a Goods Movement

Till the user goes and saves sit  i should be able to store the data in the Z interface that i developed.

So i needed to store the data which was a complex one.

 

Export to MEMORY ID concept is the most primitive one but not very powerful when you are needing to store smth very complex like an object

 

So I had to unleash the Shared memory and learn it to apply in the project.

 

 

Lets start applying here !!!

 

 

STEPS TO CREATE SHARED MEMORY CONCEPT IN ABAP

 

In the example below i like to give you a shared memory where you can store an object or data.

 

Step 1- Create the Shared memory Object- What will you store?

Create the object called  zcl_shared_root-DO NOT FORGET TO MARK IT AS SHARED MEMORY ENABLED

 

ZCL_SHARED_ROOT

class ZCL_SHARED_ROOT definition

  public

  final

  create public

  shared memory enabled .

 

 

public section.

 

 

  interfaces IF_SHM_BUILD_INSTANCE .

 

 

  data OREF type ref to OBJECT .

  data DREF type ref to DATA .

 

 

  methods SET_OREF

    importing

      !IO_OREF type ref to OBJECT .

  methods GET_OREF

    returning

      value(RO_OREF) type ref to OBJECT .

  methods SET_DATA

    importing

      !IO_DREF type ref to DATA .

  methods GET_DATA

    returning

      value(RO_DREF) type ref to DATA .

protected section.

private section.

ENDCLASS.

 

 

CLASS ZCL_SHARED_ROOT IMPLEMENTATION.

 

 

  method GET_DATA.

  ro_dref = dref.

  endmethod.

 

 

  method GET_OREF.

    ro_oref = oref.

  endmethod.

 

  method SET_DATA.

   dref = io_dref.

  endmethod.

 

 

  method SET_OREF.

  oref = io_oref.

  endmethod.

ENDCLASS.

 

Attributes: oref as reference to another object

                dref as a reference to any data

 

 

Step 2- Create the Shared memory Area- The memory area that wıill store your object

Check SHMA is quite useful !!


Question: Automatic Preload is a good feature, when we first read the data it will throw a dump so to avoid this we need to use automatic preload feature!!


Here the name of the Area is zcl_shared_areaç notice the root class name is our root at above and auto are creation is ticked !!

This is because of the interface we implemented at the zcl_shared_root object

if_shm_build_instance


shma_1.png



Step 3 - Create a the Object we want to Save called zcl_object_saved

Note that its shared memory enabled as well!!

Example data taken from sflight database!!

 

zcl_object_saved

class zcl_object_saved definition

   public

   final

   create public

   shared memory enabled .

 

   public section.

     data flight_list type sflight_tab1 .

     methods add_flight

       importing

         !is_flight type sflight .

     methods get_flight_list

       returning

         value(rt_flight_list) type sflight_tab1 .

   protected section.

   private section.

 

 

endclass.

 

 

 

class zcl_object_saved implementation.

 

 

* <SIGNATURE>---------------------------------------------------------------------------------------+

* | Instance Public Method ZCL_OBJECT_SAVED->ADD_FLIGHT

* +-------------------------------------------------------------------------------------------------+

* | [--->] IS_FLIGHT                      TYPE        SFLIGHT

* +--------------------------------------------------------------------------------------</SIGNATURE>

   method add_flight.

 

     read table flight_list transporting no fields

     with key carrid = is_flight-carrid

              connid = is_flight-connid

              fldate = is_flight-fldate

              .

     if sy-subrc ne 0.

       append initial line to flight_list reference into data(lr_flight).

       lr_flight->* = is_flight.

     endif.

 

   endmethod.

 

 

* <SIGNATURE>---------------------------------------------------------------------------------------+

* | Instance Public Method ZCL_OBJECT_SAVED->GET_FLIGHT_LIST

* +-------------------------------------------------------------------------------------------------+

* | [<-()] RT_FLIGHT_LIST                 TYPE        SFLIGHT_TAB1

* +--------------------------------------------------------------------------------------</SIGNATURE>

   method get_flight_list.

     rt_flight_list = flight_list.


Step 4 - Implement the Build of the Automatic preload!! interfaces if_shm_build_instance


Implement the code inside ZCL_SHARED_ROOT build!!


 

ZCL_SHARED_ROOT

method if_shm_build_instance~build.

     data: lo_handle type ref to zcl_shared_area,

           lo_root type ref to zcl_shared_root,

           lo_object_saved type ref to zcl_object_saved,

           ls_sflight type sflight

              .

 

*Autamatic PreLoad!!

     try.

         lo_handle = zcl_shared_area=>attach_for_write( ).

         create object lo_root area handle lo_handle.

         lo_handle->set_root( lo_root ).

 

         create object lo_root->oref area handle lo_handle type zcl_object_saved.

         lo_object_saved ?= lo_root->oref.

**get data

         select single * from sflight

           into ls_sflight.

**Set a data

         lo_object_saved->add_flight( is_flight = ls_sflight ).

         lo_handle->detach_commit( ).

       catch cx_shm_error

         into data(lo_exception).

         raise exception type cx_shm_build_failed

           exporting

             previous = lo_exception.

     endtry.

 

if  invocation_mode = cl_shm_area=>invocation_mode_auto_build.

       call function 'DB_COMMIT'.

     endif.

 

 

   endmethod.


Step 5 -Create a test program!!

 

ZTEST_SHARED

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

*& Report  ZTEST_SHARED

*&

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

*&

*&

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

 

report ztest_shared.

 

 

class lcl_test definition.

   public section.

     class-methods: test_auto_build.

     class-methods: test_write.

 

endclass.

 

class lcl_test implementation.

 

   method test_auto_build.

     data: lo_handle type ref to zcl_shared_area,

              lo_root type ref to zcl_shared_root,

              lo_object_saved type ref to zcl_object_saved,

              ls_sflight type sflight

                 .

*Autamatic PreLoad!!

     try.

         lo_handle = zcl_shared_area=>attach_for_read( ).

         lo_object_saved ?= lo_handle->root->oref.

 

         lo_handle->detach( ).

       catch cx_shm_attach_error into data(lo_exc).

 

     endtry.

 

   endmethod.

 

   method test_write.

     data: lo_handle type ref to zcl_shared_area,

              lo_root type ref to zcl_shared_root,

              lo_object_saved type ref to zcl_object_saved,

              ls_sflight type sflight

                 .

 

 

     try.

         lo_handle = zcl_shared_area=>attach_for_write( ).

         create object lo_root area handle lo_handle.

         lo_handle->set_root( lo_root ).

 

         create object lo_root->oref area handle lo_handle type zcl_object_saved.

         lo_object_saved ?= lo_root->oref.

**get data

         select single * from sflight

           into ls_sflight.

**Set a data

         lo_object_saved->add_flight( is_flight = ls_sflight ).

         lo_handle->detach_commit( ).

       catch cx_shm_error

         into data(lo_exception).

         raise exception type cx_shm_build_failed

           exporting

             previous = lo_exception.

     endtry.

 

   endmethod.

 

endclass.

 

 

start-of-selection.

   break solend.

 

 

   call method lcl_test=>test_auto_build.


Step 6- Observe the memory Area Created!!


Go to shma and choose the memory area-zcl_shared_area


shma_2.png


As you can see you can check the memory allocated for the Shared memory and inside our memory we managed to store another object!!


This could be a much complex object!!


Conclusion: So i can read this memory area and access the object from another program which is great is not it.


I hope you find my blog useful!!


Thanks all






    It was impossible to open documents in JAVA SAP GUI.

 

    To solve the problem  I have created  two enhancement in the Program LCV120F05 and FM CV200_DB_TDWE_SELECT using

 

    the implicit enhancement spot at the  beginning of the FORM appl_start_exec, and this is my simple code:

 

Step 1

Program LCV120F05

ENHANCEMENT 1  Z_LVC120F05."active version
if gs_frontend-winsys = 'MF'.

  pf_application = 'open'.   or you can also add command 'xdg-open'    <- The OS will open the document with the default program for the specified file.

  clear pf_use_reg.

endif.

ENDENHANCEMENT.

 

Step 2

FM CV200_DB_TDWE_SELECT

 

ENHANCEMENT Z_CV120_PATH
DATA : lv2_frontend      TYPE dms_frontend_data" Frontend information
CLEAR: lv2_frontend.                          
CALL FUNCTION 'CV120_GET_FRONTEND_TYPE'
* EXPORTING
*   PF_CALL_DIALOG          = ' '
*   PF_BATCH                = ' '
*   PF_HOST                 = ' '
  IMPORTING
    PFX_FRONTEND_TYPE  = lv2_frontend-frontend_type
    PFX_HOST                     = lv2_frontend-hostname
    PFX_WINSYS                 = lv2_frontend-winsys
* EXCEPTIONS
*   ERROR                   = 1
*   NO_VALID_FRONTEND       = 2
*   OTHERS                  = 3
           .
IF sy-subrc <> 0.
* Implement suitable error handling here
ENDIF.
IF LV2_frontend-winsys = 'MF'.    
PSX_tdwe-FILEP  = '/home'.    
"Default path for all user download specified file.
ENDIF.
ENDENHANCEMENT.

Step 3

go to root

# cd /

# chmod 777 /home        <- all file will be download /home path

tools.jpg

When developing for Multilingual clients normally translations are required. Even using standard transactions or reports this is a time consuming and boring task.


I build this tool to accelerate and improve translations quality. You can easily copy texts from source to target languages, import/export to excel file and prepare a transport request including only language-specific components.

 

Sorry, this blog was been moved to document:

Development dependencies translator with Transport

 

Nuno Morais's Blog

 

Nuno Morais | LinkedIn

When a form (smartforms) is printed, a PDF copy is generated and saved for future reference. Sometimes when you want to reprint from the PDF copy, you may want or it may be required, to add watermark such a 'COPY' etc., to indicate that it is not the original.

 

 

In SAP, I could not find a way to imprint watermark into the form when printing the PDF from SAP system.

 

 

Here is an alternate way flexible enough to add any watermark style in the form printed from a soft copy created earlier.

 

 

First, we are not going to use PDF format to store the copy, but OTF itself generated from the smartforms. If you want a PDF, it can be made available using SAP function modules to convert OTF to PDF anytime. So I feel it's ok to use OTF format for storing the copy.

 

 

During form printing, we get the OTF. Without converting to PDF format, save the OTF data itself, possibly in the content server.

 

 

In another time, you will retrieve the OTF data (let's call this form OTF). OTF data is in the format of PRINTER COMMAND (itcoo-tdprintcom) and PRINTER PARAMETERS ((itcoo-tdprintpar). There are different command codes such BM for bitmap, IN, RD etc. Knowing this, we are going to insert a background node with bitmap image of the watermark. For this, we need to create a smartforms (let's call this BMP form/OTF) with PAGE1's background set to the bitmap image; you may want to use dynimcal setting of BMP image. Now that the BMP form is ready, call the smartforms to get the OTF data. So, basically this OTF data will have some meta data and codes/commands for a page with background set to a BMP image. We will extract this information and insert it in the previous target OTF data. Follow these steps:

 

 

Now you have the BMP form OTF in the form TDPRINTCOM and TDPRINTPAR in an internal table.

- Delete all records except TDPRINTCOM = 'RD', the first TDPRINTCOM='IN' and the first TDPRINTCOM='MT'.

In the end you will get like,

TDPRINTCOM /TDPRINTPAR

IN 06%%BGR1

BM 1374705146 D    BDS_LOC3  A4BADB2<<<SOMECODES>>>>

RD <<<<SOME CODES>>>>>

RD <<<<SOME CODES>>>>>

RD <<<<SOME CODES>>>>>

RD <<<<SOME CODES>>>>>

RD <<<<SOME CODES>>>>>

RD <<<<SOME CODES>>>>>

 

 

Next, in the form OTF, find the index where TDPRINTCOM = 'OP'. If there are multiple pages, LOOP at TDPRINTCOM ='OP'. OP stands for Open Page.

Insert the above OTF lines into the form OTF, at index one more than the above index.

 

 

That's it. Now check your print copy or the PDF you generated from this OTF. It should have a background watermak you created in the BMP form.

HI Guys,

For past few days I was struggling hard to figure out whether we can use data types or class definitions of other programs in our programs or enhancements without using statement include or copy paste entire code in our source code. At last I have found SAP standard program which answers all my questions.

 

'DEMO_CREATE_REFERENCE' is the program which illustrates this. Here is the sample code.

 

DATA: CLS_NAME  TYPE STRING,

            REF              TYPE REF TO DATA.

 

  CLS_NAME = '\PROGRAM=DEMO_CREATE_REFERENCE\CLASS=CLS'.

  CREATE OBJECT REF TYPE REF TO (CLS_NAME).

->with the above statement REF will have type CLASS-CLS of program DEMO_CREATE_REFERENCE.

 

For eg-

                  CLS_NAME = '\FUNCTION-POOL=MEREQ\CLASS=LCL_REQ_ITEM'

                  CREATE OBJECT REF TYPE REF TO (CLS_NAME).

->here REF will have type class - LCL_REQ_ITEM of Function group - MEREQ.

 

      I know you guys might wonder how this stuff is put in use or will help. I shall explain my case where I have come across a situation where I need to define   a variable with the type of a class used in other program.

           

MY SITUATION AND SOLUTION I HAVE FOUND-

           Somehow with my requirement I have ended up in class CL_TABSTRIP_VIEW_MM with a need to access an attribute 'ITEM' of class  LCL_REQ_ITEM_STATE which is defined in Function group MEREQ.Though I can see all the required attributes in debug mode, I was unable to fetch them in the source code, as classes are defined in include of function group not inSE24.At last I have found myself a solution, below is the approach and situtaion.


            DATA:  CLS_NAME             TYPE                STRING,

                         REF                         TYPE REF TO  DATA,      
                         LC_MODEL             TYPE REF TO  IF_MODEL_HOLDER_MM,

                         LC_GET_MODEL    TYPE REF TO  IF_MODEL_MM.

  FIELD-SYMBOLS:        
                         <REF>                      TYPE               ANY,     
                         <MY_STATE>          TYPE               ANY,       
                         <ITEM>                    TYPE               MEREQ_ITEM.

 

**--Here Subviews is defined parameters in method PBO of class CL_TABSTRIP_VIEW_MM

       READ TABLE SUBVIEWS INTO lS_SUBVIEW INDEX 16.

          IF SY-SUBRC = 0.

                LC_MODEL ?=  lS_SUBVIEW.

                     IF LC_MODEL IS   BOUND.

                           LC_GET_MODEL   =  LC_MODEL->GET_MODEL( ).


**--Here LC_GET_MODEL will have data ref to type class LCL_REQ_ITEM of function pool-MEREQ, So, here is the need to **define a varaible with type ref to a class defined in another program/function pool.

                 CLS_NAME = '\FUNCTION-POOL=MEREQ\CLASS=LCL_REQ_ITEM'

                 CREATE OBJECT REF TYPE REF TO (CLS_NAME).

                         ASSIGN REF->* TO <REF>

 

**--Now, Assign Model to its type and access required attributes                 
                                <REF> ?= LC_GET_MODEL

 

                        IF  <REF> IS ASSIGNED.               

   
                                ASSIGN ('<REF>-MY_STATE') TO <ATTR>.                     
                                      IF <ATTR> IS ASSIGNED.                    
                                             ASSIGN ('<ATTR>-ITEM') TO <ITEM>.                    
                                       ENDIF.    "IF <ATTR> IS ASSIGNED.                  

                         ENDIF.   "IF <REF> IS ASSIGNED.

                  ENDIF.   "IF LC_MODEL IS BOUND.

            ENDIF.     "READ TABLE SUBVIEWS INTO lS_SUBVIEW INDEX 16.

 

                               <ITEM> will have the required information which we are looking for.

This is a blog post I wanted to write for quite some time and my first try on writing a rant. And what could be a better set up for a rant than a broken heel at the beginning of summer?

 

Before starting to work in the area of SAP CRM and SAP IS-U most of the development I did was on the Java platform. When starting to develop on the SAP Netweaver platform two things really struck me. The first one was the lack of n modern IDE, the second one the lack of consistent, well documented, object oriented APIs. The first problem has recently been solved for by ABAP in Eclipse. The second one will be the topic of this blog post. The missing of consistent, well documented, object oriented APIs is in my opinion the result of a missing focus on API design by SAP. While some areas of the Netweaver platform offer rather nice APIs, most parts and almost all applications are lacking them.

 

 

Symptoms of the missing APIs

I think there are quite a number of issues resulting from missing API design. These range from increased development effort to problems during EhP upgrades. From my experience most of these issues are symptoms caused by the following underlying problems:

  1. Working on the wrong abstraction level
  2. Duplication of functionality by creating custom APIs

In the following section I’ll describe each of these problems and the symptoms causedby them in some more detail.

Working on the wrong abstraction level

If you follow some of the different space on SDN for some time, you will most likely recognize that some similar questions are asked again and again. These questions usually contain some patterns like, “which table stores information X”, “how is table Y linked to table Z” or “how to update table W”. These kinds of questions in my opinion usually show that someone is working on the wrong abstraction level. The underlying requirements for these questions are the need to read or update some business object stored in one of the tables. For example, instead of asking how to update table BUT050 the real requirement is how to add a business partner relation to a business partner. However, as the available APIs do not abstract from the underlying tables, developers tend to think and work on the table level rather than on the more suitable business object level.

The result of working on the wrong abstraction level is ultimately bad design and bad code quality. If developers think in terms of databases tables instead of objects they will most likely write select and update statements across their code. The result of this is code that is difficult to test and hard to maintain.

Duplication of functionality by creating custom APIs

When no suitable APIs are available developers tend to redevelop similar functionality over and over again. This is not only true for custom developments but also for the SAP standard. For example, a simple search for all usages of the BAL_LOG_MSG_ADD function module in one of our CRM systems revealed about 50 classes using this function module. The following list contains some of the classes I found:

  • CL_CRM_LOG
  • CL_CRM_BSP_CU_APPLOG
  • CL_CRM_BSP_CU_APPLOG
  • CL_DMC_APPL_LOG
  • CL_LOG_PPF

All of these classes try to wrap the function module based API of the application log with an object oriented one. Each of these classes does more or less the same with some slight variations to it. In addition to the SAP standard classes wrapping the application log I also found some Z-classes as well as on “standard” class in our own namespace.

Duplication of code or functionality is always bad design. The lack of easy to use APIs even for basic tasks like logging fosters duplication. This ultimately results in increases defect rates in custom code and leads to longer development times and / or lower quality.

 

Features of good API design

Good API design is an extensively discussed topic. For this blog I will use a list of features for good API design initially given by Joshua Bloch in his talk “How to design a good API and why it matter” (cf. http://lcsd05.cs.tamu.edu/slides/keynote.pdf or How to Design a Good API &amp;amp; Why it Matters). According to Joshua Bloch a good API is

  • Easy to learn
  • Easy to use, even without documentation
  • Hard to misuse
  • Results in easy to read and maintainable code
  • Sufficiently powerful to satisfy requirements
  • Easy to extend / evolve
  • Appropriate to the audience.

In the context of development on the SAP Netweaver platform I would extend the list above by the requirement for the API to be object oriented. In my opinion most of the APIs provided by SAP fail according to the above characteristics.

 

An Example of current APIs: The business partner APIs

In the following sections I will analyze the APIs currently provided by SAP with respect to the characteristics mentioned above. As an example for this analysis I will use the different APIs for business partners.

There are two business partner APIs that are regularly use in the context of SAP CRM and SAP IS-U (besides the ever so common SELECT * FROM BUT000 ;). These are

  • the business partner BAPI API
  • the CRM BOL API.

 

I know there are quite a number of other APIs for business partner, but for the purpose of this blog I focus on these two. The use case I will use to analyze the APIs is to search for a business partner with a given name and read its default address.

 

The business partner BAPI API

Using the BAPI API this use case can be implemented using the following code. Note that I did not implement any error handling here to keep the example more concise. Furthermore, I did not take into account the possibility of having different kinds (e.g. person, organization or group) of business partners to simply things further.

  DATA: search_data TYPE bapibus1006_central_search,
        search_results TYPE TABLE OF bapibus1006_bp_addr,
        central_data_person TYPE bapibus1006_central_person,
        address_guid TYPE bu_address_guid,
        address_guid_32 TYPE sysuuid_c,
        address_data TYPE bapibus1006_address,
        return_vals TYPE TABLE OF bapiret2,
        address_string TYPE string.
  FIELD-SYMBOLS: <search_result> TYPE bapibus1006_bp_addr.
  search_data-mc_name1 = 'Test'.
  CALL FUNCTION 'BAPI_BUPA_SEARCH_2'
    EXPORTING
      centraldata  = search_data
    TABLES
      searchresult = search_results
      return       = return_vals.
  READ TABLE search_results ASSIGNING <search_result> INDEX 1.
  CALL FUNCTION 'BAPI_BUPA_CENTRAL_GETDETAIL'
    EXPORTING
      businesspartner   = <search_result>-partner
    IMPORTING
      centraldataperson = central_data_person.
  CALL FUNCTION 'BAPI_BUPA_ADDRESSES_GET'
    EXPORTING
      businesspartner     = <search_result>-partner
    IMPORTING
      standardaddressguid = address_guid.
  address_guid_32 = address_guid.
  CALL FUNCTION 'BAPI_BUPA_ADDRESS_GETDETAIL'
    EXPORTING
      businesspartner = <search_result>-partner
      addressguid     = address_guid_32
    IMPORTING
      addressdata     = address_data.
  WRITE / central_data_person-fullname.
  WRITE / address_data-street && ` ` && address_data-house_no && `, ` && address_data-city.

Analyzing this piece of code and the BAPI API according to the criteria mentioned above I came to the results listed in the table below. While the analysis is certainly subjective I think it points out some of the problems with the BAPI API. In my opinion the major problem is the need to know the underlying database mode in detail to being able to use the API. In summary I think the BAPI API for business partners is not a good API with regard to the criteria.

 

CriteriaAnalysis

Object Oriented

The API is based on function modules and not object oriented.

Easy to learnIn my opinion the API is tied very closely to the underlying data base model. Without a sound understanding of this data base model it is very difficult to guess which function modules to use to get which data. For example, it is not clear which fields to use to search for a business partner name without knowing the underlying database model.

Easy to use, even without documentation

As stated above the API is not usable without a sound understanding of the business partner data model.

Hard to misuse

It is easy to misuse the API. For example, it is quite easy to miss the need to convert between the different GUID representations used in the API resulting in a dump during runtime.

Results in easy to read and maintainable code

As the code is based on function modules it is not very concise and therefore harder to read. However, once one understands the API the core is reasonably well read and maintainable.
Sufficiently powerful to satisfy requirements

It is definitely powerful enough to fulfill the requirements for reading, storing and updating business partner data.

Easy to extend / evolve

The API can only be extended using the enhancement techniques (e.g. BAdIs or implicit enhancement points) provided by SAP.

Appropriate to the audience.

The BAPI API is not appropriate for its audience as it forces developers to switch between an object oriented and the structured programming model. Furthermore, it requires developers to understand the underlying database model in detail.


The CRM BOL API

Implementing the same use case using the CRM BOL API results in the following code. Again I omitted some error handling as well as the handling of different business partner.

 

DATA: bol_core TYPE REF TO cl_crm_bol_core,
        query TYPE REF TO cl_crm_bol_query_service,
        query_result TYPE REF TO if_bol_entity_col,
        bp_entity TYPE REF TO cl_crm_bol_entity,
        address_entity TYPE REF TO cl_crm_bol_entity,
        related_entities TYPE REF TO if_bol_entity_col,
        full_name TYPE string,
        street TYPE string,
        house_nr TYPE string,
        city TYPE string.
  bol_core = cl_crm_bol_core=>get_instance( ).
  bol_core->start_up( iv_appl_name = 'BP_APPL' ).
  query = cl_crm_bol_query_service=>get_instance( 'BuilHeaderSearch' ).
  query->set_property( iv_attr_name = 'MC_NAME1'
                       iv_value = 'Test' ).
  query_result = query->get_query_result( ).
  bp_entity = query_result->get_first(  ).
  related_entities = bp_entity->get_related_entities( iv_relation_name = 'BuilAddressRel').
  address_entity = related_entities->get_first(  ).
  full_name = bp_entity->get_property_as_string( iv_attr_name = 'FULLNAME' ).
  street = address_entity->get_property_as_string( iv_attr_name = 'STREET' ).
  house_nr = address_entity->get_property_as_string( iv_attr_name = 'HOUSE_NO' ).
  city = address_entity->get_property_as_string( iv_attr_name = 'CITY' ).
  WRITE / full_name.
  WRITE / street && ` ` && house_nr && `, ` && city.

In contrast to the BAPI API the code of the BOL API is more concise and therefore a little more readable. In contrast to the BAPI API the need to use several auxiliary variables (e.g. street, house_nr and city) leads to some additional code . These auxiliary variables could be omitted if I had used the GET_PROPERTIES method instead. However, in my opinion the reading the properties individually is easier to read and therefore leads to cleaner code. While the BOL API is a significant improvement over the BAPI API with respect to readability, there are still a number of problems I see with this API. Still it is necessary to know the underlying data mode quite well in order to perform a query. Furthermore, the API uses a lot of magic strings (e.g. relation names, property names) that need to be taken from the BOL model (using transaction GENIL_MODEL_BROWSER). This complicates developing using the BOL API as, for example, code completion is not available to read relations and attributes. With respect to the API criteria above the BOL API still fails in some important areas

 

Criteria

Analysis

Object Oriented

The API is object oriented. However, the business objects are not first class citizens of the API.

Easy to learn

The core BOL API is reasonable easy to learn. However, the usage of the API requires a constant look up of the BOL model. Furthermore, there is no consistent implementation of the BOL model across different applications (e.g. business partner vs. IS-U integration). Sometimes certain parts of the API (e.g. certain queries) simply do not work as expected.

Easy to use, even without documentation

As stated above the core BOL API is reasonable easy to learn.

Hard to misuse

It is still easy to misuse the API resulting especially in the more advanced areas like changing entities and transaction handling.

Results in easy to read and maintainable codeThe code using the BOL API tends to be more concise then the code of the BAPI API. However, the extensive use of magic strings still results in quite unreadable code especially in more complex scenarios.

Sufficiently powerful to satisfy requirements

The BOL API is definitely powerful enough to fulfill the requirements for reading, storing and updating business partner data.

Easy to extend / evolve

The core part of the API can only be extended using the enhancement techniques (e.g. BAdIs or implicit enhancement points) provided by SAP. In contrast to that, the application model (e.g. the business partner model) can be extended using a combination of customizing and custom code.

Appropriate to the audience.

The BOL API was designed to build the CRM Web UI and enable a separation of the application data model and the underlying database model. However, I think the BOL API still is not a really usable API for business partners.


What the business partner API should look like

If I lookat the task I used to analyze the business partner APIs, namely to search for a business partner with a given name and read its default address, and think of a nice API for this I end up with something like the code below:

 

DATA: query TYPE REF TO cl_bp_query_serice,
      query_result_col TYPE REF TO cl_collection,
      bp TYPE REF TO cl_bp,
      bp_address TYPE cl_bp_adress,
      street TYPE string,
      house_nr TYPE string,
      city TYPE string.
query_result_col = query->query_by_name( 'Test' ).
bp = query_result_col->get_next( ).
bp_address = bp->get_standard_address( ).
street = bp_address->get_street( ).
house_nr = bp_address->get_house_nr( ).
city = bp_address->get_city( ).
WRITE / bp->get_full_name( ).
WRITE / street && ` ` && house_nr && `, ` && city.

When I look at the code of this imaginary business partner API it has multiple advantages over the existing ones:

  • It is really object oriented
  • The code is concise and readable, the intention of the code becomes immediately clear.
  • It would be very easy to learn and use without any documentation as the objects and its methods speak for themselves.
  • It’s the kind of API I as a developer are looking for.

 

I know that my nice imaginary API cuts some corners and omits some of the complexity that underlies the business partner data model. However, I’m sure that with a focus on API design this is what SAP APIs could look like.

 

Summary

So what the result of all this?

First, all SAP applications I’ve been working with suffer from the same problems, there are no suitable APIs. If you need further examples have a look at the CRM one order API or even worse some of the SPA IS-U APIs.
Second, I think SAP should focus on API design and developer productivity as an important part of the product development process. SAP products (at least the on premise solutions) are basically never used out of the box. In all SAP installations custom code is necessary to adapt the standard software to the needs of the customers. By providing usable APIs SAP could significantly reduce the necessary development efforts and implementation time, increase the quality of custom code and, ultimately, reduce the TCO of the overall solution.

 

 

So, SAP when are us starting to build some nice APIs for us?

 

Christian

Based on the social media feedback and the activity on the previous blogs in this series, I've obviously hit a sore point with a lot of people. However, it was a bit rude of me to rant about how bad things are and demand someone fix it, without providing some ideas, some suggestions (plus every good trilogy requires at least four parts).

 

Please take this opportunity to tell me what you think of these ideas, add your own suggestions, and maybe even rank what you see here and in the comments. The SAP Developer Relations team are aware of how ugly the existing situation is, but they can't provide us with what we want (or at least decent reasons why they can't provide what we want) until they hear from us.

 

 

Alice is getting there...

First a progress report; Alice has got her SAP Developer Edition up and running, she has got her head around the fact that it is an entire server and development system in one, and she's coding away. There were some minor issues with stupid things like the difference between SAP namespaces and Customer namespaces....

https://s3.amazonaws.com/notes.basissap.com/sdn/SAP-dev-4-01.png

 

 

but it took Alice only a few minutes to produce

https://s3.amazonaws.com/notes.basissap.com/sdn/SAP-dev-4-02.png

 

 

What do want and when do we want it  ?

Now, as a developer, I'm stuck at simple ABAP procedural reporting, so I'm going to leave any critique about the documentation and training paths that Alice should now follow to some one who knows better. One thing I will say, though, is that while there is a lot of good stuff in the Cross-Technology Developer Center and ABAP Platform Developer Center Community Spaces, there are a lot of places that will confuse the unguided Developer.

 

For example, some documents point Alice at old releases of the ABAP system and other documents and pages appear to be confusing ABAP on HANA with ABAP on MaxDB. Alice started off with the "Develop an on-premise business application with HTML5 & in-memory persistence" tutorial (again with the naming confusion - in-memory persistence ? is this different to database systems ? and does this imply the existence of some kind of out of memory or even out of body persistence ? No wonder people get confused with what happens to your HANA in-memory data when you turn the box off...) and while it talks about in terms of an ABAP on HANA system, the requisite tables for working through this document were also available in her ABAP on Max DB system.

 

However, one problem that the issue with Customer v SAP namespaces raised is that unless Alice jumps through the hoops to become a certified partner, she can't get her own namespace for her developments. What happens if she builds the next 2 Clicks, and her object names clash with something that is already installed at a customer's site ?

 

This leads into code management in general - Fifteen or twenty years ago, the Transport Management System was light years ahead of anything else in change management and control of source code, but modern tools have caught up and passed it by. SAP needs to be open to GIT and Subversion and other repository tools. SAP needs to provide a ABAP client or interface that serializes SAP content to push and pull it from the non ABAP repository, and at the very least integrate with the ABAP in Eclipse tools. In a perfect world, it would also work from within the SAP GUI as well, but modern non SAP Developers won't be using SE80 unless they have to .

 

While we are on the subject of modern tools, despite SAPs flagship accounts being ones where the business runs SAP, the vast majority of customers use SAP for a specific function within their business, and run most of their processing on other software. Integrating SAP systems into other software should be as easy as making a twitter API call. The easier this integration is, the more "Innovation at the Edge" will occur, providing more value for existing SAP customers and increasing the value for new SAP customers. SAP needs to provide a wider range of APIs or pre-configured ODATA interfaces to allow on premise systems in general to integrate better with other systems; everything from Salesforce to monitoring tools like BMC to configuration software like Chef and Puppet.

 

Easy Installation

The most obvious problem that many people identified is that there are "too many step" required to install a Developer Edition. Apart from discouraging potential developers, this also introduces opportunities for error by the installer (by incorrectly performing or missing a step) and by SAP (incorrect links and documentation).

https://s3.amazonaws.com/notes.basissap.com/sdn/SAP-dev-4-06.gif

(from KIDS REACT TO OLD COMPUTERS)

 

In a perfect world, all SAP on-premise systems (whether on a physical server or Amazon, Rackmount, Open Stack, Azure...) should be able to connect and download notes, notes, bug fixes, patches, support packs, upgrades, and apply these, etc. themselves. Just like Windows Update, or "npm update" or "git pull". No Solution Manager, no SAPRouter, no nothing except a HTTP connection to SAP.

 

In a perfect world, installation should consist of running sapinst, filling out the fields and hitting go. With no questions asked after you hit the go button. Checking against a licence or control file would be a good way of ensuring that only the appropriate components are installed on appropriate hardware; for example, a "Developer Edition Licence" would allow installation on any hardware key, but would not install or run the full blown ECC or SRM components.

 

In a perfect "Innovation without disruption" world, the install would also give the option to update our installation to the latest Enhancement Pack automagically (if that is what the installer wants), but that's a bigger issue than a technical upgrade. Anyway, regardless of this, there would be an option to update the DBMS and Operating System to the appropriate patch levels for the current EHP.

 

This is how server and desktop operating systems from Windows to SUSE already work.

 

I understand that making this work would require a bit more control over the target environment than SAP has. For example, if there's an issue with the installation process, where does the blame lie ? With SAP, or the OS vendor or the DBMS vendor ? The only way this could even hope to work is for SAP to own or have some control over the DBMS and the Operating system. Like they do already do with HANA. Like the relationship they have already built with SUSE for the HANA environment. Even if it's not practical for all combinations of Hardware, Operating System and Database system, it's manageable for ABAP on HANA or MaxDB. As an aside, making this one-shot installer only available for ABAP on SUSE on HANA would be useful in marketing ABAP on HANA (make it easier to install HANA / ABAP on SUSE than on any other platform...)

 

In fact the Developer Editions would be an excellent place to start this with, but could we please have the systems in a downloadable form, not tied to a specific cloud platform in a specific location, like the Corporate Network versions of both the NW 7.40 ABAP systems currently are.

 

Easy Documentation

Can we have a simple and accurate path through the process, from a link on sap.com that says in large letters ABAP Developer Editions - no licence fees forever, that goes to a one pager that distinguishes between the on premise systems and other SAP products, and includes the download link and installation instructions for Azure or SUSE 11 (with a pointer to the appropriate SUSE image for Amazon Web Services, Rackmount etc), and a VMWare version (in the appropriate format to allow people to choose either VMWare or Virtualbox).

 

Given that the current (NW 7.4) on premise Developer editions appear to have had some of the traditional post implementation work already done (such as SGEN and Transport Management configuration), why stop there ? For example, I noted that there was no simple way of downloading the SAP GUI from within the Developer Edition that Alice installed. ABAP systems are Web Servers. The User Guide should incoporate a link to http://<ip-address>:50000/sap/bc/gui/sap/its/webgui/! to allow Alice to logon and begin her journey as soon as possible.

https://s3.amazonaws.com/notes.basissap.com/sdn/SAP-dev-4-03.png

 

Another suggestion is to build on the example of the older SAP Developer Editions, which came with a small set of help files that could be configured (ABAP systems are Web Servers) via the icm/HTTP/file_access profile parameter to be accessible via a web browser.

https://s3.amazonaws.com/notes.basissap.com/sdn/SAP-dev-4-04.png

 

Apart from documentation links, this is an appropriate place to include links to the various SAP GUIs included in the system. In the example below, I just copied the files from an older Developer system, but I could include any static html or javascript (including UI5 ...)

https://s3.amazonaws.com/notes.basissap.com/sdn/SAP-dev-4-05.png

 

Easy Information

if SAP want to attract modern developers, they have to be open in spirit not just word. This means that all Developers - freelance, employed by an SAP customer, an official SAP partner or even SAP themselves - must have the same access to howtos, work rounds and patches. Any suggestion that this is not so suggests that SAP are playing favorites among their partners and friends at the big System Integrators.

 

SAP needs to decide what to do with SCN. SAP Support needs to either commit to SCN and properly curate support documentation on SCN or stop pinching community created SCN content to respond to Service Market Place messages and to support basic installations scenarios. They need to be all in or all out. If they are going to leverage SCN then they owe it to the community to return the favor, by making their Service Market Place content (not product downloads) as accessible as SCN is.

 

Summary

I've already been approached by a member of SAPs Developer Relations team who sounds very enthusiastic about changing the process of accessing and installing Developer Editions. I'm taking the opportunity to provide his team with some feedback on what I want to see. Now it's your turn

Actions

Filter Blog

By author:
By date:
By tag: