Coding Client Applications and Services

Overview

Adapter for SAP has several APIs that you can use in your client applications and services. This chapter shows how to use the built-in services API to invoke SAP RFCs, send IDocs to an SAP system and to receive an IDoc from an SAP system. For descriptions of the available built-in services, refer to Built-in Services.

For more information about building the Java services, see the online API documentation installed with Integration Server at: Integration Server_directory\instances\instance_name\doc\api\Java\index.html

This chapter also shows how to use IBM webMethods Adapter for SAP IDoc Java API to construct an IDoc. For information, refer to packages_directory\WmSAP\pub\doc\api\index.html.

Invoking RFCs from Adapter for SAP

Calling Public Adapter for SAP Services from Java Services

About this task

This section shows an example of how to invoke an RFC from a Java service. The sample app/BAPI.javathat is shown below logs on to an SAP system and invokes a BAPI.

For more information about developing services, see IBM webMethods Service Development Help for your release and the online API documentation.

To call a public Adapter for SAP service from Java

Procedure

  1. Start Designer if it is not already running.
    Note: The steps for using Designer to call the adapter service from Java are similar.
  2. Create a Java service named app.BAPI:callService and enter the following source:
    IDataCursor idc=pipeline.getCursor();  
    IDataUtil.put(idc, "serverName", "CER");  
    IDataUtil.put(idc, "COMPANYID", "000001");  
    IDataUtil.put(idc, "$rfcname", "BAPI_COMPANY_GETDETAIL");  
    try  
    {  
        Service.doInvoke("pub.sap.client", "invoke", pipeline);  
    }  
    catch (Exception e)  
    {  
        throw new ServiceException(e);  
    }  
    finally  
    {  
        idc.destroy();  
    }
  3. This service will invoke BAPI_COMPANY_GETDETAIL with a company ID of 000001 and return the results. The logon to the SAP system is done automatically using the connection information for the RFC connection alias.
    Note: Change the RFC connection alias (field serverName of the public Adapter for SAP service) to your own alias.

Receiving IDocs from an SAP System

To receive an IDoc from an SAP system and pass it to a service, you can setup an synchronous ALE adapter notification or a routing notification. In either case, you need to assign the service you would like to invoke to the notification. For instructions on establishing routing notifications, refer to Routing Notifications. When choosing the transport for the routing notification, select the IS transport. For instructions on establishing asynchronous ALE listener notifications, refer to Creating a Synchronous RFC Adapter Notification.

Accessing and Modifying Fields in IDocs

The following code sample shows how to use the SAP Java IDoc Class Library to convert an IDoc to a structured document with direct access to each field. This allows you to modify an IDoc's contents on the fly. For example, if you want to customize incoming IDocs based on local data format, you can do so.

IDataCursor idc=pipeline.getCursor();  
com.sap.conn.idoc.IDocDocumentList iDocList=null;  
if (idc.first("iDocList"))  
   iDocList=(com.sap.conn.idoc.IDocDocumentList) idc.getValue();

under Shared > Imports, include the lines:

com.wm.adapter.sap.idoc.*  
com.sap.conn.idoc.*
Note: To resolve the included Java classes, you must include the WmSAPpackage in the dependency section of your application package.

For more information about using the SAP Java IDoc Class Library, refer to Constructing an IDoc with the SAP Java IDoc Class Library.

Converting an IDoc to XML

The following code sample shows how to convert an IDoc to XML.

String xmlData = idocList.toXML();

Constructing an IDoc with the SAP Java IDoc Class Library

The following sample shows how to construct a new MATMAS IDoc.

