Quantcast
Channel: Web Dynpro ABAP
Viewing all 141 articles
Browse latest View live

Test Scripts for WDA with Selenium - Part 1: Reasoning, Background

$
0
0

About Selenium

Selenium is a free set of tools for testing web applications in the browser. Information, downloads and a good online documentation is available at http://docs.seleniumhq.org/.

 

In short, it allows you to write scripts that will be executed within a browser. There is also a nice add-on for Firefox called Selenium IDE, which enables you to record and edit scripts directly in the browser. You can then also execute the scripts with the add-on.

 

Why This Blog Series?

I tried to use Selenium IDE for our WDA application and did everything in this blog with the Selenium IDE. Later on, I will also try the "real thing" with the Selenium server (called Web Driver) but first I want to do further tests with the IDE. I would also like to try the SeleniumABAP project by Gregor Wolf, see Automate Web Application Testing with Selenium for ABAP.

 

I started from zero and wanted to share my learnings here. Using Selenium for "normal" web applications is of course not new and you will find plenty of information about it with your favorite search engine. WDA, however, has some specialties that make browser scripting tricky:

  1. Almost everything is AJAX. The page is not reloaded when you click somewhere; instead, new page content is loaded from the server with JavaScript. That, of course, is also not unusal in normal web applications. The bigger problem is:
  2. The ID attributes in the HTML code are not stable. That is quite unusual and makes scripting tricky. I will go into more details in the next part. There are some

 

So this blog series is about the question: How do I write test scripts with Selenium for WDA?

 

Why Selenium At All?

Good question ;-) The typical choice for WDA test automation is of course ECATT. Period. There are three reasons why I started looking into Selenium at all:

  1. The systems you work with may not have eCATT enabled. That is (at least for now) the case for us. Since we are using agile development with short iterations and regular releases, however, we urgently need test automation. So we started looking for options.
  2. With a tool like Selenium, it seems easier to cover mixed scenarios, where not everything is Web Dynpro.
  3. Selenium can be used as a client-side tool - so it seems generally easier to start with.

 

As always, it does not solve every problem - I see it as an additional tool in the box.

 

Next?

In part 2, I will start describing how I wrote our scripts in detail. Part 3 adds some advanced things. (At least advanced for me...)

Test Scripts for WDA with Selenium - Part 2: Writing The First Two Scripts

Test Scripts for WDA with Selenium - Part 3: More Advance Stuff With XPath


Test Scripts for WDA with Selenium - Part 2: Writing The First Two Scripts

$
0
0

Introduction

This is part 2 of my experiences with writing test scripts for WDA with Selenium (IDE). The first part is here: Test Scripts for WDA with Selenium - Part 1: Reasoning, Background.

 

A general request: Everything here is my current experience. I am learning as I go. So if you have alternative or better solutions for some of the things, please do not hesitate to comment. I hope to improve the blog as time goes by.

 

The Application

Our application is based on NetWeaver 7.30. It consists of parts using "classic" WDA and also Floorplan Manager for Web Dynpro ABAP. We are not yet complete on Floorplan Manager, that is work in progress. If you are curious about the application itself, see here: SAP's internal solution for Forecast Reporting.

 

The First Script - Load Page and Test if we Arrived

As mentioned is part 1, everything I did so far uses the Selenium IDE. That was the fastest way to get started. To simplify the layout of this blog, I will paste the Selenium commands and parameters as text tables.

 

So, first step is loading the page - that's trivial.

open/sap/bc/webdynpro/sap/<pageID>?sap-language=EN

 

Now we wait until everything is loaded. Already at this point, AJAX strikes. Most of the page content is loaded asynchronously with JavaScript. That's of course nothing special; Selenium has the "waitFor..." commands for that. See here for details.

 

In my script, I want to wait until the "Navigation" block is present on the page.

Capture.PNG

Normally, that is not a big deal. This is the HTML code for the "Navigation" text:

 

<span class=" lsHdArTitle" id="WD2D-titletext">Navigation</span>

 

In any normal web application, you would use the ID "WD2D-titletext" to identify the <span> and the use the waitForElementPresent of waitForText in Selenium to wait until it appears on the screen. In normal language, that means that you wait until that <span> with that text "Navigation" appears. It is the safest check.

 

The problem is: The IDs in WDA are generated and not stable, so I cannot use them and expect the script to run later on. So I cannot do a test for one specific page element with a unique ID. Therefore, I was looking for the next best thing. My approach was to wait for a <span> with the correct text. Using XPath, that is easily possible in Selenium:

waitForElementPresent//span[text()='Navigation']

 

That halts the script until the page has a <span> element with the inner text "Navigation". On top of that, you could script additional checks, like if it really the only <span> with that text, what its position is etc. But at that point, that was enough for me.

 

When executing that script a couple of times, I saw that even this did not guarantee that everything was loaded. Further actions sometimes failed. I suspect that there are still JavaScripts being loaded in the background. I could not identify what exactly I must wait for to be sure that everything is loaded 100%. If anyone knows, please let me know!

 

So I added another short pause:

pause1000

 

Not very elegant - but as mentioned, let me know if you know more.

 

That basically concludes the first script - I just check if the title is right:

assertTitlePage Title

 

Second Script - Everything There?

The second script merely checks if all expected UI elements are there. I used the same technique with XPath as above. Most is pretty basic.

 

We have a few tabs:

Capture.PNG

WDA implements them with <span>, too. For example:

<span class="lsPnstLabelSel" ti="0" tabindex="0" id="WD0140-title">Modules</span>

 

So same thing as before.

waitForElementPresent//span[text()='Modules']

 

On the same page, we also have the general navigation of the Floorplan Manager:

Capture.PNG

WDA implements those with normal links, meaning <a>.

<a href="javascript:void(0);" title="Report Configuration" ti="0" tabindex="0"      class="urLnkChoice urTxtStd urLnkChoiceMnuIco" id="WD021E" lsevents="{}" lsdata="{0:'Report\x20Configuration',1:'Report\x20Configuration',2:true,3:'WD0225',4:'',5:''}"      ct="LNC">     Report Configuration</a>

 

So the XPath is slightly different:

verifyElementPresent//a[text()='Report Catalogue']

