Registration

Dear SAP Community Member,
In order to fully benefit from what the SAP Community has to offer, please register at:
http://scn.sap.com
Thank you,
The SAP Community team.
Skip to end of metadata
Go to start of metadata

Rewriting the SAP WSDL file

From the service configuration created in PI Directory or transaction soamanager, copy the WSDL url and open it in the browser. As Metro requires the policy information, the WSDL must be rewritten to Policy 1.5 by using an XSLT as described below. XSLT is a generic approach of extracting XML data and rewriting XML documents. An XSLT transformation can be called in different ways. Below you find examples how to invoke it from XSML Spy, a Java application or an ABAP application.

(warning)   Please ensure only one binding is included in the WSDL. When using soamanager, include a single endpoint in a service. Configuration created by PI Directory will allways include one binding per WSDL.

(warning)   It is recommended to create WSDL files without import statements. This will avoid authentication issues as otherwise Metro will try to resolve the WSDL during runtime. Using the Url parameters, AS ABAP generates WSDLs with or without import statements. To generate a WSDL without import statments, use the URL containing the allinone directive:

host:port/sap/bc/srt/wsdl/srvc_.../wsdl11/allinone/ws_policy/document?sap-client=000

XSLT

Use the XSLT below for rewriting the WSDL.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:wsp15="http://www.w3.org/ns/ws-policy" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsuOld="http://schemas.xmlsoap.org/ws/2002/07/utility"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:sapsp="http://www.sap.com/webas/630/soap/features/security/policy"
xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:wst="http://docs.oasis-open.org/ws-sx/ws-trust/200512"
xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" version="1.0">
<xsl:output method="xml" media-type="text/xml" indent="no" omit-xml-declaration="yes"/>
<xsl:template match="*">
<!-- copy security policy element -->
<xsl:choose>
<xsl:when test="name()='wsp:UsingPolicy'">
<wsp15:UsingPolicy xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" wsdl:required="true"/>
</xsl:when>
<xsl:when test="name()='wsp:ExactlyOne'">
<wsp15:ExactlyOne xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702" xmlns:wsp15="http://www.w3.org/ns/ws-policy">
<xsl:call-template name="copy_selected_attributes"/>
<xsl:apply-templates/>
</wsp15:ExactlyOne>
<xsl:comment>
<xsl:value-of select="count(*/sp:SecureConversationToken)"/>
</xsl:comment>
</xsl:when>
<xsl:when test="name()='wsp:All'">
<wsp15:All xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702" xmlns:wsp15="http://www.w3.org/ns/ws-policy">
<xsl:call-template name="copy_selected_attributes"/>
<xsl:apply-templates/>
</wsp15:All>
</xsl:when>
<xsl:when test="name()='wsp:Policy' and count(./wsp:PolicyReference)>0">
<wsp15:PolicyReference>
<xsl:copy-of select="./wsp:PolicyReference/@*"/>
</wsp15:PolicyReference>
</xsl:when>
<xsl:when test="name()='wsp:Policy' and count(./wsp:PolicyReference)=0 and count(./wsp:ExactlyOne)=0">
<wsp15:Policy xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<xsl:call-template name="copy_selected_attributes"/>
<wsp15:ExactlyOne>
<wsp15:All>
<xsl:apply-templates/>
</wsp15:All>
</wsp15:ExactlyOne>
</wsp15:Policy>
</xsl:when>
<xsl:when test="name()='wsp:Policy'">
<wsp15:Policy xmlns:wsp15="http://www.w3.org/ns/ws-policy">
<xsl:call-template name="copy_selected_attributes"/>
<xsl:apply-templates/>
</wsp15:Policy>
</xsl:when>
<xsl:when test="name()='saptrnbnd:OptimizedXMLTransfer'">
<!--xsl:comment>skip saptrnbnd:OptimizedXMLTransfer</xsl:comment-->
</xsl:when>
<!-- add addressing -->
<xsl:when test="name()='sp:Trust13'">
<sp:Trust13>
<!--copy attributes as well -->
<xsl:call-template name="copy_selected_attributes"/>
<!--trigger recursion of elements -->
<xsl:apply-templates/>
</sp:Trust13>
<wsaw:UsingAddressing xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" wsp:Optional="true"/>
</xsl:when>
<xsl:when test="name()='wsdl:binding'">
<wsdl:binding>
<xsl:copy-of select="@type"/>
<xsl:attribute name="name">binding</xsl:attribute>
<xsl:apply-templates/>
</wsdl:binding>
</xsl:when>
<xsl:when test="name()='wsdl:service'">
<wsdl:service>
<xsl:attribute name="name">service</xsl:attribute>
<xsl:apply-templates/>
</wsdl:service>
</xsl:when>
<xsl:when test="name()='wsdl:port'">
<wsdl:port>
<xsl:attribute name="name">binding</xsl:attribute>
<xsl:attribute name="binding">tns:binding</xsl:attribute>
<xsl:apply-templates/>
</wsdl:port>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<!--copy attributes as well -->
<xsl:call-template name="copy_selected_attributes"/>
<!--trigger recursion of elements -->
<xsl:apply-templates/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="copy_selected_attributes">
<xsl:copy-of select="@*[name()  != 'wsp:Optional' and name() != 'wsuOld:Id']"/>
<xsl:if test="count(@wsp:Optional)=1">
<xsl:attribute name="wsp15:Optional"><xsl:value-of select="@wsp:Optional"/></xsl:attribute>
</xsl:if>
<xsl:if test="count(@wsuOld:Id)=1 and string-length(@wsuOld:Id)>0">
<xsl:attribute name="wsu:Id"><xsl:value-of select="@wsuOld:Id"/></xsl:attribute>
</xsl:if>
</xsl:template>
</xsl:stylesheet>