Important: Remember to include com.wm.adapter.sap.idoc.*and com.sap.conn.idoc.* in Shared > Imports.
public final static void createIDoc (IData pipeline)  
throws ServiceException  
{  
//create a new and empty MATMAS02 document  
try  
{  
com.sap.conn.idoc.IDocDocumentList iDocList = new IDataDocumentList("MATMAS02");  
IDocDocument doc = iDocList.addNew();  
//set the appropriate control header data  
doc.setIDocNumber("0000047112211178");  
doc.setClient("000");  
doc.setDirection("1");  
doc.setRecipientPartnerType("LS");  
doc.setMessageType("MATMAS");  
doc.setRecipientPartnerType("LS");  
doc.setRecipientPartnerNumber("TSTCLNT000");  
doc.setSenderPort("SAPBCIDOC");  
doc.setSenderPartnerType("LS");  
doc.setSenderPartnerNumber("SBCCLNT000");  
doc.setCreationDate("20030511");  
doc.setCreationTime("103051");  
doc.setSerialization("20030511103051");  
//get the root segment from the document  
//The root segment does not contain any fields or data. It is only  
//used as the standard parent segment and won't be transmitted when  
//the document is sent to an SAP system.  
IDoc.Segment segment = doc.getRootSegment();  
//create and add a new and empty child segment of type E1MARAM  
//and fill the segment data  
segment = segment.addChild("E1MARAM");  
segment.setValue("MSGFN", "005");  
segment.setValue("MATNR", "BOXCOOKIES");  
segment.setValue("ERSDA", "20030303");  
segment.setValue("ERNAM", "TOPSI");  
segment.setValue("PSTAT", "KBG");  
segment.setValue("MTART", "FERT");  
segment.setValue("MBRSH", "L");  
segment.setValue("MATKL", "G1113");  
segment.setValue("MEINS", "PCE");  
segment.setValue("BLANZ", "000");  
segment.setValue("BRGEW", "0.550");  
segment.setValue("NTGEW", "0.000");  
segment.setValue("GEWEI", "KGM");  
segment.setValue("VPSTA", "KBG");  
//create and add a new and empty child segment of type E1MAKTM  
//and fill the segment data  
segment = segment.addChild("E1MAKTM");  
segment.setValue("MSGFN", "005");  
segment.setValue("SPRAS", "D");  
segment.setValue("MAKTX", "Schachtel mit Keksen");  
segment.setValue("SPRAS_ISO", "DE");  
//create and add a new and empty sibling segment of type E1MAKTM (same  
//type) and fill the segment data  
segment = segment.addSibling();  
segment.setValue("MSGFN", "005");  
segment.setValue("SPRAS", "E");  
segment.setValue("MAKTX", "Box of cookies");  
segment.setValue("SPRAS_ISO", "EN");  
//create and add a new and empty sibling segment of type E1MARCM  
//and fill the segment data  
segment = segment.addSibling("E1MARCM");  
segment.setValue("MSGFN", "005");  
segment.setValue("WERKS", "0001");  
segment.setValue("PSTAT", "BG");  
segment.setValue("PLIFZ", "0");  
segment.setValue("WEBAZ", "0");  
segment.setValue("PERKZ", "M");  
segment.setValue("AUSSS", "0.00");  
segment.setValue("BESKZ", "E");  
segment.setValue("AUTRU", "X");  
//create and add a new and empty sibling segment of type E1MBEWM  
//and fill the segment data  
segment = segment.addSibling("E1MBEWM");  
segment.setValue("MSGFN", "005");  
segment.setValue("BWKEY", "0001");  
segment.setValue("VPRSV", "S");  
segment.setValue("VERPR", "0.00");  
segment.setValue("STPRS", "15.50");  
segment.setValue("PEINH", "1");  
segment.setValue("BKLAS", "7920");  
segment.setValue("VJVPR", "S");  
segment.setValue("VJVER", "0.00");  
segment.setValue("VJSTP", "15.50");  
segment.setValue("LFGJA", "2002");  
segment.setValue("LFMON", "08");  
segment.setValue("PSTAT", "BG");  
segment.setValue("KALN1", "000100126602");  
segment.setValue("KALNR", "000100126603");  
segment.setValue("EKALR", "X");  
segment.setValue("VPLPR", "0.00");  
segment.setValue("VJBKL", "7920");  
segment.setValue("VJPEI", "1");  
segment.setValue("BWPEI", "0");  
IDataCursor idc=pipeline.getCursor();  
IDataUtil.put(idc, "iDocList", iDocList);  
idc.destroy();  
}  
catch (Exception e)  
{  
    throw new ServiceException(e);  
}

Sending IDocs to an SAP System

About this task

The basic steps to send an outbound IDoc from either a client or a service are:

Procedure

  1. Create a transaction ID by invoking the pub.sap.client:createTIDservice.
  2. Send the IDoc to the SAP system by invoking the pub.sap.client:sendIDoc service, passing in the com.sap.conn.idoc.IDocDocumentList object (iDocList).

    If an error occurs, repeat the pub.sap.client:sendIDocservice invocation with the same transaction ID. The SAP system guarantees that the transaction will execute only once.

  3. After pub.sap.client:sendIDoc returns successfully, invoke pub.sap.client:confirmTID.

Transaction Features for HTTP and SAP-XML

When executing HTTP Posts using IDoc-XML and XRFC with transactions, you should make sure that your client correctly handles such calls. It should have transaction management that supports at least the following features:

  • Transaction ID generation.
  • Resending documents with same transaction ID in error cases.
  • After a successful execution of a transaction, a document cannot be sent again.

To transfer the transaction ID to Adapter for SAP, you add an extra header to the HTTP POST, x-tid, that contains the transaction ID.

Example: HTTP POST of an IDoc

POST /invoke/pub.sap.transport.ALE/InboundProcess HTTP/1.0  
X-tid: 9B38FA81133A38B518A10036  
Content-type: application/x-sap.idoc  
Content-Length: 4242  
  <?xml version="1.0" encoding="iso-8859-1"?>  
  <MATMAS02>  
    <IDOC BEGIN="1">  
     <EDI_DC SEGMENT="1">  
        <TABNAM>EDI_DC</TABNAM>  
        <MANDT>000</MANDT>  
        <DOCNUM>0000047112211178</DOCNUM>  
        <DOCREL/>  
        <STATUS/>  
        <DOCTYP>MATMAS02</DOCTYP>  
        <DIRECT>1</DIRECT>  
...

For XRFC documents, you can also put the transaction ID in the header of the document:

<?xml version="1.0"?>  
  <sap:Envelope xmlns:sap="urn:sap-com:document:sap" version="1.0">  
   <sap:Header xmlns:rfcprop="urn:sap-com:document:sap:rfc:properties">  
    <rfcprop:Transaction>0A1104DC080C3C60F9E106A1</rfcprop:Transaction>  
   </sap:Header>  
   <sap:Body>  
    <rfc:SBC_TEST_SAVE xmlns:rfc="urn:sap-  
        com:document:sap:rfc:functions">  
       <INPUT>Have fun!</INPUT>  
     </rfc:SBC_TEST_SAVE>  
   </sap:Body>  
  </sap:Envelope>

Calling a BAPI Synchronously from SAP System

About this task

This example demonstrates how to send the BAPI CompanyCode.GetDetail from an SAP system to the Web via XML.

As the BAPI will be handled by a routing notification, you need to specify some information to enable correct routing. For this purpose, you should use the parameter SBCHEADER when calling the RFC function module from the SAP system.

To set up for the example

Procedure

  1. Set up an RFC Listener for the SAP system on your Adapter for SAP as described in Listeners.
  2. Set up a corresponding RFC destination on your SAP system for your RFC Listener using the transaction SM59 as described in Creating an RFC Destination on an SAP System.
  3. Create a program Z_BAPI_RFC_DEMO in the SAP system using the transaction SE38 You can enter the following source code:
    REPORT Z_BAPI_RFC_DEMO .  
    *variable companyCodes will take the application result  
    data companyCodes like BAPI0002_1 occurs 1 with header line.  
    *variable header gives Adapter for SAP instructions for routing  
    data header like SBCCALLENV occurs 1 with header line.  
    *variable returnCode takes the processing information after the  
    *synchronous call  
    data returnCode type BAPIRETURN.  
    *Fill the Adapter for SAP routing instructions  
    header-name = 'sender'.  
    header-value = 'CERCLNT800'.  
    append header.  
    header-name = 'receiver'.  
    header-value = 'CERCLNT750'.  
    append header.  
    *Execute the RFC with destination ISCER  
    CALL FUNCTION 'BAPI_COMPANYCODE_GETLIST'  
    *->ISCER should be maintained in SM59 as alias to Adapter for SAP  
      DESTINATION 'ISCER'  
    IMPORTING  
      RETURN = returnCode  
    TABLES  
      COMPANYCODE_LIST = companyCodes  
      SBCHEADER = header[]  
    .  
    *process the BAPI-Return parameter  
    if not returnCode is initial.  
      write: / 'BAPI return parameter:'.  
      write: / ' Code: ' , returnCode-CODE.  
      write: / ' Message: ' , returnCode-MESSAGE.  
    endif.  
    *display the application result  
    loop at companyCodes.  
      write: / companyCodes-COMP_CODE, ' ', companyCodes-COMP_NAME.  
    endloop.

Preparing a Routing Notification for the BAPI Call

About this task

Before executing the report in the section Calling a BAPI Synchronously from SAP System, you should specify a routing notification to the XML transport. You can send the XML message to any server that is able to process the HTTP Post message and send back a correct response. In this example, the call will be sent back to the locally installed Integration Server to demonstrate its inbound XML processing capabilities.

To prepare a routing notification for the BAPI call

Procedure

  1. Open Designer and select New > Adapter Notification. Click Next.
  2. Select IBM webMethods Adapter for SAP from the list of available adapter types. Click Next.
  3. From the list of available templates, select Routing Notification. Click Next.
  4. Select the routing listener wm.sap.internal.ls:routingListener. Click Next.
  5. Enter a name and select a folder where the routing notification should be stored.
  6. Select any service that should be invoked by this notification. Click Next and then Finish.
    Note: The service you selected in step 6 will only be used if the outbound transport that is chosen in your routing notification is "IS". For all other outbound transports, this selection will be overridden by a transport specific service.
  7. In the input fields at the top of the page, enter the following data:
    1. Sender: CERCLNT800.
    2. Receiver: CERCLNT750.
    3. msgType: BAPI_COMPANYCODE_GETLIST.
    4. Select XML in the Transport field.
  8. Specify a URL for the target system. To test the functionality using your local Integration Server's Inbound processing, enter: http://localhost:5555/invoke/pub.sap.transport.BAPI/InboundProcess (note that in some cases you have to adjust the port 5555 to your current settings).
    1. Select dialect bXML for the xmlType parameter.
    2. Select Yes for the useBAPI parameter.
    3. Enter "CompanyCode" for the objectName parameter.
    4. Enter "GetList" for the bapiName.
    5. Click the Save button.

Specifying a Second Routing Notification for the BAPI

About this task

To handle the inbound XML message, which will now be sent back to the local Integration Server, you have to specify a second routing notification for the BAPI:

To specify a second routing notification for the BAPI

Procedure

  1. In the input field at the end of the page, enter the following data:
    1. Sender: CERCLNT800.
    2. Receiver: CERCLNT750.
    3. msgType: CompanyCode.GetList.
  2. Select BAPI in the Transport field.
  3. Select the SAP system to which the message should be routed from the drop down list.
    When executing the program in the SAP system, Adapter for SAP sends the HTTP Request to the remote host, which looks similar to the following:
    POST /invoke/pub.sap.transport.BAPI/InboundProcess HTTP/1.0  
    User-Agent: Mozilla/4.0 [en] (WinNT; I)  
    Accept: image/gif, */*  
    Host: localhost:90  
    Content-type: application/x-sap.busdoc  
    Cookie: ssnid=553891555519  
    Content-length: 817  
    <?xml version="1.0" encoding="iso-8859-1"?>  
     <biztalk_1 xmlns="urn:biztalk-org:biztalk:biztalk_1">  
      <header>  
       <delivery>  
        <message>  
         <messageID>0A125F1315B3D24B0000001E</messageID>  
         <sent>2000-06-20T09:58:00</sent>  
        </message>  
        <to>  
         <address>urn:sap-com:logical-system:CERCLNT750</address>  
        </to>  
        <from>  
         <address>urn:sap-com:logical-system:CERCLNT800</address>  
        </from>  
       </delivery>  
      </header>  
      <body>  
       <doc:CompanyCode.GetList xmlns:doc="urn:sapcom:  
        document:sap:business" xmlns="">  
        <CompanyCodeList>  
         <item>  
          <COMP_CODE></COMP_CODE>  
          <COMP_NAME></COMP_NAME>  
         </item>  
        </CompanyCodeList>  
       </doc:CompanyCode.GetList>  
      </body>  
     </biztalk_1>

Results

When using the Integration Server as the remote partner as described above, the BAPI will be executed in the selected system, the exporting and changing parameters will be put in an XML response document and sent back to the calling SAP system.

The report will then display the parameters received from the remote system, which in this case is a list of company codes.

Calling a BAPI Asynchronously from an SAP System

This example demonstrates how to call a BAPI asynchronously from an SAP system over the Web. For this purpose, you have to create an ABAP program inside the SAP system. This program calls the proxy function module to generate an ALE message for a BAPI. After performing a COMMIT WORKcommand, the SAP system will generate an IDoc through the ALE service layer and send it to Adapter for SAP. There the IDoc will be transformed into the original BAPI representation and sent as XML using HTTP to any remote web system.

Note: While BAPI function module names usually start with the prefix BAPI_, the corresponding ALE proxies are usually named equally with the prefix ALE_

To run an example, you should set up your SAP system for ALE processing as described in the SAP system documentation and in this guide. When defining the partner profile for the outgoing IDoc in the SAP system, ensure that the option Transfer IDoc immediatelyis selected because the BAPI conversion tool on Adapter for SAP does not support IDoc packages.

Create the following report in your SAP system to test the BAPI conversion with the BAPI Bank.Create(available as of SAP release 4.6C).

REPORT Z_BAPI_ALE_DEMO .  
parameters receiver like BDI_LOGSYS-LOGSYS.  
parameters country like BAPI1011_KEY-BANK_CTRY default 'DE'.  
parameters bankkey like BAPI1011_KEY-BANK_KEY default '34981255'.  
data: receivers like BDI_LOGSYS occurs 0 with header line,  
      address like BAPI1011_ADDRESS.  
*prepare the distribution information  
move receiver to receivers-LOGSYS.  
append receivers.  
*prepare the BANK addres parameter  
address-BANK_NAME = 'Demo Bank'.  
address-REGION = 'BW'.  
address-STREET = 'Neurottstr. 16'.  
address-CITY = 'Walldorf'.  
address-SWIFT_CODE = 'ABCDDE12'.  
address-BANK_GROUP = 'SB'.  
address-BANK_NO = '12345678'.  
address-ADDR_NO = '123'.  
*send data to ALE  
CALL FUNCTION 'ALE_BANK_CREATE'  
  EXPORTING  
   BANKCTRY = country  
   BANKKEY = bankkey  
   BANKADDRESS = address  
  TABLES  
   RECEIVERS = receivers  
  EXCEPTIONS  
   ERROR_CREATING_IDOCS = 1  
   OTHERS = 2  
.  
IF SY-SUBRC <> 0.  
  write: / 'IDoc could not be created'.  
ELSE.  
  write: / 'IDoc successfully created'.  
ENDIF.  
*trigger processing  
commit work and wait.

Creating Similar Routing Notifications

About this task

To create similar routing notifications

You can create routing notifications similar to those described in the synchronous example.

Procedure

  1. In the input field, enter the following data:
    • Sender: enter the logical system of the sending system.
    • Receiver: enter the logical system of the target system.
    • msgType: BANK_CREATE.
  2. In the transport field, select XML.
  3. Specify an URL for the target system. To test the functionality using your local Integration Server's Inbound processing, enter:
    http://localhost:5555/invoke/pub.sap.transport.BAPI/InboundProcess

    (note that in some cases you have to adjust the port 5555 to your current settings)

  4. Select dialect BizTalk for the xmlType parameter.
  5. Select Yes for the useBAPI parameter.
  6. Enter "bank" for the objectName parameter.
  7. Enter "Create" as the BAPI.

Handling Inbound XML Message

About this task

To handle the inbound XML message, which will now be sent back to the local Integration Server, you have to specify a second routing notification for the BAPI.

To handle the Inbound XML Message

Procedure

  1. In the input field, enter the following data:
    • Sender: enter the logical system of the sending system.
    • Receiver: enter the logical system of the target system.
    • Message-type: Bank.Create.
  2. In the field transport, select BAPI.
  3. Select the SAP system to which the message should be routed from the drop down list.

    When executing the report, you have to enter a RECEIVER. This should be the name of the logical system you have defined for your Adapter for SAP.

Example of an XML

When executing the report in the SAP system, Adapter for SAP will transmit the XML document via HTTP (names of logical systems depend on your system configuration). The XML would look like this:

<?xml version="1.0" encoding="iso-8859-1"?>  
 <biztalk_1 xmlns="urn:biztalk-org:biztalk:biztalk_1">  
  <header>  
   <delivery>  
    <message>  
     <messageID>0A125F1315B3A11B00000035</messageID>  
     <sent>2000-06-07T09:22:40</sent>  
    </message>  
    <to>  
     <address>urn:sap-com:logical-system:CERCLNT750</address>  
    </to>  
    <from>  
     <address>urn:sap-com:logical-system:CERCLNT800</address>  
    </from>  
   </delivery>  
  </header>  
  <body xmlns="">  
   <doc:Bank.Create xmlns:doc="urn:sap-com:document:sap:business">  
    <BankKey>34981243</BankKey>  
    <BankCtry>DE</BankCtry>  
    <BankAddress>  
     <BANK_NAME>Demo Bank</BANK_NAME>  
     <REGION>BW</REGION>  
     <STREET>Neurottstr. 16</STREET>  
     <CITY>Walldorf</CITY>  
     <SWIFT_CODE>ABCDDE12</SWIFT_CODE>  
     <BANK_GROUP>SB</BANK_GROUP>  
     <POBK_CURAC></POBK_CURAC>  
     <BANK_NO>12345678</BANK_NO>  
     <POST_BANK></POST_BANK>  
     <BANK_BRANCH></BANK_BRANCH>  
     <ADDR_NO>123</ADDR_NO>  
    </BankAddress>  
   </doc:Bank.Create>  
  </body>  
 </biztalk_1>

You can check the correct processing of your BAPI-call in the IDoc status monitor.

In the target SAP system, you can also inspect the correct processing using the ALE status monitor (BD87 in SAP release 4.6C. IDoc lists can also be displayed with WE05). If any application errors occurred, they are listed in the IDoc monitor.