As before, this simply checks if there is an <a> present on the screen with the inline text "Report Catalogue".

 

The next challenge was to check for the individual menu entries that hide behind those menus:

Capture.PNG

To make it short: I found no realiable way to script the opening of the menu and then a check on the items. So I used a workaround: The script opens the "Map" view of the navigation:

click//span[text()='Map']

Capture.PNG

So now I could check all entries. WDA uses <a> tags again.

verifyElementPresent//a[text()='New']

 

Next?

Some advanced XPath madness follows in part 3...

Test Scripts for WDA with Selenium - Part 3: More Advance Stuff With XPath

** TEAM WDA **:Configuration, Customizing, Personalization FAQ

$
0
0

What is Configuration, Customizing, Personalization?

Web Dynpro ABAP allows developers, administrators or end users to change parts of the screens.

Configuration

Developers, especially at SAP, would create Configuration data. These are development objects with version management, where-used-list and SNOTE connection. Configuration objects would mostly hold explicit data (see below). The configuration is applied for all users in the system.

Customizing

At customer site data can be changed using Customizing. Customizing is not a development object. In most cases Customizing contains changes to the configuration or implicit data (see below). Customizing is client dependent. We assume that customizing is done in a development system and transported to the productive system.

Personalization

If not prohibited the end user can personalize the application. These are some changes, which are only used for the user himself. The functionality is very limited. Personalization is normally not transported, therefore changed in the productive system itself.
All these adaptations are merged together and applied to the application.

What is the relationship between Application Configuration and Component Configuration?

Application Configuration

An application configuration belongs to the application, a component configuration to the component. That was simple. But how do they belong together?
You can create an application configuration for the application. To call the application with this configuration, just add the URL parameter "sap-wd-configid=<appl_config_name>" to the application URL (or call the application configuration directly from SE80, where you see it as a subobject of the application).
The application configuration consists of some parameters and a hierarchy of the components. Within this hierarchy you can set the component configuration ids. (If the application structure is static, you see the whole component structure, if it is dynamic, like FPM, you see only the topmost components).

Component Configuration

These component configuration ids will then be used to load the component configuration, customizing and personalization.
This means: The URL parameter defines the application configuration, and within this the component configuration id is chosen. The component configurations (and/or customizings and/or personalizations) contain the screen changes.
If you have not defined an application configuration or if you have not set a component configuration id within it, the component configuration ids are generated from the application name and the component hierarchy.

What is Implicit resp. Built-In Adaptation? What is Explicit resp. Component Defined Adaptation?

Some change features are provided for any Web Dynpro Application, like hiding a UI element, reorder the columns of a table (not all tables, but most of them), etc. These adaptations are called implicit or built-in.

 

In some application this is not sufficient. Therefore the developer of the Web Dynpro component enhanced the possibilities. This is explicit or component defined. E.g. the FPM components use explicit configuration extensively.

 

 

What can I do with Built-In Customizing?

With Implicit Customizing you can change data of a Web Dynpro application for all users. The available functionality depends on the UI element type.

 

Start the application with URL parameter "sap-config-mode=X". Use the context menu on the UI element you want to change and select "Settings for current configuration". If you do not see this meu entry, please check your autorization.

 

You can hide each UI element. You can change the labels, set the value of an input field, reorder the sequence of the table columns, modify the number of visible rows in a table, set the width of some UI elements, and so on.

 

In some cases you can add decorative elements to containers (when the layout is matrix, grid, flow or form layout) . When you have added some elements to a data structure, which is used within the context, you can add UI elements displaying these fields to the screen.

 

How can I create / change the Configuration?

To create an application configuration, go to SE80 and select the Web Dynpro application. Then open the context menu and choose "create / change application configuration".

 

A Web Dynpro application is started, where you can enter the name of the application configuration. Please note that the name must be globally unique. When you press "new" or "create" (depending on the release), you should enter detailed information like package, transport request, etc.

On the main screen you can enter the necessary data and press SAVE.

 

Then the application configuration is visible as a subnode to the application in SE80 (press "refresh", if not yet visible). Double click and then you can call the configuration editor from there.

 

To create a component configuration you can use a similar way as with the application configuration, or you can navigate from the application configuration to it. If it does not yet exist, you have the chance to do it there. This is the easiest way.

 

How can I change the Customizing?

If you just want to do some implicit changes, call the application with URL parameter "sap-config-mode=X". If you have the necessary authorization, you can do the changes using the context menu at the UI element you want to change.

 

If you want to do changes, which are not available at runtime, you should start the customizing editor. This is nearly the same as the configuration editor, but the object you are working on, is a different one. Start the confguration editor, and change the name of the application in the URL from "configure_component" to "customize_component".

 

For FPM components: Start the application in customizing mode (see above). Then you see some icons in the top right corner, which you can use to start the customizing editor.

 

How can I change the Personalization?

Personalization are changed just at runtime. If allowed, use the context menu set the visibility of a UI element or set the default value of an input field. Changing the order of table columns is just done via drag and drop.

  

Which authorization is needed?

For Personalization there is no authorization needed.

For Customizing authorization object S_WDR_P13N or development authorization is used.

Configuration is only allowed for users with S_DEVELOP authorization.

 

How can I prohibit Personalization?

You can disallow personalization in general, prohibit only hiding of fields, or exclude changing specific properties.

 

To disallow personalization in general, set the application parameter WDDISABLEUSERPERSONALIZATION to true. This can be done per client (with application WD_GLOBAL_PARAMETERS) or for specific WD applications on the Parameters tab of the application.

 

If you want to allow personalization excluding hiding UI elements, the application parameter WDENABLEUIELEMENTSHIDE can be used. This is set to true be default, but it can be set to false. This functionality is available from 7.31.

 

When there are only some selected properties you want to remove from the personalization list, you can set it to "final" on configuration or customizing level. This is true for explicit and implicit personalization.

 

Which texts are translatable?

Some configuration texts and customizing texts are translatable.

For implicit adaptations those texts are translatable, which are also translatable in Web Dynpro ABAP itself.

For explicit adaptations this is a little bit more difficult, because it depends on the declaration within the configuration context of the component.

 

How can I translate the texts?

Translation is done using the standard translation transaction SE63.

