cancel
Showing results for 
Search instead for 
Did you mean: 

WebDynpro API?

Former Member
0 Kudos

Hello,

I want to build a standard framework for our next WebProjects; so I got some questions:

1. Is it possible to access the Context, UI Element Properties etc at runtime from other platforms, e.g. Programs connected to SAP via librfc32.dll, JCo, normal Dynpros or another WebDynpros.

2. Can I insert JavaScript anywhere in my WebDynpro like in BSP?

3. Is it planned to create an API for capturing Function Keys in WD4A like it is available for WebDynpro for Java?

Accepted Solutions (0)

Answers (3)

Answers (3)

Former Member
0 Kudos

Hi Alfons,

Before going too far, I wanted to clarify, the requests for 1 and 2 and the Web dynpro paradigm.

Firstly, it is not expected that an external tool should be accessing the data with a presentation tool. If the data it has inside is of interest, it should have been retrieved from or about to be writing to an a business object or model. In the case of model, no persistency is actually required.

So the data inside a WDA should not be accessed directly. It should be via a model.

Answer 1 explains a model orientated solution. The model is a shared memory object.

============================================================

<b>Q1. Is it possible to access the Context, UI Element Properties etc at runtime from other platforms, e.g. Programs connected to SAP via librfc32.dll, JCo, normal Dynpros or another WebDynpros.</b>

To access context outside of Webdynpro requires the WEB dynpro to expose the data.

Since the context is a class, traditional JAVA approaches to deserialising class data apply.

You need to traverse a class hierarchy, picking off attributes recursively.

Not hard to do...

Here is some code to traverse the context and build a table to display it.

From another tool, but it serves as a template here.

You can use parts of it to prepare your external model.


METHOD build_context .
  DATA:
     l_api_componentcontroller TYPE REF TO if_wd_component,
     lr_windows_manager TYPE REF TO if_wd_window_manager,
     lr_wdw type REF TO if_wd_window,
     lt_text TYPE string_table,
      node_jockey   TYPE REF TO if_wd_context_node,
      elem_jockey   TYPE REF TO if_wd_context_element,
      stru_jockey   TYPE if_debug_jockey_context=>element_jockey ,
      curr_elem_stru TYPE if_debug_jockey_context=>element_jockey ,
      lv_prev_path  TYPE string,
      lv_parent_node TYPE string,
      lv_parent_elem TYPE string,
      lv_path       TYPE string,
      lv_index      TYPE string,
      lv_lines      TYPE i,

      src_node_info TYPE REF TO if_wd_context_node_info,
      src_attr_set  TYPE wdr_context_attr_info_map,
      src_attr      TYPE wdr_context_attribute_info,
      src_elem_set  TYPE wdr_context_element_set,
      src_elem      TYPE REF TO if_wd_context_element ,
      src_child_node_set TYPE  wdr_context_child_map,
      src_child_node TYPE wdr_context_child.

***************************************************************

  IF ir_node IS BOUND.
  ELSE.
    l_api_componentcontroller = wd_comp_controller->wd_get_api( ).
    lr_windows_manager =
    l_api_componentcontroller->get_window_manager( ).

    APPEND 'Context to debug is not bound.' TO lt_text.
    APPEND 'Use the SHOW_CONTEXT on interface controller' TO lt_text.
    APPEND 'to pass a reference to the Context ' TO lt_text.
    APPEND 'to debug to the debug component.' TO lt_text.
    lr_wdw =  lr_windows_manager->create_popup_to_confirm(
                     text           = lt_text
                     button_kind    = '1'      ).

     lr_wdw->open( ).

    exit.
  ENDIF.




  lv_prev_path = iv_prev_path.
* get the node we use to show data
  node_jockey = wd_context->get_child_node( name = if_debug_jockey_context=>wdctx_jockey ).


*Get the metadata for currently processed node
  src_node_info = ir_node->get_node_info( ).
  src_attr_set  = src_node_info->get_attributes( ).

* BANG the current node in the tree
  CLEAR stru_jockey.
  stru_jockey-name = src_node_info->get_name( ).

  IF lv_prev_path = space.
    stru_jockey-path =  stru_jockey-name.
  ELSE.
    CONCATENATE lv_prev_path '.' stru_jockey-name
       INTO stru_jockey-path.
  ENDIF.


  stru_jockey-parent_path = lv_prev_path.
  stru_jockey-icon = 'ICON_WD_VALUE_NODE'.