1) The simple way: using XML Spy

 A simple approachis to run the transformation in  XMLSpy.

To rewrite the WSDL using XMLSpy:

  1. Download the WSDL and save it as a file
  2. Open the WSDL file in XMLSpy and select menu XSL->XSL Transformation
  3. Use the XSLT below and save the result in a file

2) The Java way 

To rewrite the WSDL using an Java program:

  1. Copy the file below into a Java IDE
  2. Copy the XSLT and save it as "p12-p15.xslt" in the same package
  3. Adopt the main method an specify:
    1. wsdl url
    2. username for WSDL access
    3. password for WSDL access
    4. Location to store the SAP-WSDL
    5. Location to store the rewritten WSDL
package rewriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
public class WSDLRewriter {
    private static Transformer transformer12deserialize;
    public static void rewriteWSDL(String url, String sapWsdlPath, String metroWsdlPath,
final String username, final String password) throws MalformedURLException, IOException,
TransformerConfigurationException, ParserConfigurationException, SAXException, TransformerException {
        /*
         * add authentication
         */
        url += "&sap-user=" + username + "&sap-password=" + password;
        /*
         * Read wsdl file and store it
         */
        URL urlObject = new URL(url);
        HttpURLConnection connection = (HttpURLConnection) urlObject.openConnection();
        int responseCode = connection.getResponseCode();
        if (responseCode == 200) {
            InputStream is = connection.getInputStream();
            int data;
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            while ((data = is.read()) != -1) {
                bos.write(data);
            }
            bos.close();
            byte[] wsdlData = bos.toByteArray();

            FileOutputStream fos = new FileOutputStream(sapWsdlPath);
            fos.write(wsdlData);
            fos.close();
            /*
             * Run XSLT
             */
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            dbf.setNamespaceAware(true);
            DocumentBuilder newDocumentBuilder = dbf.newDocumentBuilder();
            Document wsdlDocument = newDocumentBuilder.parse(new ByteArrayInputStream(wsdlData));
            DOMSource wsdlSource = new DOMSource(wsdlDocument.getDocumentElement());
            DOMResult wsdlResult = new DOMResult();
            TransformerFactory tf = TransformerFactory.newInstance();
            transformer12deserialize = tf.newTransformer(
new StreamSource(WSDLRewriter.class.getResourceAsStream("p12-p15.xslt")));
            transformer12deserialize.transform(wsdlSource, wsdlResult);
            fos = new FileOutputStream(metroWsdlPath);
            write(wsdlResult.getNode(), fos);
            fos.close();
        } else {
            throw new IOException("Error reading WSDL. HTTP Response code:" + connection.getResponseMessage());
        }
    }
    static private void write(org.w3c.dom.Node document, OutputStream os)
throws TransformerFactoryConfigurationError, TransformerException, IOException {
        /* Create output container */
        StreamResult streamResult = new StreamResult(os);
        /* Prepare input data */
        Source source = new DOMSource(document);
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer tr = tf.newTransformer();
        tr.setOutputProperty(OutputKeys.METHOD, "xml");
        tr.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
        tr.setOutputProperty(OutputKeys.STANDALONE, "yes");
        tr.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
        tr.setOutputProperty(OutputKeys.INDENT, "no");
        /* Convert */
        tr.transform(source, streamResult);
        os.close();
    }
    public static void main(String args[]) throws Exception {
        // WSDL url
        String wsdlUrl = "...";
        // user for WSDL access
        String username = "WSS_ABAP";
        // password for WSDL access
        String password = "abcd1234";
        // location where SAP WSDL will be downloaded
        String sapWsdlFile = "c:/temp/wsdl/sap.wsdl";
        // location where rewritten WSDL will be stored
        String metroWsdlFile = "c:/temp/wsdl/sap.wsdl";
        /*
         * Rewrite WSDL file
         */
        WSDLRewriter.rewriteWSDL(wsdlUrl,sapWsdlFile, metroWsdlFile, username, password);
    }
}