Configuration texts are identified with logical transport object WDCC and the key (use a '*' behind the configuration id).

Customizing texts are found through the table WDY_CONF_USERT2 and the key.

For detailed description please refer to the FPM blog http://scn.sap.com/community/web-dynpro-abap/floorplan-manager/blog/2012/10/04/team-fpm--all-about-translation-and-texts-of-fpm-applications

 

Why am I asked for Access Keys?

From 7.31 on you will be asked for an object access key, if you want to create or change a configuration in the SAP namespace. You also need a developer access key.

This is implemented to remind you of the difference between configuration and customizing. When you change customizing data, no access key is needed.

 

What about FPM?

FPM (Floor Plan Manager) is a development framework built on top of Web Dynpro ABAP. The first version are available with release 7.01, but with 7.02 and especially 7.31 the functionality is extended.

With FPM the applciations consist mainly of feeder classes to access the business logic and WDA configurations to define the UI.

For more information about FPM please change to the FPM community.

 

How can I get an overview of the Configurations, Customizings, Personalizations?

Application configurations

  • You can find application configurations in the Workbench (SE80). They are subnodes of the application, or you can find them in the package, or search in the Repository Information System.
  • In se80 you can also use the Where-Used-List of component configurations to get all application configurations which contain them. (release 7.02 and higher)
  • You can use WD application WD_ANALYZE_CONFIG_APPL to search and display application configurations.

Component configurations

  • Like application configurations you can find them in the Workbench in your package or as a subnode of the component (in most cases). With release 7.31 and higher, you will not only see the organizational data, but also the contents of the configuration.
  • Where-Used-List is also available for component configurations. (release 7.02 and higher).
  • You can use WD application WD_ANALYZE_CONFIG_COMP to search and display component configurations.

Component customizings and personalization

  • Customizings and personalization can be found and displayed with WD application WD_ANALYZE_CONFIG_USER. To find only customizing data, enter a '*' as user name, then press the icon in front of this input field and select "[=] single entry".

 

How can I delete Configurations, Customizings, Personalizations?

Configurations

You can delete configurations in the workbench, in the configuration editor or with wd application WD_ANALYZE_CONFIG_COMP / WD_ANALYZE_CONFIG_APPL.

Customizings

Customizings can be deleted by the administrator with the customizing editor or with WD_ANALYZE_CONFIG_USER.

Personalization

The user can reset the personalization data within the application using the context menu "user settings"->"more"->"reset user settings for Running application".

The administrator can delete the personalization objects using WD_ANALYZE_CONFIG_USER.

How can I analyze, where the values come from?

If you have release 7.31 SP07 or newer, you can use the Runtime Analysis Tool, otherwise you could use the WD_ANALYZE_* applications.

Please see the separate blog about analyzing web dynpro abap adaptations by Michel Seifner http://scn.sap.com/community/web-dynpro-abap/blog/2013/08/08/team-wda--analyzing-web-dynpro-abap-adaptations

 

What are Configuration Enhancements and how can I use them?

Configuration objects can be enhanced using the enhancement framework.

 

There are 2 different implementations depending on teh release.

Release 7.01 and 7.02

In these releases configuration enhancements are configurations with an additional redirection entry. We call then "delegation enhancements". If there is configuration C1 and you create a configuration C2 as an enhancement for it, then you will get C2 whenever you call C1. You can create those enhancement in the configuration editor with function "Enhance". Then a copy of C1 is created and a redirection entry is added.

In newer releases you cannot create such enhancements anymore, but you can change or delete them.

These enhancements are available for application and component configurations.

 

Release 7.31 and higher

In release 7.31 we have implemented "real" enhancements for component configurations (Application enhancements are still the delegation enhancements). These are objects of type ENHO. You create them on the main page of the configuration editor in display mode as with any other enhancement in SE80. These enhancements are only deltas to the original configurations. This way it is possible to have more than one enhancement for one configuration.

When you are in the editor in display mode of a configuration with enhancements, you see the end result (configuration + enhancements). When you go to edit mode, you only see the configuration itself. When changing an enhancement you see the configuration plus enhancement.

 

You can see the enhancement in SE80 in the package. In release 7.40 you see them also as subobjects of the configuration.

You can also see the enhancements in WD_ANALYZE_CONFIG_COMP when you open the popin of the table row showing your configuration.

 

Which changes should be done with which technique?

  • When you create your own application and need configuration, you should use the configuration object. This is especially true for FPM applications,
  • When you want to modify a configuration delivered by SAP, it depends on the kind of changes whether you better use enhancements or customizing. Enhancement are better for larger changes, because you have features like version management, and you can add customiing on top.
  • For minor layout changes customizing is the right way to do it.

 

Can I use Personas to change Web Dynpro Screens?

Currently SAP GUI Personas is only available for SAPGUI Screens

.

Test Scripts for WDA with Selenium - Part 3: More Advance Stuff With XPath

$
0
0

Introduction

This is part 2 of my experiences with writing test scripts for WDA with Selenium (IDE). The first two parts are here:

Test Scripts for WDA with Selenium - Part 1: Reasoning, Background

Test Scripts for WDA with Selenium - Part 2: Writing The First Two Scripts.

 

A general request: Everything here is my current experience. I am learning as I go. So if you have alternative or better solutions for some of the things, please do not hesitate to comment. I hope to improve the blog as time goes by.

 

Third Script - Do The First Clicks

My first two scripts were rather boring because they hardly did anything. They mainly checked for UI elements. This will change now.

 

I had to experience that due to the lack of stable IDs, finding and clicking the right element can be really tricky. I had to experiment a lot. Two sources helped me tremendously:

  1. The XPath reference.
  2. The XPath Checker add-on for Firefox.

 

Without those, I would not have come this far. Reminder: I am new to XPath. But let's start.

 

I call our so-called "Content Selection", which is a "classic" WDA page, meaning no Floorplan Manager. It looks like this:

Capture.PNG

 

These 4 commands call the page from the navigation menu that I showed in part 2:

pause1000
waitForElementPresent//a[text()='New']
click//a[text()='New']
waitForElementPresent//span[contains(text()[2],'Management Journal')]

 