*  stru_jockey-ctx_val = '<NODE>'.
  stru_jockey-celldesign = '06'.

  src_elem_set = ir_node->get_elements(  ).
  DESCRIBE TABLE src_elem_set LINES lv_lines.
  IF lv_lines > 0.
    stru_jockey-is_leaf = abap_false.
  ELSE.
    stru_jockey-is_leaf = abap_true.
  ENDIF.

  node_jockey->bind_structure(  new_item            = stru_jockey
                                set_initial_elements = abap_false ).

* record the parent key of node
  lv_parent_node = stru_jockey-path.


  LOOP AT src_elem_set INTO src_elem.
    CLEAR stru_jockey.

    lv_index = sy-tabix.
    stru_jockey-name = '<ELEMENT>'.
    CONCATENATE lv_parent_node '.' lv_index INTO  lv_path.
    CONDENSE lv_path NO-GAPS.


    stru_jockey-path = lv_path.
    stru_jockey-parent_path = lv_parent_node.
    stru_jockey-icon = 'ICON_ELEMENT'.
    stru_jockey-celldesign = '07'.
*    stru_jockey-ctx_val = lv_index.
    DESCRIBE TABLE src_attr_set LINES lv_lines.
    IF lv_lines = 0.
      stru_jockey-is_leaf = abap_false.
    ELSE.
      stru_jockey-is_leaf = abap_false.
    ENDIF.
    node_jockey->bind_structure(  new_item            = stru_jockey
                                 set_initial_elements = abap_false ).

    curr_elem_stru = stru_jockey.

    lv_parent_elem = lv_path.

* add the attributes
    LOOP AT  src_attr_set INTO src_attr.
      lv_index = sy-tabix.
      stru_jockey-parent_path = curr_elem_stru-path.
      CONCATENATE lv_parent_elem '.' src_attr-name
                  INTO stru_jockey-path .

      stru_jockey-name = src_attr-name.
      stru_jockey-is_leaf = abap_true.
      stru_jockey-icon = 'ICON_WD_VALUE_ATTR'.
      stru_jockey-celldesign = '08'.
      stru_jockey-src_element = src_elem.

      src_elem->get_attribute(
        EXPORTING  name   = src_attr-name
         IMPORTING value  =   stru_jockey-ctx_val           ).

     IF stru_jockey-ctx_val is INITIAL.
        stru_jockey-ctx_val = '<initial>'.
     ENDIF.


      node_jockey->bind_structure(  new_item            = stru_jockey
                                   set_initial_elements = abap_false ).


    ENDLOOP.

    src_child_node_set = src_elem->get_child_nodes( ).

    LOOP AT src_child_node_set INTO src_child_node.
      wd_this->build_context(
        ir_node      =   src_child_node-node
        iv_prev_path =   lv_parent_elem   ).

    ENDLOOP.



  ENDLOOP.



ENDMETHOD.

Now You need to expose this data:

Shared memory objects are a way to do this.

A shared memory object is a class, accessible by multiple sessions.

So an RFC or another ABAP can read the data in the this class.

Eg an attribute table on a shared memory object which was built using code similar to above.

The shared memory ABAP objects help is good.

<a href="http://help.sap.com/saphelp_nw2004s/helpdata/en/59/de853f11ed0617e10000000a114084/frameset.htm">Shared Memory Objects</a>

<b>

2. Can I insert JavaScript anywhere in my WebDynpro like in BSP?</b>

No, if you need JAVAscript use BSPs.

Webdynpro is supposed to be client neutral. So fixing it to browsers and JAVAscript

was deliberately avoided.

You can however on exit of an application trigger Javascript.

USeful for specific tasks. Not a solution for embedded javascript in the middle of an Application. See transaction SICF to add exit page javascript. eg to close browser.

<b>3. Is it planned to create an API for capturing Function Keys in WD4A like it is available for WebDynpro for Java? </b>

Im not sure what is approved for development.

regards

Phil

Former Member
0 Kudos

Hello Phil,

