Introduction
A few weeks back there was a discussion on one of the Forums about the Java WebService Navigator application that is present in Netweaver 04. This application shows a tree of all the local Java released webservices. The questions was if there was a way to show the ABAP released WebServices here as well (presently they can be seen in the SAPGui transaction WSADMIN). After some research it appears that this application provided by SAP only displays local Java WebServices. However research on the subject lead me to find out that there is a standard similar to WSDL called WSIL (Web Service Inspection Language) for exposing a directory of WebServices. A nice article on WSIL and the differences between WSIL and UDDI can be found here . True to SAP's approach to support open standards, both the ABAP and J2EE personalities expose their WebServices Directories in the WSIL format (Not to be overlooked, Publishing ABAP WebServices to an External UDDI Server).
Screen Shot of the Java WebService Navigator
!https://weblogs.sdn.sap.com/weblogs/images/1918/J2EE_WSNav.jpg|height=390|alt=image|width=385|src=ht...!
Screen Shot of the ABAP WSADMIN
!https://weblogs.sdn.sap.com/weblogs/images/1918/WSADMIN_Example.jpg|height=345|alt=image|width=567|s...!
Now armed with the knowledge, I set out to create an application that combined the functionality of both the Java WebService Navigator and the ABAP transaction WSADMIN. I decided to build it upon the Open WSIL standard so theoretically it could support a WebService Directory from a Non-SAP system as well (The WSIL definition was co-authored by Microsoft and IBM so I would assume there is built in support in their tools as well). But I also decided to build this application as a BSP, Stateless Model View Controller Program. This approach is built upon the BSP: Stateless Modelbinding - Proof Of Concept put forth by Thomas Ritter a few weeks back. So I will be serializing my Model Class and storing it in Server Cookie to avoid excessive calls to the remote systems to re-gather the WSIL definitions. This example application is also closely tied to the Java WebService Navigator application. Although the display of the WebServices is done in BSP and the WSIL Parsing is done in ABAP, I still launch the Java WebService Test tool for detailed interaction with the WebServices themselves.
Hopefully I have included a enough screen shots and complete code samples so that is application can easily be recreated in anyone's 640 WebAS system (as well as serving as a tutorial for the concepts discussed).
Screen Shot of the Finished Product
!https://weblogs.sdn.sap.com/weblogs/images/1918/BSP_WSNav.jpg|height=323|alt=image|width=515|src=htt...!
Getting the WSIL
The first part to tackle will be about what the WSIL format is and how to get it. Like I said before both the Java and ABAP sides have web endpoints that will deliver a WSIL file. The endpoint for ABAP is /sap/bc/srt/wsil. The endpoint for JAVA is /inspection.wsil. So I started off by just opening my browser to these locations and downloading the WSIL samples for both personalities.
Screen Shot of the ABAP WSIL
!https://weblogs.sdn.sap.com/weblogs/images/1918/ABAP_wsil.jpg|height=332|alt=image|width=596|src=htt...!
Screen Shot of the JAVA WSIL
!https://weblogs.sdn.sap.com/weblogs/images/1918/Java_wsil.jpg|height=390|alt=image|width=581|src=htt...!
Now I know that I can use the HTTP Client Functionality in ABAP to make the same call that my browser just made and retrieve the XML file with the WSIL information. However I want maximum flexibility for maintaining the systems that I will get this information from. Being an old school ABAPer, I naturally turn to my old friend - the configuration table. I setup a customizing table and generated table maintenance for it. This table will hold my destinations and their descriptions. I also decided not to store my connection information in this table. Instead for greater flexibility I will store this information in an RFC Destination (either type G - External HTTP or type H - HTTP Connection to R/3 system) in SM59.
Screen Shot of the Customizing Table
!https://weblogs.sdn.sap.com/weblogs/images/1918/config_table.jpg|height=247|alt=image|width=530|src=...!
Screen Shot of the Customizing Table Sample Data
!https://weblogs.sdn.sap.com/weblogs/images/1918/Config_table_contents.jpg|height=80|alt=image|width=...!
Setting Up the RFC Destinations
Now we come to the point where we must setup the RFC destinations. For both the Java and ABAP connections, I decided to use Type H RFC destinations (HTTP with special features for SAP products). By using type H instead of type G, I am able to set this up as a trusted connection. Therefore the user credentials of the person logged into my BSP application will pass through the HTTP Client call to the destination. Keep inmind that the setup of the RFC (especially the service number) could vary from installation to installation. The service number is effected by the setup of the ICM and the type of system (ABAP+J2EE vs. Standalone J2EE). I have my ABAP personality running on port 80 and the J2EE add-in running on Port 52000 (5XX000 where XX is your system number). However ICM is setup for Java to be the default root handler so I don't need to specify the port number in the RFC connection.
ABAP RFC - Technical Settings
!https://weblogs.sdn.sap.com/weblogs/images/1918/ABAP_RFC_Tech.jpg|height=281|alt=image|width=533|src...!
ABAP RFC - Logon/Security
!https://weblogs.sdn.sap.com/weblogs/images/1918/ABAP_RFC_Logon.jpg|height=397|alt=image|width=533|sr...!
ABAP RFC - Special Options
!https://weblogs.sdn.sap.com/weblogs/images/1918/ABAP_RFC_Special.jpg|height=390|alt=image|width=465|...!
JAVA RFC - Technical Settings
!https://weblogs.sdn.sap.com/weblogs/images/1918/Java_RFC_Tech.jpg|height=298|alt=image|width=536|src...!
JAVA RFC - Logon/Security
!https://weblogs.sdn.sap.com/weblogs/images/1918/Java_RFC_Logon.jpg|height=393|alt=image|width=429|sr...!
JAVA RFC - Special Options
!https://weblogs.sdn.sap.com/weblogs/images/1918/Java_RFC_Special.jpg|height=394|alt=image|width=473|...!
Now that we have the RFCs setup, we can use the RFC test connection to make sure they are working fine. You should see a response somewhat like the following:
!https://weblogs.sdn.sap.com/weblogs/images/1918/ABAP_RFC_Test.jpg|height=326|alt=image|width=516|src...!
The Model Class
This is just personal preference, but I usually start my application by building my model class. I try to finish the model class and test it using the workbench test tool (or a custom test ABAP program) before I even create my BSP application. Therefore that is where I am going to start in this tutorial. We will start by creating a class that inherits from the CL_BSP_MODEL class.
Model Class Properties
.
CLEAR link.
escape '&' to distinguish between WSDL address
and URL of the test page
REPLACE ALL OCCURRENCES OF '&' IN -name.
l_descrp = 'description'.
build url of the testpage
CONCATENATE j2ee_server co_url_wsnavigator '?'
co_param_wsdl '=' receive
exceptions
http_communication_failure = 1
http_invalid_state = 2
http_processing_failed = 3
others = 4.
****Get the response content in Binary format
c_content = client->response->get_cdata( ).
r_content = client->response->get_data( ).
ENDMETHOD.
BSP Controller Methods - do_request
For the most part this is fairly normal high level controller do_request method. The only difference here is the coding for the serialization/deserialization of the model class. Now I took a little different approach than Thomas Ritter had done in his example. I attempt to deserialize my model before I call dispatch input. Therefore my model class is restored before the input binding and event handling. This allows for the integration of the stateless model without further modifications to the normal controller programming. You can also notice that I store away the model class right before calling to my view.
initialize_data( ).
endif.
endif.
****Get a pointer to the Model Object.
model2 ?= get_model( 'MN' ).
if input is available, dispatch this input to subcomponent.
this call is only necessary for toplevel controllers.
( if this is not a toplevel controller or no input is present,
this call returns without any action)
dispatch_input( ).
if any of the controllers has requested a navigation,
do not try to display, but leave current processing
if is_navigation_requested( ) is not initial.
return.
endif.
****Serialize the Model
me->save_model( model2 ).
****Call our View
view = create_view( view_name = 'default.bsp' ).
view->set_attribute( name = 'model' value = model2 ).
call_view( view ).
endmethod.
BSP Controller Methods - save_mode
This method has our logic to serialize our Model class and write it to a server cookie.
METHOD save_model.
*@78QImporting@ I_MODEL TYPE REF TO CL_BSP_MODEL BSP: Model Basis Class
DATA: ostream TYPE string,
xslt_err TYPE REF TO cx_xslt_exception.
serialize model class
TRY.
CALL TRANSFORMATION id
SOURCE model = i_model
RESULT XML ostream.
****Write cookie it into the Server Cookie
cl_bsp_server_side_cookie=>set_server_cookie( name = 'model'
application_name = runtime->application_name
application_namespace = runtime->application_namespace
username = sy-uname
session_id = runtime->session_id
data_name = 'model'
data_value = ostream
expiry_time_rel = '1200' ).
CATCH cx_xslt_exception INTO xslt_err.
ENDTRY.
ENDMETHOD.
BSP Controller Methods - read_mode
Now for just the opposite: we have our method to read our Model from the Server Cookie and deserialize it.
method READ_MODEL.
*@7BQReturning@ VALUE( R_MODEL ) TYPE REF TO CL_BSP_MODEL BSP: Model Basis Class
data: iStream type string,
xslt_err type ref to cx_xslt_exception.
Read Server cookie
call method cl_bsp_server_side_cookie=>get_server_cookie
EXPORTING
name = 'model'
application_name = runtime->application_name
application_namespace = runtime->application_namespace
username = sy-uname
session_id = runtime->session_id
data_name = 'model'
CHANGING
data_value = iStream.
deserialize the Class
if iStream is not initial.
try.
call transformation id
source xml iStream
result model = r_model.
catch cx_xslt_exception into xslt_err.
endtry.
endif.
endmethod.
On 4/27/2005 I created a WebService Navigator Page for ABAP and Java: Part 2 - ABAP Unit that enhances the objects built here by including an ABAP Unit class.
Closing
It almost feels like I set out to see how many different technologies I could combine together into one solution. But that wasn't the intention at all. I really just wanted to create simple tool for displaying webservices from multiple sources. It is just nice to see how all the different technologies that we have at our disposal today can come together to make such a thing possible.