The fourth command is special. What I wanted to do was to wait until the page was loaded. To do that, I wanted to wait for the first menu option, "Management Journal", to appear. That turned out to be difficult because the HTML looks a bit weird. To be honest, that is probably driven by the way we developed that WDA page... Here is the HTML:

<span class="urCLbl urCl1" unselectable="on" f="WD9A" ti="0" tabindex="0" id="WD9A-lbl">     <img align="absmiddle" style="-moz-user-select:none;" class="urRImgOn" src="/sap/public/bc/ur/nw5/1x1.gif" id="WD9A-img">      Management Journal</span>

 

So the text starts with two blanks - but they have an image in between. First I could not find the XPath to identify the <span> that had the text "Management Journal". You find some discussions about XPath and blanks (e.g. here) but none helped.

 

Then I tried using a sub-string like this: //span[contains(text(),'Management Journal')] That XPath basically means: return the <span> that has inline text containing "Management Journal". It did not work.

 

Finally, XPath Checker showed me the problem: Because of the <img> in the middle, the <span> has an array of two texts: The first with " " and the second with " Management Journal". So I had to use the second entry in that entry. Fortunately, XPath can do that with the syntax you see above.

 

That was when I became a friend of XPath...

 

With that little trick, my script could do the next few clicks:

click//span[contains(text()[2],'Management Journal')]
waitForElementPresent//span[contains(text()[2],'FC')]
pause1000
click//span[contains(text()[2],'FC')]

 

And so on... You see the waits for AJAX and the additional pauses. As mentioned, I have not found out how to avoid the pauses.

 

The next commands checked for UI elements etc. Nothing you have not seen in part 2.

 

It Gets Better...

Again, I got stuck soon after. Look at the third column in the screen above. There are several checkboxes. The problem with those was that their texts were not unique. So far, I identified all elements with their unique inline texts. That was no longer possible.

 

So I tried to find an XPath that said: "Look for a <span> with text 'P&L PAC' and return the first <span> containing 'Expense' in its text that comes after". And XPath can do that. The syntax is: //span[text()='P&L PAC']/following::span[contains(text()[2],'Expense')][1]. So there was my next command:

click//span[text()='P&L PAC']/following::span[contains(text()[2],'Expense')][1]

 

After that, I felt lucky. I wanted to try to check if the checkboxes for "Title Page" and "Glossary" in the last column were set. For that you have to know that WDA renders the checkboxes as images with different CSS classes: 'urCImgOn' if selected and 'urCImgOff' if not.

 

So I went for an XPath that looked for the <span> with text "Title Page" and returned the first <img> before it, if it is of class 'urCImgOn'. Also that works. It looks like this:

verifyElementPresent//span[text()='Title Page']/preceding::img[1][@class='urCImgOn']

 

Summary

The rest of my scripts so far use the same concepts described here and in part 2. After seeing how powerful XPath can be, I feel that I should be able to script meaningful tests, even without having fixed IDs.

 

As mentioned, I keep going. If I learn more noteworthy XPath variants, I will add them here. Again, if you see anything that can be done better or easier, please let me know in the comments.

How to find the implementation of an ICF service

$
0
0

It is not trivial to find the coding, that hides behind an HTTP URL for the AS ABAP.

URLs on the AS ABAP need to be published and activated first of all in the service maintenance transaction SICF. Given the URL, you can browse the SICF to the service maintenance screen, lets take for example the implementation of the odata demo service /sap/opu/odata/iwfnd/rmtsampleflight.

sicf rmtsampleflight.png

The URL request to the AS is handled by program SAPMHTTP, which does a lot of the stuff around handling a HTTP request and in the end uses function module HTTP_GET_HANDLER_LIST to get a list of handler classes for all the nodes in the path to the requested service (You can use the FM to get the handler list for a given path, but the output is rather ugly). By looking into the handler list property of the service and its parent nodes in the tree you can find all handler classes, that potentially might apply for this service.

handlerlist rmtsampleflight.pnghandlerlist opu.png

In this example, there is no handler present for the service rmtsampleflight itself, but in its parent node /sap/opu/odata, there is the handler class /IWFND/CL_SODATA_HTTP_HANDLER registered. In this case, this is the only class in all the nodes of the tree to our sample service and thus the only handler class that could possibly be executed. Nevertheless, there could be multiple classes e.g. several nodes in the path have a handler class, or even multiple handler classes are registered in a single node. The execution order of the handler classes seems to be in the following order: from the higher up nodes to the lower nodes in the path, in the numbered order of the handler list within a node (if there are more than one handlers per node). If there are more than one handler, then they will be executed one by one in the order just described, but every handler can control if the remaining handlers will be executed by the value the handler returns in the attribute flow_rc of the interface IF_HTTP_EXTENSION. You can jump to the implementation classes of the handlers by simply double click on the classname in the handler list.

 

So now that you know the handler class, how to proceed with the reverse lookup of the sicf service from here?

 

The good news is that for each request, the interface IF_HTTP_EXTENSION object method HANDLE_REQUEST is called for an instance of the handler class. This gives you an uniform entry point, from were you can go forward and dive into the coding. You can set breakpoints, that are triggered when you perform the HTTP request and nicely debug all the workings on the server.

 

The bad news is that there is no common implementation of what is happening at this point. Each handler class does things in its own way, so you are on your own from there on. By the way you also can write your own handler class, SAP provides some documentation about how to do that in the SAP help, just google for "sap Developing a HTTP Request Handler " and pick a more recent sap help site.

 

For the rmtsampleflight example this means that by debugging you can find out that the odata service is implemented by a complex framework: the Netweaver Gateway in package /IWFND/FRAMEWORK. With some patience you can find the tables where the metadata information about the odata services are stored and from those tables find which reports and thus transactions access them. But more efficient is in fact to look up Netweaver Gateway maintenance and find the transactions from SCN or the documentation. In this case transaction /IWFND/MAINT_SERVICE to manage and register odata services.

Debugging into a HTTP request on AS ABAP

$
0
0

If you want to debug into what is happening in the ABAP application server when you access an HTTP URL on it with your browser, there are several places to set an external breakpoint which will bring up the ABAP debugger for this web request.

 

 