can you tell me if (and how) I can access not only the Context of a WebDynpro but also methods of the WebDynpro from external Interfaces? I want to call a refresh-Method via VB.net in a WebDynpro which is embedded in a HTML-Control. Is that possible?

Regards,

S. Voll

Former Member
0 Kudos

Hi Steffen,

it is possible to set the timer UI element, to cause an action,

the action ( which is just a method) can read the content of a shared memory object

or even persisted data to show some updated state.

The web dynpro class could call a web server proxy to call you .net webservice...

But none of this relies on a timer event from the client.

Forcing a HTTP client to accept data is not a simple matter. ( considered a virus attack )

A purpose built client that can be behave a server... Would work.

Perhaps it would be useful to know exactly what you need to do.

<b>A key point here </b>

I see you have a html control embedded in a .net app.

You have therefore FULL control of the client and can indeed trigger a refresh.

However remember the standard refresh implies restart application.

Did you mean trigger a press of a button.?

Your purpose build client would need to do the equivalent of press a button on the form.

This would be possible, But now this is a tricky .net programming question.

I havent attempted such .net programming. google / .net forums may be able to help.

Did that help you understand the task at hand ?

Cheers

Phil.

Former Member
0 Kudos

Hi Phil,

thanks for your very fast response. I'll try your solution with the timer only as a work around when nothing else is working.

To make it clear; I want to implement some sort of function keys, because (as you mentioned already earlier) there isn't a function key API in WD4A (the refresh-Method was a bad example). The concept is to build a framework in VB.net with the function key buttons. When the buttons are pressed I want to call a method which is implemented in the WebDynpro.

Can you think of a way to do that? Is it possible to call the method somehow directly?

Former Member
0 Kudos

Hi Steffen,

I know what you want to do.

Wow thats a lot of effort to get F keys.

The question now becomes, if you are happy to build a purpose built client

in .net, why not do all the presentation there and then call SAP system to get and post data.

Build the masks in .net.

Trying to unwind the HTML/Javascript in an HTTP client on .net, so you can

make the call manually doesnt sound that easy to me.

Did you know you can write a custom service and place it in SICF?

This service can look at simple http post data, Typically in XML format

and return a simple XML response.

It may be easier to write a custom mask, in .net, then have a HTTP client

that just poped calls off to a custom service.

This service can return XML or just strings if thats easier.

Easier is to just expose a web service. Check the blogs on Exposing web services

on an ABAP WAS 7.0 (NW2004s) stack.

But in case you are keen, here is a sample custom service: Ie straight HTTP service

not a web service.


METHOD if_http_extension~handle_request .

  TYPE-POOLS: ixml.   "constants for the CL_IXML factory.

  DATA:
   sflight_tab type flighttab,
   elementname TYPE string,
   fields    TYPE tihttpnvp,
   cdata     TYPE string,
   xdata     TYPE xstring,
   xsrc_data TYPE xstring,
   csrc_data TYPE string,
   dummy_str TYPE string,

   o_ixml             TYPE REF TO if_ixml,          "THE XML factory, see CL_IXML
   o_ostream          TYPE REF TO if_ixml_ostream,  "OUTPUT USE
   o_istream          TYPE REF TO if_ixml_istream,  "INPUT STREAMS
   o_stream_factory   TYPE REF TO if_ixml_stream_factory,   " create the stream types
   o_document         TYPE REF TO if_ixml_document, "An instance of a DOM XML document
   o_parser           TYPE REF TO if_ixml_parser,   " parse rawdata as XML DOM
   o_encoding         TYPE REF TO if_ixml_encoding, " encoding to apply to stream
   o_renderer         TYPE REF TO if_ixml_renderer, "output XML usage
   o_element          TYPE REF TO if_ixml_element,  " an element in XML document
   o_node             TYPE REF TO if_ixml_node,     " a full NODE in an XML doc
   o_nodecoll         TYPE REF TO if_ixml_node_collection. "many nodes





*****************************************************************
  CLASS cl_ixml                  DEFINITION LOAD.

* The source object SERVER is of TYPE CL_HTTP_REQUEST.
* This is a subclass to cL_http_ENTITY.
* we therefore have access to all methods on the entity object.
* This includes CDATA and Cookies etc.
* see the class for more details.

