Introduction
You might be thinking: how is consuming WebServices in ABAP really related to BSP. Is it because the WebAS and the ICM (Internet Communication Manager) are at the core of both technologies? Or perhaps it is because you might describe Consuming WebServices in ABAP as BSP turned inside out? When it comes right down to it, I included this in BSP Weblog because for me using WebServices just goes hand-in-hand with the applications that I happen to be developing in BSP. But don't feel that this technology is limited to BSP. In fact all the samples I am going to share today run within good old traditional ABAP. There is even one with - gasp - just plain List Output (talk about combining old technology with new!).
Release 620
First off there is no easy, good way of consuming SOAP WebServices in 620. There is a client API realized as an ABAP Class Library. But if you read the SOAP Processor section on the service marketplace , you see that this method in 620 is basically incompatible with release 640. You have to work directly with the SOAP request at a fairly low level in the 620 API because proxy generation is not supported. All this and then you read the statement:
applications based on this interface therefore will face a considerable migration workload. Automatic conversion will not be possible.
Well that was enough to convince me to wait until 640 for full SOAP WebServices.
Coding
We are ready to look at the coding now. We will break it down into little parts so that is can be easily digested. First I implemented this functionality as a function module so that it can be called via RFC from our 46C R/3 system. I take in the SMS number, the Message Class, the Message, and the Priority as importing parameters. I then pass back the unique SMS confirmation number, the status and the entire HTTP response as a string.
*"----
""Local interface:
*" IMPORTING
*" VALUE(SMS_NUMBER) TYPE AD_PAGNMBR
*" VALUE(CLASS) TYPE CHAR1 DEFAULT 1
*" VALUE(MESSAGE) TYPE STRING
*" VALUE(PRIORITY) TYPE CHAR1 DEFAULT 3
*" EXPORTING
*" VALUE(SMS_ID) TYPE ZZES_SMS_ID
*" VALUE(STATUS) TYPE ZZES_SMS_RESULT_STATUS
*" VALUE(P_CONTENT) TYPE STRING
*" EXCEPTIONS
*" MESSAGE_TOO_LONG
*" UNKNOWN_ERROR
*"----
I wanted to make it easy to support different SMS providers or to make changes to the URL and SSL_ID; so ended up setting up everything in a configuration table.
!https://weblogs.sdn.sap.com/weblogs/images/1918/SMS_Config.jpg|height=122|alt=image|width=595|src=ht...!
So we can then start of function module with a little bit of code to read the configuration settings from the config table.
Next up I want to perform some checks on the input data. First I will check to make sure the message isn't too long. Next up I want to check for Polish Characters. Even though we are going through a Polish SMS provider, they asked us not to send any Polish National Characters. So we will use some SAP function modules to check the codepage of the string and then transliterate any national characters back to ASCII7. Finally we will replace any + in the SMS number and remove any spaces.
Next up is where things get really interesting. We will build our full Request URL by adding on all of the outbound parameters. We create the client object for this URL.
Next up we set our request type to 'GET' and start the HTTP communications.
Now we are ready to receive the response back. We read it in character format. We then pull out the return parameters from this response block.
In the end we have fairly simple approach to what could have been a complex problem. We leverage the ability of the WebAS to act as an HTTP client and create an end result that functions very much like a WebService.
Release 640
If you really had your heart set on consuming SOAP WebServices from ABAP, you aren't out of luck. WebAS 640 comes along and makes the process relatively painless by offering the ability to generate proxy classes. Since this technology is so new, I thought I might just build and walkthough a complete example here. I wanted to use a public webservice that was available for free for several reasons. First I wanted to demonstrate how flexible the technology was. Second I wanted anyone with a 640 system to be able to recreate the steps in this weblog on their own with the same webservice. I found a nice collection of webservices at the following web address: www.xmethods.com . I finally decided upon a simple service that returns book information when given an ISBN. It even gives us the current price of the book at several on-line retailers. The Service Description can be found here: http://www.winisp.net/cheeso/books/books.asmx .
Now that we have our webservice picked out, we are ready to generate our ABAP Proxy. To get the process started, we turn to our old friend SE80. From the Enterprise Services Tab, we are going to select Client Proxy and then hit create.
!https://weblogs.sdn.sap.com/weblogs/images/1918/WSC1.jpg|height=257|alt=image|width=421|src=https://...!
Next up we have to choose where our WSDL file is going to come from. We could connect directly to a UDDI server or XI repository and query for our object. Or we might have saved the WSDL definition to a file on our local machine. But in this case we are going to connect directly to the WSDL definition using the URL that we got from our on-line search.
!https://weblogs.sdn.sap.com/weblogs/images/1918/WSC2.jpg|height=149|alt=image|width=197|src=https://...!
!https://weblogs.sdn.sap.com/weblogs/images/1918/WSC3.jpg|height=131|alt=image|width=440|src=https://...!
Now we are asked what Package (Development Class for those you upgrading from 46C or lower) we want to place the generated object in as well as what prefix we want to use. I'm just playing around so I am going to make the object Local Private by putting in my $TMP package. To follow SAP naming standards, as well as my company's standards, I will get the object a prefix of ZES_ (In case you are wondering - the object starts with Z to follow SAP's naming standard for customer development. The next letter E standard for Electronics - the division I work for. Finally the S stands for Basis - the application area that this development belongs to.)
!https://weblogs.sdn.sap.com/weblogs/images/1918/WSC4.jpg|height=109|alt=image|width=393|src=https://...!
We have our generated Client Proxy. The following are some screen shots of what this should look like in SE80. You can see that not only do we have an ABAP class, but the process also generated structures and table types to represent all the importing and exporting data.
!https://weblogs.sdn.sap.com/weblogs/images/1918/WSC5.jpg|height=399|alt=image|width=573|src=https://...!
!https://weblogs.sdn.sap.com/weblogs/images/1918/WSC7.jpg|height=398|alt=image|width=598|src=https://...!
There is only one last thing we need to do to our Client Proxy before we are ready to use it: we need to configure a Logical Port for it. We can do this in transaction LPCONFIG. We can configure more than one Logical Port and specify the one we want at runtime. However for this solution we will just configure one port and make it the default.
!https://weblogs.sdn.sap.com/weblogs/images/1918/WSC8.jpg|height=190|alt=image|width=426|src=https://...!
Inside the definition of the Logical Port we can adjust settings for the Client Proxy such as the URL we going to call, the logging, State Management, etc. Since this is the default Logical Port, we will just save it with all the settings that were imported from the WSDL definition.
!https://weblogs.sdn.sap.com/weblogs/images/1918/WSC9.jpg|height=355|alt=image|width=473|src=https://...!
We can then return to SE80 and perform a test on the WebService by hitting F8. We then get a dialog that allows us to set parameters for our test.
!https://weblogs.sdn.sap.com/weblogs/images/1918/WSC10.jpg|height=397|alt=image|width=486|src=https:/...!
We then choose which method we want to invoke. We are going to be using the GET_INFO method later in our example, so let's test that.
!https://weblogs.sdn.sap.com/weblogs/images/1918/WSC11.jpg|height=232|alt=image|width=462|src=https:/...!
Hopefully you get a success message like the following:
Once everything checks out OK in the test tool, we are ready to start programming against our Client Proxy. The following program example has one parameter for supplying the ISBN. We then take this parameter and use it to fill out the request object for our Client Proxy. After the call to the Client Proxy, all the returned data is contained in our response object. The response object has the format of the generated table types and structures as defined in the WSDL file. We can loop through this data and process as we see fit. For this case we are just going to output a simple ABAP list.
PARAMETER: p_isbn(100) TYPE c OBLIGATORY.
DATA:
Reference variables for proxy and exception class
lo_clientproxy TYPE REF TO zes_co_looky_book_service_soap,
lo_sys_exception TYPE REF TO cx_ai_system_fault,
Structures to set and get message content
ls_request TYPE zes_get_info_soap_in,
ls_response TYPE zes_get_info_soap_out.
****Set the input parameter ISBN into the Request of the SOAP Object
ls_request-isbn = p_isbn.
****Create the Proxy and Clall it.
CREATE OBJECT lo_clientproxy.
TRY.
CALL METHOD lo_clientproxy->get_info
EXPORTING
input = ls_request
IMPORTING
output = ls_response.
CATCH cx_ai_system_fault INTO lo_sys_exception.
Error handling
ENDTRY.
COMMIT WORK.
****Write Out the Basic Information
WRITE: / 'ISBN:', ls_response-get_info_result-isbn.
WRITE: / 'Title: ', ls_response-get_info_result-title.
WRITE: / 'Author: ', ls_response-get_info_result-author.
WRITE: / 'Publish Date: ', ls_response-get_info_result-pubdate.
WRITE: / 'Publisher: ', ls_response-get_info_result-publisher.
WRITE: / 'Format: ', ls_response-get_info_result-format.
****Loop through the listing of Vendor Prices and output each one
FIELD-SYMBOLS
What I showed you here today is the tip of the iceberg for this technology. The possibilities for connecting applications through WebServices (even with different implementing technologies) are quite exciting. This is just one of the many new areas of NetWeaver that we all have to look forward to.