Function module HTTP_DISPATCH_REQUEST line 982 seems to be the first point from where a breakpoint will bring you into the debugger.

debug http_dispatch_request line982.png

At this point, the http handler list is already populated. This is done by call function module HTTP_GET_HANDLER_LIST from line 606 and gives you all the handlers into question for the URL.

debug http_dispatch_request servtbl.png

For this example, there exist 2 handlers for /sab/bc/ui5_ui5.

debug http_dispatch_request handlertbl.png

If you look at the nested handlertbl, you can see the handler implementation classes and the order in which they will be executed to handle the http request.


 

The next point of interest is where the actual call of the http handler is done. This is in class method CL_HTTP_SERVER=>EXECUTE_REQUEST line 627.

debug cl_http_server execute_request line627.png

A bit up in the code, an object instance was created from the http handler class and now the interface method if_http_extension->handle_request is called. From here it is up to the http handler object to proceed with the processing. This may be completely different from one handler to the next, and you can of course implement and register your own http handler class as well.

Note that the handle_request method has to set the flow_rc attribute of the if_http_extension interface with a value that determines if more handlers will be executed or not (if there are multiple handlers registered).

 

As an alternative, you can figure out the handler class for your URL from the transaction SICF and just set a breakpoint in its implementation of method if_http_extension->handle_request or some other place of interest.

 

This is coding for the SAP_BASIS 7.31 SP 7, it may be different on other SPs or releases.

Code Snippet Series: Determining the Client Environment

$
0
0

This post is part of a series on code snippets. The complete list of posts in the series is available in the document Code Snippets: A Blog Series.

 

Knowing the environment in which a Web Dynpro ABAP application is running is necessary if you want to branch logic or show or hide content depending on the client environment. An example is showing the user's logon name in a header or a copyright notice in a footer when the application is running standalone but hiding these view elements when the application is running in the NetWeaver portal.

 

 

   DATA lo_wd_component TYPE REF TO if_wd_component.   DATA lo_wd_application TYPE REF TO if_wd_application.   DATA lv_client_environment TYPE i.   lo_wd_component ?= wd_this->wd_get_api( ).   lo_wd_application = lo_wd_component->get_application( ).   lv_client_environment = lo_wd_application->get_client_environment( ).   CASE lv_client_environment.       WHEN if_wd_application=>co_client_environment-nwbc.
 *     NetWeaver Business Client       WHEN if_wd_application=>co_client_environment-portal.
 *     NetWeaver Portal       WHEN if_wd_application=>co_client_environment-sapgui.
 *     SAPgui       WHEN if_wd_application=>co_client_environment-standalone.
 *     Standalone       WHEN if_wd_application=>co_client_environment-unknown.
 *     Unknown client environment   ENDCASE.

 

If you are on a version of NetWeaver that supports chaining method calls (NW 7.0 EhP 2 or higher), you may skip declaration of the object references.

 

   CASE wd_this->wd_get_api( )->get_application( )->get_client_environment( ).       ...   ENDCASE.


Code Snippet Series: Creating Menu Items Dynamically

$
0
0

This post is part of a series on code snippets. The complete list of posts in the series is available in the document Code Snippets: A Blog Series.

 

In a view's layout, individual MenuItems may be added as child elements to a Menu, ButtonChoice or LinkChoice parent element, but what if the list of menu options is not known at design time? An example is needing to present the user with a ButtonChoice that lists employees who report directly to the user. This list will be different for each user and must be read from a database table, so these menu options cannot be created at design time.

 

The Menu, ButtonChoice or LinkChoice element may be created in the view's layout at design time and its child elements created dynamically at runtime, for example in the view's WDDOINIT hook method. The example below creates MenuActionItems for a ButtonChoice. The same approach may be used to dynamically create menu items for a Menu or LinkChoice UI element.

 

 

   DATA lo_view TYPE REF TO if_wd_view.   DATA lo_buttonchoice TYPE REF TO cl_wd_button_choice.   DATA lo_menuactionitem TYPE REF TO cl_wd_menu_action_item.
 * Get a reference to the ButtonChoice view object   lo_view ?= wd_this->wd_get_api( ).   lo_buttonchoice ?= lo_view->get_element( 'BUTTONCHOICE_ID' ).
 * Add a MenuActionItem to the ButtonChoice for each record in the source data table   LOOP AT lt_data ASSIGNING <data>.       CALL METHOD cl_wd_menu_action_item=>new_menu_action_item           EXPORTING               id               = <data>-id               on_action = 'VIEW_ACTION'   " action to be executed upon selection of the menu item               text            = <data>-text           RECEIVING               control   = lo_menuactionitem.       CALL METHOD lo_buttonchoice->add_choice           EXPORTING               the_choice = lo_menuactionitem.   ENDLOOP. " <data>

Code Snippet Series: Passing Parameters to Web Dynpro from SAPgui

$
0
0

This post is part of a series on code snippets. The complete list of posts in the series is available in the document Code Snippets: A Blog Series.

 

Two steps are needed to pass parameters into a Web Dynpro ABAP application from the SAPgui. First, the SAPgui must construct the URL of the Web Dynpro application and open the URL in a web browser. This step may be done in any ABAP routine.

 

   DATA lv_absolute_url TYPE string.   DATA lv_url                TYPE char255.   DATA ls_parameter    TYPE ihttpnvp.   DATA lt_parameters   TYPE tihttpnvp.
 * Assemble the parameter name/value pairs as needed   ls_parameter-name  = 'param1_name'.   ls_parameter-value  = 'param1_value'.   APPEND ls_parameter TO lt_parameters.   ls_parameter-name  = 'param2_name'.   ls_parameter-value  = 'param2_value'.   APPEND ls_parameter TO lt_parameters.
 * Construct the URL with parameters   cl_wd_utilities=>construct_wd_url(       EXPORTING           application_name = 'WEB_DYNPRO_APPLICATION_NAME'           in_parameters      = lt_parameters       IMPORTING           out_absolute_ur l = lv_absolute_url   ).   lv_url = lv_absolute_url. " cast data type   CALL FUNCTION 'CALL_BROWSER'       EXPORTING           url                    = lv_url           window_name = 'Example: Passing Parameters'           new_window   = abap_true       EXCEPTIONS           OTHERS        = 0.


 

