cancel
Showing results for 
Search instead for 
Did you mean: 

base64 string to put binary file into ftp server using receiver ftp adapter

former_member229036
Participant
0 Kudos

Hi guru;

i have been searched the article helping my issue, but i do not have good article or documents helping to me.

so, anyway source system tried to convert binary file(excel or image or pptx . etc) into base64 encode string in one of parameter(string type) in DT ,,

PI(7.5) will decode param1 encoded base64 string as following decode source

and then how can i make decode string to be sending binary file to remote ftp server using receiver file adapter ?

also java mapping might help me ,, welcome java mapping or udf to me.

decode source is like below;

Base64.Decoder decoder = Base64.getDecoder();

byte[] decodedByteArray = decoder.decode(encodstring.getBytes("UTF-8"));

Thank you

Benjamin

Accepted Solutions (0)

Answers (4)

Answers (4)

former_member190293
Active Contributor

Hi Benjamin!

With java mapping you can directly send your byte array to output stream to get binary payload as the result:

public void transform(TransformationInput in, TransformationOutput out)throws StreamTransformationException {
// Your code here
OutputStream os = out.getOutputPayload().getOutputStream();
os.write(decodedByteArray);}

Regards, Evgeniy.

former_member229036
Participant
0 Kudos

hi Sugata Bagchi Majumder,

i tryied to test with the above format # 3 and i did not use DynamicConfiguration for simple testing .

String b64Str = nodeListToString(nodels);//b64Str is the base64 string for the data type

byte [] b64bytes= Base64.decodeBase64(b64Str); arg1.getOutputPayload().getOutputStream().write(b64bytes);

the aaaa.pptx was created in remote ftp server through file adapter as binary mode, it's same size by original pptx file.

but could not opened it. also used in java mapping, but same issue.

byte [] b64bytes= Base64.decodeBase64(b64Str.getBytes("UTF-8"));

do i have to something in configuration receiver file adapter ?

Thanks

Benjamin

sugata_bagchi2
Active Contributor
0 Kudos

Hi Benjamin,
Depending on how you are getting the request message, the approach will differ.
will you get the data type multiple times in your source payload ? something like this -

<Records>
<base64Data>base64 data for Excel1</base64Data>
<base64Data>base64 data for Excel2</base64Data>
<base64Data>base64 data for Excel3</base64Data>
</Records>

or a mixed data ?

<Records>
<base64Data>base64 data for Excel1</base64Data>
<base64Data>base64 data for iamge2</base64Data>
<base64Data>base64 data for ppt3</base64Data>
</Records>

or only a single type of data only once at a time?

<Records>
<base64Data>base64 data for Excel1</base64Data>
</Records>

if you are getting the data in the above format # 3 -

you can try using the below java mapping and maintain the parameter in receiver file channel - file type as Binary.

package com.sap.ConvertBase64toStream;
import java.io.InputStream;
import java.io.StringWriter;
import org.apache.commons.net.util.Base64;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import com.sap.aii.mapping.api.AbstractTransformation;
import com.sap.aii.mapping.api.StreamTransformationException;
import com.sap.aii.mapping.api.TransformationInput;
import com.sap.aii.mapping.api.TransformationOutput;

public class ConvertBase64toStream extends AbstractTransformation 
{
public void transform(TransformationInput arg0, TransformationOutput arg1) throws StreamTransformationException
    
    {
     getTrace().addInfo("JAVA Mapping Called");
     try
     {
            InputStream isData = arg0.getInputPayload().getInputStream();
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            Document doc = dbf.newDocumentBuilder().parse(isData);
            doc.setXmlStandalone(true);
            XPath xPath = XPathFactory.newInstance().newXPath();
            /*I have used Java Xpath to extract Block of XML, this can be passed as a parameter as well from interface determination
             *Better to parameterize the Xpath, if there is a change in source structure this code will not work.
             *The Xpath expression can be passed as parameter using below code snippet
             *String xpathV = transformationInput.getInputParameters().getString("XPATH");
             * XPATH value should be maintained in interface determination and must be binded in operation mapping in ESR.
             * Then the below statement can be modified as -
             * NodeList nodels = (NodeList)xPath.evaluate(xpathV, doc, XPathConstants.NODESET);
             */
            NodeList nodels = (NodeList)xPath.evaluate("Records/base64Data", doc, XPathConstants.NODESET);
            String b64Str = nodeListToString(nodels);//b64Str is the base64 string for the data type
            byte [] b64bytes= Base64.decodeBase64(b64Str);
            try
            {
            arg1.getOutputPayload().getOutputStream().write(b64bytes);
            }
            catch(Exception e)
             {
                e.toString();
             } 
            
         
     }
     catch (Exception e)
     {
         e.printStackTrace();
     }
    
    }

private static String nodeListToString(NodeList nodels) throws TransformerException 
{
 DOMSource source = new DOMSource();
 StringWriter writer = new StringWriter();
 StreamResult result = new StreamResult(writer);
 Transformer transformer = TransformerFactory.newInstance().newTransformer();
 transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
 for (int i = 0; i < nodels.getLength(); ++i)
    {
     source.setNode(nodels.item(i));
     transformer.transform(source, result);
    }
 return writer.toString();
}
}

But , there will be an issue even if you get only one base64 string at once, if the type of base64 is different every time. eg.- pdf, ppt,image etc. in that case the file name needs to be dynamically changed based on the type of file you receive. It will be better in that case, if you can add another field in your data type say - filetype or even the filename(better to have this). the source will look like this -

<Records>
<FileName>ABC.xls</FileName>
<base64Data>base64 data for Excel1</base64Data>
</Records>

And you can add something to the Java mapping -

add the below imports -

import com.sap.aii.mapping.api.DynamicConfiguration;
import com.sap.aii.mapping.api.DynamicConfigurationKey;

and the below code snippet after this line in the existing code- byte [] b64bytes= Base64.decodeBase64(b64Str);

Add the below code -

DynamicConfiguration dynConfig = arg0.getDynamicConfiguration();
            DynamicConfigurationKey key1 = DynamicConfigurationKey.create("http:/"+"/sap.com/xi/XI/System/File","FileName");
            NodeList fnode = (NodeList)xPath.evaluate("Records/FileName", doc, XPathConstants.NODESET);
            String fname = nodeListToString(fnode);
            dynConfig.put(key1,fname);

And if you do not want to add the Dynamic file name using Java code,you can use the previous code and populate the file name using variable substitution.

In the Java mapping add the external Jar file - commons-net-3.6.jar from

https://commons.apache.org/proper/commons-net/download_net.cgi

Thanks

Sugata

vinaymittal
Contributor
0 Kudos

Hello,

You can use the byte array to set attachment in java mapping.

Check out this thread for code to set attachments

https://answers.sap.com/questions/12630857/sap-pipo-rest-to-file-download-file-from-url-which.html

Regards vinat