Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
Showing results for 
Search instead for 
Did you mean: 
Active Participant

The Requirement

I recently had a requirement to embed a web based map within a Web Dynpro application to search for customers and display markers for each result found on the map.  I know there is an existing component for mapping but it's a little bit restrictive in some areas and not in line with our organisations grand plan.  Suffice to say we opted against using it and decided on Leaflet.js.  It's OpenSource and free from any vendor specific lock in (I.e. Nokia, Google, ESRI, etc).

The Approach

The only way for us to achieve integration with a Javascript based web map with a Web Dynpro application in NW 7.3 is via a BSP application embedded with an IFrame (but from NW 7.4 it may be possible with HTML5 integration but I've not tried it).

IFrames have long been a contentious subject in web development.  Most developers believe them to be evil and quick search in google can point you to a fair few posts around this. Things were so bad SAP banished them from ABAP WD (I don't know the version this happened from) deprecating it's from the language.  However in relatively recent turn of events the IFrame is back and from NW 7.03 and you can use them without fear of persecution (well almost).

But what about security?

In terms of security the web map has the same origin and can utilise the same authentication procedures as the Web Dynpro Application it is embedded in.

OK. But how can I react to the search event?

Now the SAP Help states that an IFrame should be used with caution, as the WebDynpro and the embedded content are effectively two independent applications.  Take a look at the SAP Help for more info.

IFrame -  Web Dynpro ABAP - SAP Library

As such you cannot really react to events raised from the Web Dynpro within the embedded IFrame.  You can however re-call the page, which will result in the page being rebuilt.  This may sound terrible, but bare in mind that depending on the type of content being loaded on the page , a lot of the static content should be cached after the first load, so subsequent reloads may not be so costly. 

On a side note as of NW 7.4 WebSockets support was introduced to ABAP.  In theory I believe it should be possible to use this to react to events triggered in ABAP within Javascript.  Unfortunately it's something I have not had a chance to try out, but hopefully in the next evolution of this it will happen....

I can't get the page to reload...

Yep. After looking at the APIs and searching the forums I could not find a way to trigger an IFrame refresh within the standard WebDynpro APIs. I'm not sure why this is not possible, but hey, that's just the way it is.  Thankfully there is a simple work around.

All you need to do is pass a changing request parameter in the IFrame URI for the BSP Web Map. This forces the framework and thus the browser into thinking the content has changed and results in the page refreshing.  I used a simple counter in the Web Dynpro code I wrote to get the URI for the map, that increments each time the search results were updated.

Please note nothing in the code for the BSP web map reacts to this additional parameter and as such it has no effect on the actual application processing.

METHOD get_map_uri.

  DATA: l_url         TYPE agr_url2,

        l_counter     TYPE char10,

        lt_url_params TYPE tihttpnvp,

        lo_bsp_runtime TYPE REF TO cl_bsp_runtime.

  FIELD-SYMBOLS: <http_param> TYPE ihttpnvp.

  APPEND INITIAL LINE TO lt_url_params ASSIGNING <http_param>.

  <http_param>-name = 'view'.

  <http_param>-value = 'AddressSearch'.

  APPEND INITIAL LINE TO lt_url_params ASSIGNING <http_param>.

  <http_param>-name = 'gui'.

  <http_param>-value = 'webdynpro'.

  " Add the optional sessionId param if passed

  IF im_session_id IS NOT INITIAL.

    APPEND INITIAL LINE TO lt_url_params ASSIGNING <http_param>.

    <http_param>-name = 's'.

    <http_param>-value = im_session_id.


  " Added a counter to fudge url param and trigger refresh of iframe, which works

  wd_this->g_counter = wd_this->g_counter + 1.

  l_counter = wd_this->g_counter.

  CONDENSE l_counter.

  APPEND INITIAL LINE TO lt_url_params ASSIGNING <http_param>.

  <http_param>-name = 'c'.

  <http_param>-value = l_counter.

  " Currently defaulting this to HTTPS but need a better way to identify this

  cl_bsp_runtime=>if_bsp_runtime~construct_bsp_url( EXPORTING    in_protocol = 'HTTP'

                                                                 in_application = 'ZEI_MAP'

                                                                 in_page = 'START.HTM'

                                                                 in_parameters = lt_url_params

                                                       IMPORTING out_abs_url = re_map_uri  ).


And then there is the session handling...

So how can I access the search results in my map from the WebDynpro each time the search results change.

At this point I should probably point out that I wrote a set of Restful APIs using BSP to generate GeoJSON that can be consumed by the web based map. For now that is all a little off topic for this blog and a much bigger subject in itself, as we need throw in a mix of Javascript, BSP, XML, JSON, HTTP and Simple Transformations to make it happen.  The basis for the APIs I created was learnt from this great blog Developing a REST API in ABAP by rdiger.plantiko , which is a must read for anyone working in this space.  I learnt a lot about the low level interactions of the client and server, which proves invaluable in developing JS based web apps.

So let's get back on track..I don't want to embed a heap of content into the request body of the map URI called from the Web Dynpro only to then push the same content back to the server in a follow up request to retrieve the actual map data for obvious reasons.  Instead to get the search results map data I used something called server side cookies. 

They have actually been around for ages, but I only recently discovered they existed thanks to the main man of ABAP thomas.jung who mentioned it in a forum post.  These little gems can be used to store and retrieve large datasets on the server, independent of the session and persist them up until a specified expiry time has passed or can be explicitly deleted.  They are also super easy to implement. 

Server-Side Cookies and Data Persistency (SAP Library - Business Server Pages)

Two important fields for a server side cookie are the session ID and user ID and both must be specified when creating and retrieving them.

To get a unique session ID for my current WD application session I make a call to function module TH_GET_SESSION_ID. I subsequently use this session id to set my server side cookie for the authenticated user.  Next I set the URI of the IFrame to the web based map and also pass this session id as request parameter. 

In the web map I have some javascript code to retrieve the session id from the application request URI. I finally make the call to the Restful APIs to GET the map content and again pass this same session id as a request parameter.  Using the session ID and the user ID of the authenticated user (which is the same user as was authenticated by the Web Dynpro) I am able to retrieve the server side cookie containing the search results and use this to create the map data to pass back to the embedded web map.

Note that when setting the time a server side cookie be realistic.  Don't set huge timeouts.  In my scenario, nobody is going to click a button and wait for a response greater than one minute.  So persisting the server side cookies any longer than that makes no sense. 

The Conclusion

Things are not so bad with the old IFrames if used responsibly.  You'll be surprised at what you can achieve.

Here is a pic of the map I created and embedded within a WebDynpro ABAP FPM based search for addresses.  The map zooms to best dimensions to display all the search results on the map, each time a search is triggered.

It works nicely in Chrome, Firefox, Safari and with a little extra work on the Javascript side also works in IE (SAP dropped an IE7 compatibility mode bombsell setting in the page header, which causes havoc with JS as a lot of functionality was not around then).

1 Comment
Labels in this area