Second, the Web Dynpro application must read the parameters from its URL query string. This step must be done in the HANDLEDEFAULT event handler method of the Web Dynpro application's interface view, i.e., its window.

 

   DATA lt_parameters TYPE tihttpnvp.
* Read URL parameters from the query string   wdevent->get_data(       EXPORTING           name =  if_wd_application=>all_url_parameters       IMPORTING           value = lt_parameters    ).


Internal table LT_PARAMETERS may now be read and the parameter name/value pairs processed as needed by the application.

Enhancements in Web Dynpro ABAP

$
0
0

Enhancements enable us to enhance standard or custom Web Dynpro components by UI or by code. Whatever changes that we make are stored in the enhancement and all changes will be reverted back once the enhancement has been deleted.

There are two types of changes that can be implemented – UI changes and code changes through enhancements.

UI Enhancements

We can enhance both standard and custom web dynpro applications. For ease of explanation I will be enhancing a custom application.

Here is an example of a custom web dynpro application created by me for which I have implemented enhancements.

1.png

I would like to enhance this custom application by creating a new UI element (new input field)

In order to enhance a view in a WD component, navigate to the required view and click on the ico.pngicon.

Untitled.png

 

Enter the name of the enhancement in the pop up that appears.


zenh_3.png

 

Insert the required UI element (Label and input field) into the view and activate the component.

In the following screenshot a new label and an input field has been inserted.

The Active(Enhanced Implemtn ZENH_ZWEB_1 Active) notification on top of the editor tells us that we are currently working on enhancement ZENH_ZWEB_1. One component can have multiple enhancements.

zenh_4.png

 

A new folder Enhancement Implementations has been created. This folder contains information for all the changes that were incorporated in this enhancement.


zenh_5.png


After inserting the UI element you can activate and test the application in the browser. A new label and input has been added to component.


zenh_6.png

Code Enhancements

Now if we want do a code related enhancement to component, navigate to the respective view and re-select the enhance option (ctrl + f4) and choose the enhancement created by you.

zenh_7.png

 

 

Go to the methods tab and observe the new Pre-Exit, Post-Exit and Overwrite Exit that are visible against the standard WD methods.


8.png

 

Click on the create button under the column where you want to write the exit code.

·         Pre-Exit is used to write code which will be executed before the existing method code.

·         Post-Exit is used to write code which will be executed after the existing method code.

·         Overwrite-Exit completely overwrites the previously existed code for that method.

If we were to create a Post-Exit code for WDDOINIT method, click on the create button under the post-exit column. Following screen would appear and the method name would be system generated.

9.png

 

Save and activate the method, the enhanced method will have the enhanced icon instead of the create icon under the post-exit column.


10.png

 

This enhancement technique can be very useful while enhancing standard and custom Web Dynpro components. It helps us to modify standard functionality according to our requirements.

Webdynpro Component Interface

$
0
0

Hi Experts,

 

I am sharing my knowledge on Webdynpro Component Interface.

 

By using the component Interface, We can call multiple components dynamically based on action triggered.

 

In this document , I am calling 4 components dynamically based on action .

 

Steps to follow.

 

1.   Create a table named ZCOUNTRY_COMP.

 

  Create the entries as below

 

 

1.  Create a Webdynpro Component Interface with name 'ZRAO_INTERFACE_TEST' with interface view 'INTERFACE_VIEW'.

 

 

2. Create the 4 compoents with the names 'ZRAO_INTERFACE_COMP1,ZRAO_INTERFACE_COMP2,ZRAO_INTERFACE_COMP3

    and ZRAO_INTERFACE_COMP4'.

 

      Creating component 'ZRAO_INTERFACE_COMP1' as follows.

 

       i.  Delete the default window in ZRAO_INTERFACE_COMP1 and Implement the interface in the component ZRAO_INTERFACE_COMP1'.

           This interface will provide common window named 'INTERFACE_VIEW'.

 

         

 

     ii.  Create a view with UI element caption as below.

          

 

   Follow the above two steps for the another 3 components.( ZRAO_INTERFACE_COMP2, ZRAO_INTERFACE_COMP3, ZRAO_INTERFACE_COMP4 ).

 

 

     

 

    

 

&

   

 

After creating all the 4 components , Create a Main component ZRAO_INTERFACE_MAIN with re-use component

ZRAO_INTERFACE_TEST interface as follows.

 

   

 

3. Create the view with dropdownbyindex with action 'DROPDOWN' and one ViewContainerElement as below.

 

   

 

 

4.  Write the code in Action DROPDOWN .

 

     METHOD onactiondropdown .

   DATA lo_nd_country_comp TYPE REF TO if_wd_context_node.
   DATA lo_el_country_comp TYPE REF TO if_wd_context_element.
   DATA lv_wda_component TYPE string .

* navigate from <CONTEXT> to <COUNTRY_COMP> via lead selection
   lo_nd_country_comp = wd_context->get_child_node( name = wd_this->wdctx_country_comp ).
* get element via lead selection
   lo_el_country_comp = lo_nd_country_comp->get_element( ).

   IF lo_el_country_comp IS NOT INITIAL.
* get single attribute
     lo_el_country_comp->get_attribute(
       EXPORTING
         name 'WDA_COMPONENT'
       IMPORTING
         value = lv_wda_component ).

       DATA lo_cmp_usage TYPE REF TO if_wd_component_usage.
       lo_cmp_usage =   wd_this->wd_cpuse_dynamic_comp1( ).
       IF lo_cmp_usage->has_active_component( ) IS INITIAL.
         lo_cmp_usage->create_component( lv_wda_component ). "Dynamic wda component name.
       ELSE.
         lo_cmp_usage->delete_component( ).
         lo_cmp_usage->create_component( lv_wda_component ). "Dynamic wda component name.
       ENDIF.

       wd_this->wd_get_api( )->do_dynamic_navigation(
         source_window_name = 'ZRAO_INTERFACE_MAIN' "{this is my window name }
         source_vusage_name = 'MAIN_USAGE_0' "{this one is MAIN--"}
         source_plug_name = 'OUT_PLUG1' "{this plug name can be generated dynamically }
         target_component_name = 'ZRAO_INTERFACE_TEST'
         target_component_usage = 'DYNAMIC_COMP1'
         target_view_name = 'INTERFACE_VIEW' "{the view i want to embed}
         target_plug_name = 'DEFAULT'
         target_embedding_position = 'MAIN/VCE' ).

   ENDIF.

