How to Send Binary Data to RFC from XI(or)PI


SAP PI Interview Questions and SAP PI Tutorials

SAP PI Interview Questions and SAP PI Tutorials

Scenario & Aspects

Let’s consider a very simple scenario say HTTP to RFC (either synchronously or asynchronously, as we can handle these behaviors from HTTP sender side
using BE & EO qualifiers). I will not be explaining each and every XI design and configuration step as our focus is different here. But to simplify the things, I recommend in using the concept of ID configuration without IR Design. Of course we need to use IR for at least importing the ZBAPI* structure in SWCV. Make sure that necessary associations are in place in SLD for RFC R/3 business system and SWCV for which we have to import ZBAPI * structure in IR.

In this article we will mainly focus on the following three aspects.
I.    The first part deals with posting of binary data to XI inbound HTTP adapter for the above assumed scenario using Java based HTTP client. Since the inbound XI HTTP adapter doesn’t \
accept/support binary format we will encode binary data to Base64 and post the same. So I am providing a snippet of java HTTP Client code.
II.    The second part is altogether different as we consider that the sender can be anything like File Adapter or proxy etc carrying direct binary data to Integration Engine and hence we
consider the IR design part for the sender message interface along with interface mapping. Here our main focus is how to encode the received binary data in mapping using Java Mapping concept. So here I will be only providing the snippet of java mapping code which does this job.
III.    The third part mainly considers ZBAPI coding details in R/3 ECC 6.0 SAP system. Here I will mainly consider how the ZBAPI calls the standard bapi SSFC_BASE64_DECODE (this standard BAPI is available from ECC6.0 and is not remote enabled. Interested ABAP developers can write a custom BASE64 decoder for lower R/3 versions as the decoding algorithm is a open source on internet) for decoding the received base64 data to binary data and finally file handling this binary data to a local file system to check the correctness. In real time we might have different business logics according to the requirements.

Prerequisites

SAP XI/PI, SAP ECC 6.0 systems and a J2SDK 1.4_XX version software.
Jar files required: aii_utilxi_misc.jar, aii_map_api.jar

Custom BAPI Creation Steps and FM code

So, let’s first start with part III. Check the below screen shots for the ZBAPI structures.
Tcode:         SE37
ZBapi Name:     Z_BASE64_DECODE

SAP PI Interview Questions and SAP PI Tutorials

SAP PI Interview Questions and SAP PI Tutorials

So the above import tab has two parameters one for carrying the filename and the other for the file data in Base64 format.

Under Source Code Tab provide the following code. Save and activate the function module.

Description of FM code

The code reads the filename and base64 data and then it internally calls standard BAPI “SSFC_BASE64_DECODE” to decode the base64 data to binary stream and then it writes the binary stream to a shared file system using the above read filename. I have hard coded the export parameter with
success message, but we can also add different exceptions and set the

status message for the export parameter accordingly.

Z_BASE64_DECODE Function Module Code

 

FUNCTION Z_BASE64_DECODE.
*"----------------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     VALUE(IV_FILENAME) TYPE  STRING
*"     VALUE(IV_BASE64_DATA) TYPE  STRING
*"  EXPORTING
*"     VALUE(EV_BASE64_DATA) TYPE  STRING
*"----------------------------------------------------------------------
DATA LV_BINDATA TYPE XSTRING.
DATA LV_FILEPATH TYPE STRING.
data: lv_msg type string.

CALL FUNCTION 'SSFC_BASE64_DECODE'
  EXPORTING
    b64data                        = IV_BASE64_DATA
*   B64LENG                        =
*   B_CHECK                        =
 IMPORTING
   BINDATA                        = LV_BINDATA
* EXCEPTIONS
*   SSF_KRN_ERROR                  = 1
*   SSF_KRN_NOOP                   = 2
*   SSF_KRN_NOMEMORY               = 3
*   SSF_KRN_OPINV                  = 4
*   SSF_KRN_INPUT_DATA_ERROR       = 5
*   SSF_KRN_INVALID_PAR            = 6
*   SSF_KRN_INVALID_PARLEN         = 7
*   OTHERS                         = 8
  .
DATA: lv_filename TYPE dxfilename,
lv_data TYPE XSTRING.
lv_data = LV_BINDATA.

*Here you can pass the application server location and file name.
concatenate '/usr/sap/tmp/' IV_FILENAME into lv_filename.

