WebService Navigator Page for ABAP and Java
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
Screen Shot of the ABAP WSADMIN
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
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
Screen Shot of the JAVA WSIL
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
Screen Shot of the Customizing Table Sample Data
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
ABAP RFC – Logon/Security
ABAP RFC – Special Options
JAVA RFC – Technical Settings
JAVA RFC – Logon/Security
JAVA RFC – Special Options
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:
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.
method do_request. data: view type ref to if_bsp_page. data: model1 type ref to zcl_bsp_m_ws_navigator. data: model2 type ref to zcl_bsp_m_ws_navigator.****Get a pointer to the Model Object. model1 ?= get_model( ‘MN’ ). if model1 is initial. model1 ?= me->read_model( ). if model1 is not initial. model1->if_bsp_model~init( id = ‘MN’ owner = me ). me->set_model( model_id = ‘MN’ model_instance = model1 ). else. model1 ?= create_model( model_id = ‘MN’ class_name = ‘ZCL_BSP_M_WS_NAVIGATOR’ ). model1->
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.
Thanks Thomas!!!!
I think you showed us how every BSP application should be built (Build modelclass -> test it -> build UI -> test it -> done). I would call it a "best practise" application 😉
Some thoughts:
-Jep, restoring the model before invoking the dispatch_input() method is the way to go. Didn't think about that.
-Why do you test your modelclass with the workbench tool? Build some unit tests instead which can repeat everytime you want =)
-How do you clean up the old cookies?
-I would place the read and save model methods into a untility class. I am pretty sure you will need this code again.
-Thanks for the xml parser code. I thought about how parsing can be done with ABAP at sdn meets labs (I normally use java for this kind of stuff) because Craig told me some nice ideas for building rss feeds.
regards
Thomas
--brian
Q. Why do you test your model class with the workbench tool? Build some unit tests instead which can repeat everytime you want
A. Old habits die hard. Now that I am on 640 I need to spend sometime and explore ABAP Unit. Actually for some more complex model classes I have in the past built reusable custom ABAP programs for testing. I can then repeat the tests. However this was a relativly simple class so I just tested using the workbench tool.
Q. How do you clean up the old cookies?
A. If you are going to work with Server Cookies in BSP, there are two very important programs you should know about. The first is BSP_SHOW_SERVER_COOKIES. This is nice report on all Server Cookies. The other program is BSP_CLEAN_UP_SERVER_COOKIES. This will delete up all your expired Server Cookies. I have this scheduled to run once a day (since it only works off the expire date and doesn't take time into account). This is sort of a lazy way out. If I had thousands of simultanous users, I would probably want to come up with a better routine. But right now, my cookie table just doesn't get big enough to justify the effort.
Q. I would place the read and save model methods into a untility class. I am pretty sure you will need this code again.
A. Actually I have that. I have a little controller class framework of my own that inherits from CL_BSP_CONTROLLER2. My actual controllers usually inherit from these classes instead of the SAP ones. I have several reusable methods built into my classes. I recently added the model read and save to this framework. However this weblog was already getting fairly complicated and I didn't want to throw in two many more elements that had to be created from my system. That is why you rarely see my controller classes (and I actually have the same for application classes and models) mentioned in my weblogs. I try to avoid too much "bagage" so that people can hopefully recreate the examples in their systems.