ENDMETHOD.

 

 

Finally run the application.

 

 

If we select COMP2 , second component view will trigger.

 

 

 

 

 

Hope it will helpful.

 

 

Best regards,

Rao.

Upload/Read .xlsx file in SAP Web Dynpro

$
0
0

This document explains how to read contents from .xlsx file. It explains reading file contents from .xlsx file by code snippets. Following are the steps explaining the procedure:-

  1. Define a Web Dynpro component with name for example ‘ZZDEV_WD_TEST’.
  2. Define File Upload UI element and a Button UI element in the main view.browse.jpg
  3. Create context node with attributes FILENAME (string), FILETYPE (string), FILECONTENTS (xstring).context.jpg
  4. Bind these to the File Upload UI element. Bind FILECONTENTS to DATA attribute, FILENAME to FILENAME attribute and FILETYPE to MIMETYPE attribute.binding.jpg
  5. Browse the .xlsx file and click on upload button.
  6. On action of upload button read the context node defined in step 3.
  7. Follow below code to read the browsed .xlsx file.

* Internal tables declaration

  DATA:

        lt_worksheets                             TYPE STANDARD TABLE OF string,

        lt_contents                                 TYPE string_table,

        lt_final_contents                          TYPE <target structure table type>.

 

* Structures declarations

  DATA:

        ls_return                                      TYPE bapiret1,

        ls_contents                                  TYPE <target structure>,

        ls_file_upload                               TYPE wd_this->element_file_upload.

 

 

* Local variables declaration

  DATA:

        lv_name                                       TYPE string,

        lv_string                                       TYPE string,

        lv_msg                                         TYPE string,

        lv_flag                                          TYPE boolean,

        lv_message                                  TYPE string.

 

* References declarations

  DATA:

        lref_excel                                     TYPE REF TO cl_fdt_xl_spreadsheet,

        lref_excel_core                             TYPE REF TO cx_fdt_excel_core,

        lref_data                                       TYPE REF TO data,

        lref_dref                                        TYPE REF TO data,

        lo_nd_file_upload                          TYPE REF TO if_wd_context_node,

        lo_el_file_upload                           TYPE REF TO if_wd_context_element.

 

 

* Field symbols declarations

  FIELD-SYMBOLS:

        <fs_table>                                  TYPE table,

        <fs_data>                                   TYPE any,

        <fs_data_str>                              TYPE any,

        <fs_comp>                                 TYPE any,

        <fs_output>                                TYPE string.

 

* navigate from <CONTEXT> to <FILE_UPLOAD> via lead selection

   lo_nd_file_upload = wd_context->get_child_node( name = wd_this->wdctx_file_upload ).

 

* get element via lead selection

   lo_el_file_upload = lo_nd_file_upload->get_element( ).

 

* get all declared attributes

   lo_el_file_upload->get_static_attributes(

     IMPORTING

       static_attributes = ls_file_upload ).

 

  TRY.

*     Create object of class to read .xlsx file contents

      CREATE OBJECT lref_excel

        EXPORTING

          document_name = ls_file_upload-filename

          xdocument         = ls_file_upload-filecontents.

 

    CATCH cx_fdt_excel_core INTO lref_excel_core.

      CLEAR lv_msg.

 

*     Call method to get error message text

      CALL METHOD lref_excel_core->if_message~get_text

        RECEIVING

          result = lv_msg.

*<< Display error message returned in lv_msg >>

      RETURN.

 

  ENDTRY.

 

* Call method to get list of worksheets in the .xlsx file

lref_excel->if_fdt_doc_spreadsheet~get_worksheet_names(

    IMPORTING

      worksheet_names = lt_worksheets ).

 

* Condition to check whether .xlsx file has any active worksheets

  IF lt_worksheets IS NOT INITIAL.

*   Read active worksheet

    READ TABLE lt_worksheets INDEX 1 INTO lv_ws_name.

  ELSE.

*<< Display error message >>

    RETURN.

 

  ENDIF.

 

* Get reference of .xlsx file contents in the active worksheet

  lref_data = lref_excel->if_fdt_doc_spreadsheet~get_itab_from_worksheet( lv_name).

 

* Fetch all records in the active worksheet

  ASSIGN lref_data->* TO <fs_table>.

 

* Prepare exporting table with .xlsx file contents

  IF <fs_table> IS NOT ASSIGNED.

*<< Display error message >>

    RETURN.

  ENDIF.

 

* Loop dynamic table to prepare final table contents to pass in exporting parameter

  LOOP AT <fs_table> ASSIGNING <fs_data>.

*   Initialize flag

    lv_flag = abap_true.

 

    WHILE lv_flag = abap_true.

*     Read columnwise entries

      ASSIGN COMPONENT sy-index OF STRUCTURE <fs_data> TO <fs_comp>.

      IF <fs_comp> IS NOT ASSIGNED.

        lv_flag = abap_false.

*       Exit the loop when a row ends

        EXIT.

      ELSE.

*       Concatenate each cell data in a row into string seperated by '||'

        CONCATENATE lv_string <fs_comp> INTO lv_string SEPARATED BY '||'.

 

      ENDIF.

 

*     Unassign field symbol

      UNASSIGN <fs_comp>.

 

    ENDWHILE.

 

*   Shift final string having a row left by 2 places to remove leading '||'

    SHIFT lv_string LEFT BY 2 PLACES.

 

*   Append prepared row data to exporting parameter

    APPEND lv_string TO lt_contents.

 

*   Clear variable having row data

    CLEAR lv_string.

 

  ENDLOOP.

 

*   Loop internal table to split records and fill in target internal table

    LOOP AT lt_contents ASSIGNING <fs_output>.

*     Split file contents returned at '||'

      SPLIT <fs_output>

        AT '||'      

        INTO ls_contents-col1

    ls_contents-col2

    ls_contents-col3……..