* ********************************
* Begin analysis of the http request.
***********************************

* get the URL name Value pairs.
*
  CALL METHOD server->request->get_form_fields(
              CHANGING fields = fields ).

* get the post data as hex and CHAR

  xsrc_data = server->request->get_raw_message( ).
  csrc_data = server->request->get_cdata( ).


* IF WE KNOW the data posted is in XML format and not a pdf document or
* something like that, then we can process it via the XML factory.

* IN THE CLASS WE MAKE THIS ASSUMPTION. The data is not TESTED as being
* XML before hand.  Please add handling here if you see fit.

* xml CLASS instance VIA static method to get a SINGLETON.
  "private instanciation only. This is our create object equivalent
  o_ixml = cl_ixml=>create( ).

* and now the stream factory is created
* A stream factory knows about hex and C strings, plus table streams
* etc.  NOTE THE APPROACH WORKS VIA REFERENCE TO VARIABLES.
* The C routines in the KERNEL get a handle to the DATA elements
* Subsequent XML factory calls updates our data since we handed over the
* reference to our data !!!!!!  Very fast, but also difficult to follow.
  o_stream_factory = o_ixml->create_stream_factory( ).


* an encoding object is built just in case...
  o_encoding = o_ixml->create_encoding( character_set = 'utf-8'
                                        byte_order    = 0 ).

* the input stream object is associated with our char string.
* we can use the hex equivalent when working with hex data.
* see method create_istream_string if you need to work in hex.
* NOTE csrc_data was fished out of the http_request above.

  o_istream = o_stream_factory->create_istream_cstring( string = csrc_data ).



* parse input document =================================================
* create an XML DOM document instance
  o_document = o_ixml->create_document( ).


* Allocate a parser to our input document
*********************************************************************
  o_parser = o_ixml->create_parser( stream_factory = o_stream_factory
                                  istream  = o_istream
                                  document = o_document ).

* request the stream be parsed.
  o_parser->parse( ).

****************************************
* XML DOCUMENT IS NOW CONSTRUCTED
****************************************

*We can now access nodes etc from the XML data.

*EG get the root element of out XML document.

  o_node = o_document->get_root( ). "
  dummy_str = o_node->get_name( ).


* look at the query interface method on the ELEMENT object,
* now look at the Type-pool above with all the constants.
* All with become much clearer,
* let grab a set of nodes by name.
  elementname = 'FLIGHT_LIST'.  "eg the famous flight list
  o_nodecoll   = o_document->get_elements_by_tag_name( elementname ).
* the first node of the collection please...
  IF NOT o_nodecoll IS INITIAL.
    o_node = o_nodecoll->get_item( index = 0 ).
* using the query trick, get element part of a node.
    TRY.
        o_element ?= o_node->query_interface( ixml_iid_element ).
        dummy_str  = o_element->get_content_as_string( ).
      CATCH cx_root.
    ENDTRY.
  ENDIF.

**************************************
* BUILD THE RESPONSE
**************************************
*
* as an example return SFLIGHT in a table,
* but the catch !!! we buld the result via a transformation
*
  select * from sflight into table sflight_tab.


*
* associate our o_ostream var with output stream
  o_ostream = o_stream_factory->create_ostream_cstring( string = cdata ).

* we could build output XML via an XSLT program.
* now illustrate a way of converting ABAP DATA TO XML via a sample transformation
*  call transformation SXSLTDEMO_FLIGHTS_CONNECTIONS
*        source     sflight_tab = sflight_tab
*        result xml o_ostream.

* but here is one baked by hand.

concatenate
  '<?xml version="1.0"?>'
  '<ROOT>'
  '<MAIN>'
     '<F1>some value</F1>'
     '<F2>some value</F2>'
  '</MAIN>'
 '</ROOT>'
 into cdata.


* response type to XML data

  CALL METHOD server->response->set_header_field(
    name = 'Content-Type'
    value = 'text/xml' ).


* call some transformation to BUILD THE XML outputs



*  call method server->response->set_header_field(
*              name  = 'Expires'
*              value = '0' ).
* see the service ECHO for conversion to UTF-8

* here we set CHARACTER DATA

  CALL METHOD server->response->set_cdata( data = cdata ).