* open dataset-Open the file in write/append mode.
* For write mode use OUTPUT instead of APPENDING.
OPEN DATASET lv_filename FOR APPENDING
IN LEGACY BINARY MODE.
* Transfer the Record to application server
TRANSFER lv_data TO lv_filename.
* close data set.
CLOSE DATASET lv_filename.
EV_BASE64_DATA = 'Success'.

ENDFUNCTION.

XI/PI Design and Configuration brief

Now let’s deal with XI/PI design and configurations for the above scenario (HTTP to RFC).
In the integration repository import the above developed Z_BASE64_DECODE bapi structure and activate it.
Now in Configuration create any new scenario. Create a new business service for the HTTP sender say “BS_BASE64”.
Assign the real business system of the R/3 system from SLD. Create a RFC channel under this business system with correct parameters to have a connection with R/3 system.
Since sender is HTTP, we can directly start with Receiver determination. Give Sender service as “BS_BASE64”. For message interface and namespace
we can give any dummy names. Remember we should provide the same information (Business System or Service, Message Interface and Namespace)
in Java HTTP client.

The scenario should look like as below.


Save and activate all objects. We have done with XI/PI.
Now let’s test this scenario from Java HTTP client. This java client requires an extra jar file aii_utilxi_misc.jar from XI server apart from the standard J2SDK APIs for its compilation and execution.

Java HTTP client code

 

import com.sap.aii.utilxi.base64.api.*;
import java.net.*;
import java.io.*;
import java.util.*;

class HTTPToXIToRFCBinaryToBase64
{
	public HTTPToXIToRFCBinaryToBase64() { }
	public byte[] read2array(String file) throws Exception
	{
		InputStream in = null;
		byte[] out = new byte[0];
		try{
		 in = new BufferedInputStream(new FileInputStream(file));
		 int bufLen = 2000*1024;
		 byte[] buf = new byte[bufLen];
		 byte[] tmp = null;
		 int len    = 0;
		 while((len = in.read(buf,0,bufLen)) != -1){
			tmp = new byte[out.length + len];

			System.arraycopy(out,0,tmp,0,out.length);
			System.arraycopy(buf,0,tmp,out.length,len);
			out = tmp;
			tmp = null;
	 }
	}finally{
	 if (in != null) try{ in.close();}catch (Exception e){}
	}
	return out;
	}

	public static void main(String[] args)
	{
		HTTPToXIToRFCBinaryToBase64 bfr = new HTTPToXIToRFCBinaryToBase64();
		try {
				byte[] b = bfr.read2array(args[0]);
				String rfcXML = Base64.encode(b);	//Encoding Binary Data to Base64 format.

				//rfcXML = "<?xml version=\"1.0\" encoding=\"utf-8\"?><ROOT><FILENAME>" + args[0] + "</FILENAME><BASE64rfcXML>" + rfcXML + "</BASE64rfcXML></ROOT>";
				rfcXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><ns0:Z_BASE64_DECODE xmlns:ns0=\"urn:sap-com:document:sap:rfc:functions\"><IV_BASE64_rfcXML>" + rfcXML + "</IV_BASE64_rfcXML><IV_FILENAME>" + args[0] + "</IV_FILENAME></ns0:Z_BASE64_DECODE>";
				URL url = new URL("http://<XIServerHost>:<PORT>/sap/xi/adapter_plain?namespace=http://httptohttpservlet.com&interface=MI_HTTPToServlet&service=BS_BASE64&party=&agency=&scheme=&QOS=BE&sap-user=<UserName>&sap-password=<PassWord>&sap-client=001&sap-language=EN"); //Comment: use your XI server details such as //hostname, port, username and password.
				HttpURLConnection conn = (HttpURLConnection) url.openConnection();
				conn.setDoInput(true);
				conn.setDoOutput(true);

				OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
				wr.write(rfcXML);
				wr.flush();

				// Get the response
				BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
				System.out.println("HTTP Status-Code : " + conn.getResponseCode() );

				String line;
				System.out.println("############ RFC Response ############");
				while ((line = rd.readLine()) != null)
				{
					System.out.println(line);
				}
				System.out.println("############ RFC Response ############");
				wr.close();
				rd.close();
			} catch (Exception e) {
					System.out.println("Exception : " + e);	}
	}
}

To compile the above code we need to have J2SDK software and the extra XI JAR file aii_utilxi_misc.jar (Location of jar file in XI/PI server: /usr/sap/<SID>/DVEBMGS<nr>/j2ee/cluster/server0/bin/ext/com.sap.xi.util.misc) which will be used to encode binary data to Base64 data.

I am using the standard XI Base64 Encoding method as this method design will be definitely compliant with SAP standard function module SSFC_BASE64_DECODE Base64 encoding and