*     Append split records in internal table

      APPEND ls_contents TO lt_final_contents.

 

    ENDLOOP.

 

   7. Contents will be appended to internal table LT_FINAL_CONTENTS. Define a structure in SE11 with fields corresponding to upload file structure and declare                           LS_CONTENTS of this type. Define a table type in SE11 with this structure and declare LT_FINAL_CONTENTS of this type.

   8. Finally LT_FINAL_CONTENTS will have all the records present in the browsed .xlsx file.

 

Hope this solves reading file contents from .xlsx file.

Eureka - FPM ( Floor Plan Manager ) is so simple - Part 2 ( Not Anymore )

$
0
0

Welcome back.

 

Continuing from my blog - Eureka - FPM ( Floor Plan Manager ) is so simple, today was the second session in the FPM.

 

Today the topic of discussion was the role and implementation of feeder classes in FPM.

 

The concepts addressed today were as follows:

 

The User Interface Building Block ( UIBB ), in the FPM - FLUID editor for the component configuration can be provided with view - freestyle view using Web Dynpro component ( briefly introduced in the steps 5 in my previous blog) OR through feeder classes implementing relevant GUIBB ( Generic UIBB ) classes.

 

FPM provides generic WD components for FORM, LIST, TABBED etc. Ex: FPM_FORM_UIBB.

 

Steps to design the view using the feeder classes, are as follows:

 

1. Open the suitable, generic WD Component - FPM_FORM_UIBB - SE80

uibb_1.PNG

2. Create a Component configuration in the component and give a custom name.

 

3. The FLUID designer will prompt for a feeder class

 

          3.1 Create a custom class SE24

 

          3.2 Implement the feeder interface for form - IF_FPM_GUIBB_FORM.

guibb_1.PNG

          3.3. Implement the following methods:

                    GET_DEFINITION - To descibe the structure i.e. fields and buttons and events, to be made available in the screen / UIBB

                    GET_DATA - Populate the data to the fields in the screen

                    PROCESS_EVENT - Handle the events defined in the definition using the event ID.

 

4. Fill the name of the feeder class with the newly created custom feeder class.

 

5. The FLUID ( Flexible UI Designer ) editor will open a Excel type of designer screen.

 

6. Open the properties panel which lists the elements defined int he GET_DEFINITION method in the feeder class

 

7. Drag and drop the relevant elements and button onto screen.

 

     Note: The properties - visual only can be modified in this editor and will override the property defined in the method

               Also, there is no restriction of Layout(matrix,grid etc.) in the screen design.

 

8. Save the configurations

 

9. Provide the FORM name and newly created configuration name in the FUILD editor of the component configuration created in the step 3 of my previous blog.

 

You can modify the view layout i.e. order of the appearance of UIBBs in the preview. Also, add more UIBBs, if necessary.

 

The execution of the main configuration, shows the screen with the UIBB defined.

 

Note, the execution of the methods in the feeder classes follows the FPM Phase Model concept( This is something of an amalgamation of WD Phase model and FPM eventing - Right now, I have little info regarding it.)

 

Tip: If a view contains more than 1 UIBB, then on event the PROCESS_EVENT method of all the UIBBs are invoked by the framework. Hence it is performance intensive and developer has to be very careful in the handling of events.

 

The FPM Apis can be used, in case the view navigation is to handled at the FPM level ex: if one UIBB event should trigger a view navigation from view 1 to view 2.

 

To summarize, the structuring of the components in FPM is done with a noble intention to promote better development practice. However, it is quite restrictive on the developer. It seems like SAP - FPM has decided what is the best option. Hence, discouraging any scope of manipulation. Also, the process of designing the fields using the FLUID screen designer seemed clumsy and property control at multiple points ( at feeder class level, at fluid editor level, at fpm config level etc. ) makes it difficult to track the changes.

 

But, Its also a good practice to think of the variables and handle them in definition thus reducing the code and promoting re-usability.

 

Looking forward for the next class or may be an opportunity to work on FPM.

 

Thank you one and all.

 

Regards,

Sharath

Build a Simple Web Dynpro ABAP Application, Navigation (PART 1)

$
0
0

 

This Tutorial is the first tutorial from a series of Web Dynpro Basic tutorials. This shows how you can navigate from a View to another View, by creating the Outbound and Inbound plugs and also creating the Navigation Links.

Build a Simple Web Dynpro ABAP Application, Transport Data Context Component Controller (PART 2)

$
0
0

 

This second tutorial shows how you can play with the data between 2 different views with binding to the View component controller and also read the data from the Component Controller in a View, which plays a role like the session in J2EE, where you can store data.


Build a Simple Web Dynpro ABAP Application, Assistance Class, Message Manager(PART 3)

$
0
0

 

This tutorial explains how you can Use the Assistance Class and also the getText Method of the Assistance Class. It also shows us how to use the Message manager and how you can store it in a global referrence of the component controller or in the assistance class to use it then in any controller.

Build a Simple Web Dynpro ABAP Application, Service Call Create Context Node Automatically (PART 4)

$
0
0

 

This tutorial shows how you can use the Service Call Wizard, which creates  automatically the node accordingly to the Function Module Signature. You can also use a method or you can create an attribute in the Component Controller, not just a Node. It also creates the call of the method.

Build a Simple Web Dynpro ABAP Application, Web Dynpro Event Handling, Context Menu (PART 5)

$
0
0

 

This tutorial shows how to create a context menu, how to assign it to a part of the View, in our case to the table. It also shows how to raise a Web Dynpro Event and how to handle it.

Build a Simple Web Dynpro ABAP ,Config Controller, Component, Application Configuration (PART 6)

$
0
0

 

This tutorial shows how to create a Custom Controller, than change it to a Configuration Controller, Create a Component Configuration, than create a Application Configuration, assign the Component Configuration to the Application Configuration. Last step, assign the Application Configuration to the Web Dynpro Application. This way you make modifications that are visible to all users.

Build a Simple Web Dynpro ABAP, Data Node Binding,Table Binding (PART 7)

$
0
0

 

This tutorial shows how you can fill data in the Component Controller, which is like a global place, where you can transport the data and to use it in another Views. Also do a Binding Table and fill the table with data from the Context Node which has a Cardinality from 0..n.

Viewing all 141 articles
Browse latest View live


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