**************************************************************
*  DO YOU WANT TO BUILD XML DATA VIA the XML DOM processor ?
**************************************************************
* Here is a little example
*
*** create output document
**   odocument = ixml->create_document( ).
*** create element 'SenderService' and add it to the document
**
**  MSG_Element = odocument->create_simple_element( name = 'MBGMCR02'
**                                                parent = odocument ).
**
**
**
*** create element 'IDOC BEGIN' and add it to the output document
**
**  IDOC_element = odocument->create_simple_element( name = 'IDOC'
**                                                   parent = msg_Element ).
**
**  IDOC_element->set_attribute( name  = 'BEGIN'
**                               VALUE = '1' ).
**
*** add the first segment, with the parent IDOC.
**  seg_element = odocument->create_simple_element( name = 'E1BP2017_GM_HEAD_01'
**                                                parent = IDOC_Element ).
**  seg_element->set_attribute( name  = 'SEGMENT'
**                              VALUE = '1' ).
**
**
**
**
*** add elements for each tag at this level
*** get a value from the source XML document,
*** we want the string.
**
**  work_text =   me->get_str_from_xml_tag( src_doc = idocument
**                                         elementname = 'PostingDate' ).
**
*** ADD eLEMENT TO OUTPUT DOC,
**  element = odocument->create_simple_element( name = 'PSTNG_DATE'
**                                            value = work_text
**                                            parent = seg_Element ).
**
**
*** DocumentDate
**  work_text =   me->get_str_from_xml_tag( src_doc = idocument
**                                         elementname = 'DocumentDate' ).
**
*** ADD eLEMENT TO OUTPUT DOC,
**  element = odocument->create_simple_element( name = 'DOC_DATE'
**                                            value = work_text
**                                            parent = seg_Element ).
**
**
*** add the second segment, with the parent IDOC.
**  seg_element = odocument->create_simple_element( name = 'E1BP2017_GM_CODE'
**                                                parent = IDOC_Element ).
**  seg_element->set_attribute( name  = 'SEGMENT'
**                              VALUE = '1' ).
**
*** ADD eLEMENT TO OUTPUT DOC,
**  element = odocument->create_simple_element( name = 'GM_CODE'
**                                            value = '05'
**                                            parent = seg_Element ).
**
**
**
**
**
**
**
**** add node to the output document WITH FULL TAG FROM SRC
**** get message content of tag
**** This adds   <tag> value </TAG> to the document.
**** Use this approach where the tag names are the same.
***
***  NODECOLL = o_document->get_elements_by_tag_name( 'DocumentDate' ).
***  outnode = inval->get_item( index = 0 ).
***  rc = msg_ELEMENT->append_child( outnode ).
***
**
**
**
**
**********************************************************
*** render document -
***********************************************************
*** create output stream
**  o_ostream = o_stream_factory->create_ostream_xstring( xdata ).
**
*** create renderer
**  renderer = o_ixml->create_renderer( ostream = o_ostream
**                                      document = o_document ).
**  rc = renderer->render( ).
**
**
*    call method server->response->set_data( data  = xdata ).

ENDMETHOD.

Curious to see which way you go.

Cheers

Phil

Former Member
0 Kudos

1. Yes,

but you need to deserialize class data first.

eg code to take all elements and output in XML.

2. only with attach to response see cl_wd_utilities

or using transaction sicf error pages etc.

If you need javascript use BSP.

3. I hope so. I cant confirm this sorry.

cheers

Phil.

Former Member
0 Kudos

Hi Phil,

thanks for your answers. I searched for further information yesterday evening, but I couldn't find something 😕

Can you give me some example coding or a link to a documentation for 1. + 2.?

Former Member
0 Kudos

> 1. Yes,

> but you need to deserialize class data first.

> eg code to take all elements and output in XML.

>

> 2. only with attach to response see cl_wd_utilities

> or using transaction sicf error pages etc.

> If you need javascript use BSP.

>

> 3. I hope so. I cant confirm this sorry.

>

> cheers

> Phil.

Could someone else provide me with some information?

Former Member
0 Kudos

Hi,

1 I don't know for sure

2 no javascript available

3 i also don't think you can capture the function keys

grtz

Koen