3) The ABAP way

The ABAP approach is to provide the WSDL by URL. To achive this, a HTTP handler is created that will take the following step to rewrite the WSDL.

  1. Create an CL_HTTP_CLIENT and read the read the WSDL from the same ABAP system using destination NONE
  2. Transform it using the XSLT transformation
  3. Write the transformed WSDL

Implementation: IF_HTTP_EXTENSION

This solution is implemented as an ICF node. First create a class implementing IF_HTTP_EXTENSION. Use the coding below for IF_HTTP_EXTENSION~HANDLE_REQUEST.

SPAN {
font-family: "Courier New";
font-size: 10pt;
color: #000000;
background: #FFFFFF;
}
.L1S31 {
font-style: italic;
color: #808080;
}
.L1S32 {
color: #3399FF;
}
.L1S33 {
color: #4DA619;
}
.L1S52 {
color: #0000FF;
}
method if_http_extension~handle_request.
  data:
        lr_http_client type ref to if_http_client,
        lf_url         type string,
        lf_subrc       type int4,
        lf_errortext   type string,
        lf_wsdl_data   type xstring,
        lf_rewritewsdl type xstring.

  "
  " - 1 - get url
  "
  server->request->get_form_field(
    exporting
      name               =  'url'
    receiving
      value              = lf_url
    exceptions
      others             = 1
  ).
  do strlen( lf_url ) times.
    if lf_url+sy-index(1) = '/' and sy-index > 8.
      lf_url = lf_url+sy-index.
      exit.
    endif.
  enddo.
  if sy-subrc <> 0 or lf_url is initial.
    call method server->response->set_cdata( data = 'error: parameter url not set' ).
    return.
  endif.

  "
  " - 2 - read data
  "
  cl_http_client=>create_by_destination( exporting destination = 'NONE'
                                         importing client      = lr_http_client ).
  cl_http_utility=>set_request_uri( request = lr_http_client->request
                                   uri     = lf_url ).
* Send
  lr_http_client->request->set_method( if_http_request=>co_request_method_get ).

  call method lr_http_client->send
    exporting
      timeout                    = 60
    exceptions
      http_communication_failure = 1
      http_invalid_state         = 2
      http_processing_failed     = 3
      others                     = 4.

  if sy-subrc <> 0.
    call method lr_http_client->get_last_error
      importing
        code    = lf_subrc
        message = lf_errortext.
    call method server->response->set_cdata( data = 'communication_error( send )' && lf_errortext ).
    return.
    exit.
  endif.

* receive

  call method lr_http_client->receive
    exceptions
      http_communication_failure = 1
      http_invalid_state         = 2
      http_processing_failed     = 3
      others                     = 4.

  if sy-subrc <> 0.
    call method lr_http_client->get_last_error
      importing
        code    = lf_subrc
        message = lf_errortext.
    call method server->response->set_cdata( data = 'communication_error( send )' && lf_errortext ).
    return.
  endif.
  lr_http_client->response->get_data(
    receiving
      data               =  lf_wsdl_data
    exceptions
      others             = 1
  ).
  if sy-subrc <> 0.
    call method server->response->set_data( data = lf_wsdl_data ).
    return.
  endif.
* close
  call method lr_http_client->close
    exceptions
      http_invalid_state = 1
      others             = 2.
  if sy-subrc <> 0.
    call method lr_http_client->get_last_error
      importing
        code    = lf_subrc
        message = lf_errortext.
    call method server->response->set_cdata( data = 'communication_error( close )' && lf_errortext ).
    return.
  endif.

  "
  " - 3 - call transformation
  "
  call transformation z_p12_p15 source xml lf_wsdl_data result xml lf_rewritewsdl.
  server->response->set_content_type('text/xml').
  server->response->set_data(
    exporting
      data   = lf_rewritewsdl
  ).

endmethod.

Implementation: XSLT transformation

Using transaction STRANS to create a new XSLT transformation object and add the XSLT above.  To match the coding above, use name z_p12_p15 as transformation name.

Implementation: SICF node

Finally, create an ICF node using the ABAP class as handler.

Rewriting WSDLs

To rewrite a WSDL, call the ICF handler by passing the wsdl-url as parameter url. The url will depend on the name of the created ICF node,  i.e.

http://ldciu7c.wdf.sap.corp:57400/sap/z_wsdl_rewrite?sap-client=001&url=http://host:port/sap/bc/srt/wsdl/bndg_001560AB336002DDAEE074FBD993CEDB/wsdl11/allinone/ws_policy/document?sap-client=001

(warning)   NetBeans is not able to handle WSDL files requiring authentication. There are multiple solutions to this:

  1. Download the WSDL and specify the file
  2. Add &sap-user=<username>&sap-password=<password> to the url
  3. Add a service user in the icf node and select service user authentication
  • No labels