decoding methods. Of course, we can also use any third party Java implementations of Base64 encoding and decoding methods (http://www.koders.com/java/fid36571AEBB9AA7C1E039DC88B866A85348F7B077E.aspx).

Compilation & Execution

Compile the java file by setting the aii_utilxi_misc.jar file in CLASSPATH environment.
Run the program by providing any binary file as input to this program.
E.g., in DOS mode,
C:\test>set CLASSPATH=%CLASSPATH%; aii_utilxi_misc.jar
C:\test>set PATH=.;<Drive>:\< J2SDKDirectory>\bin
C:\test>javac HTTPToXIToRFCBinaryToBase64.java
C:\test>java HTTPToXIToRFCBinaryToBase64 <BINARYFILE>

Once executed, check the message in XI/PI using SXMB_MONI tcode. Then check file in the shared folder where the FM Z_BASE64_DECODE writes the binary stream.  For example if it is a PDF file then it should be opened by Adobe Acrobat Reader.

Now let’s consider part II i.e., in XI the binary message might come from File Adapter. So enable the File Adapter specific message attributes in File Sender channel and get the filename in java mapping using dynamic configuration. Encode the binary stream to Base64 format. Below is the snippet of Java Mapping code for this case. To compile the code we require aii_map_api.jar and aii_utilxi_misc.jar JAR Files in the CLASSPATH environment.

Java Mapping Snippet Code

import com.sap.aii.mapping.api.StreamTransformation;
import com.sap.aii.mapping.api.*;
import com.sap.aii.utilxi.base64.api.*;
import java.io.*;
import java.util.*;

public class Base64EncodingXIStandard implements StreamTransformation{
	String fileNameFromFileAdapterASMA;
	private Map param;
	public void setParameter (Map map)
	{
		param = map;
		if (param == null)
		{
			param = new HashMap();
		}
	}

	public static void main(String args[])
	{
		Base64EncodingXIStandard con = new Base64EncodingXIStandard();
		try
		{
			InputStream is = new FileInputStream(args[0]);
			OutputStream os = new FileOutputStream(args[1]);
			con.execute(is, os);
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}

	}
public void execute(InputStream inputstream, OutputStream outputstream)
    {
			DynamicConfiguration conf = (DynamicConfiguration) param.get("DynamicConfiguration");
			DynamicConfigurationKey KEY_FILENAME = DynamicConfigurationKey.create("http://sap.com/xi/XI/System/File","FileName");
			fileNameFromFileAdapterASMA = conf.get(KEY_FILENAME);
			if (fileNameFromFileAdapterASMA == null)
			{
				fileNameFromFileAdapterASMA = "ToBase64.txt";
			}
		try
		{
			while ((len = inputstream.read(buffer)) > 0)
				baos.write(buffer, 0, len);
			str = Base64.encode(baos.toByteArray());	//buffer);
			outputstream.write("<?xml version=\"1.0\" encoding=\"utf-8\"?><ROOT>".getBytes());
			outputstream.write(("<FILENAME>" + fileNameFromFileAdapterASMA + "</FILENAME>").getBytes());
			outputstream.write( ("<BASE64DATA>" + str + "</BASE64DATA></ROOT>" ).getBytes());
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
	byte[] buffer = new byte[1024*5000];
	ByteArrayOutputStream baos = new ByteArrayOutputStream();
	int len;
	String str = null;
}

Further Enhancements for handling huge binaries

In case if we have to handle huge binary file (in the order of Megabytes) then we can use the chunking concept on the sender side (HTTP or File Adapter). Add an extra import parameter to ZBAPI structure such as IV_FILEMODE and pass the value “append or overwrite” and accordingly handle the same in ZBAPI coding.

Posting Binary Data from R/3 ZBAPI* to XI

We can also post binary data from R/3 to XI. All that we have to do is call the standard bapi SSFC_BASE64_ENCODE in the ZBAPI by passing the read binary file stream as input. It will return the base64 format. Now assign this to one of the ZBAPI field which should be of type string. Do the necessary design and configurations in XI to receive this data and then read and decode base64 format to binary format at mapping or adapter module level according to the requirement.

SAP PI Interview Questions and SAP PI Tutorials

SAP PI Interview Questions and SAP PI Tutorials

Share this:
Share this page via Email Share this page via Stumble Upon Share this page via Digg this Share this page via Facebook Share this page via Twitter
PDF24    Send article as PDF   
This entry was posted in How to Send Binary Data to RFC from XI(or)PI and tagged . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *