SAP Process Orchestration, SAP Process Integration

SAP PI/PO – Java Mapping Create attachments – SFTP

I just would like to post one solution for a project that the requirement to write down the files in the SFTP server must follow the order – first PDF and the corresponding XML for each PDF’s.

Integration Diagram:

Outbound interface – Abap proxy with attachments (application/pdf and application/xml) in SAP PI transformation of reading stream attachments, create new attachments with the dynamic name of the XML file get previously in the message mapping using UDF – GET FILENAME and generating new attachments as (application/xml) setting the main payload as (application/xml), create the ICO with order processing mapping and two channels SFTP receiver because the attachments and the main payload contains Content-Type different and this is not possible to handle in the SFTP channel two different extensions –

Also Read: SAP PO Certification Preparation Guide

You can develop a custom module adapter to solve it but in the duty of time, I did this solution.

Rules:

  1. Tag – : Subelement of the element . With version 2.0 it’s possible to attach more than one PDF file to a request (e.g. invoices, packaging lists). Additionally, the filenames of files attached to a request may now be chosen by the applicant without any restrictions. To be able to assign the files to a request, it’s necessary to indicate the name of the file in the new element .
  2. The elements and need not to be included in the XML file under the following conditions:
    – There is only one PDF file which has to be attached to the request. In this case, the name of
    the PDF file must be equal to the one of the XML file (except the file extension)
    – The file to be attached to the request has also to be certified.
  3. If your XML file doesn’t contain the elements and , the XML file
    and the corresponding document must have the same filename (except the file extension)
    – If your XML file contains these two elements, you’re free to use any filename for the PDF files to be attached to the request. In this case, the element must reflect the name of a corresponding file.
    – In any case, the additional documents must be uploaded to the server before uploading the corresponding XML file.

Clear for you?

Let’s rock!

Integration Development Steps:

  1. Repository:
    1. Imported Archives – JavaMapping
    2. Message Mapping – UDF – SetFileName
    3. Two Operation Mappings – First – XML – Second: Payloads – PDF
  2. Directory:
    1. ICO Receiver Interface
    2. ICO Outbound Processing SFTP Channels

Process steps – Repository:

  • Repository: Imported Archives – JavaMapping

Rename Attachments java:

package yourpackage;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.Collection;

import com.sap.aii.mapping.api.AbstractTransformation;
import com.sap.aii.mapping.api.Attachment;
import com.sap.aii.mapping.api.DynamicConfiguration;
import com.sap.aii.mapping.api.DynamicConfigurationKey;
import com.sap.aii.mapping.api.InputAttachments;
// import com.sap.aii.mapping.api.StreamTransformation;
// import com.sap.aii.mapping.api.StreamTransformationConstants;
import com.sap.aii.mapping.api.StreamTransformationException;
import com.sap.aii.mapping.api.TransformationInput;
import com.sap.aii.mapping.api.TransformationOutput;
import com.sap.engine.interfaces.messaging.api.auditlog.AuditLogStatus;

public class RenameAttachments extends AbstractTransformation {

	public static void main(String[] args) throws Exception {

		FileInputStream inFile = new FileInputStream("C:\\Users\\luzholar\\Desktop\\Payload.xml"); 
		FileOutputStream outFile = new FileOutputStream("C:\\Users\\luzholar\\Desktop\\Payload2.xml");

		new RenameAttachments().local(inFile, outFile);
	} 

	private void local(FileInputStream inFile, FileOutputStream outFile) throws Exception{

		String xmlPayload= "";
		xmlPayload="<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
		xmlPayload = xmlPayload.concat("<ns0:FileInfoGeneric xmlns:ns0=\"http://roche.com/rp/EM/CH/LAL/Common\">");
		xmlPayload = xmlPayload.concat("<Receivers>");
		xmlPayload = xmlPayload.concat("<Receiver/>");
		xmlPayload = xmlPayload.concat("</Receivers>");
		xmlPayload = xmlPayload.concat("<Name>");
		xmlPayload = xmlPayload.concat("test");
		xmlPayload = xmlPayload.concat("</Name>");
		xmlPayload = xmlPayload.concat("</ns0:FileInfoGeneric>");

		outFile.write(xmlPayload.getBytes("UTF-8"));

	}

	private static final DynamicConfigurationKey KEY_FILENAME = DynamicConfigurationKey.create("http://sap.com/xi/XI/System/File","FileName");

	public void transform(TransformationInput in, TransformationOutput out) throws StreamTransformationException {
		try {
			AuditLogHelper logger = AuditLogHelper.getInstance(in.getInputHeader().getMessageId());
			logger.log("**** Java Mapping Starting ******", AuditLogStatus.SUCCESS);
			OutputStream outputstream = out.getOutputPayload().getOutputStream();
			String xmlPayload= "xml";
			DynamicConfiguration conf = in.getDynamicConfiguration();
			String fileName = "";
			fileName = conf.get(KEY_FILENAME);
			logger.log("Dynamic name of XML: "+ fileName, AuditLogStatus.SUCCESS);
			String fileNamepdf = fileName.replace(".xml", "");
			logger.log("Dynamic name of PDF Attachment(s): "+ fileNamepdf, AuditLogStatus.SUCCESS);
			Object[] arrayObj = null;
			String attachmentID = null;
			InputAttachments inputAttachments = in.getInputAttachments();
			if (inputAttachments.areAttachmentsAvailable()) {
				// gets the attachmentIds and store it in an Object array
				Collection<String> collectionIDs = inputAttachments.getAllContentIds(true);
				arrayObj = collectionIDs.toArray();
				// Object[] arrayObj = collectionIDs.toArray();
				// Loops at the input attachments to get the content of the attachment and then
				int counter = 1;
				for (int i = 0; i < arrayObj.length; i++) {
					attachmentID = (String) arrayObj[i];
					Attachment attachment = inputAttachments.getAttachment(attachmentID);
					byte[] attachmentBytes = attachment.getContent();
					logger.log("Content-Type: "+ attachment.getContentType(), AuditLogStatus.SUCCESS);
					Attachment newopAttachment = out.getOutputAttachments().create(fileNamepdf+"_" + counter +".pdf", "application/pdf; name="+fileNamepdf+"_" +counter +".pdf",attachmentBytes);
					out.getOutputAttachments().setAttachment(newopAttachment);
					out.getOutputAttachments().removeAttachment(attachmentID);
					logger.log("New Attachment: "+ newopAttachment.getContentType(), AuditLogStatus.SUCCESS);
					counter++;
				}
				logger.log("**** Java Mapping End ******", AuditLogStatus.SUCCESS);
			}
			outputstream.write(xmlPayload.getBytes("UTF-8"));
		} catch (Exception e) {
			throw new StreamTransformationException("Error: " + e.getMessage());
		}
	}
}
  • Repository: Imported Archives – JavaMapping

Audit Logger java:

import com.sap.engine.interfaces.messaging.api.MessageDirection;
import com.sap.engine.interfaces.messaging.api.MessageKey;
import com.sap.engine.interfaces.messaging.api.PublicAPIAccessFactory;
import com.sap.engine.interfaces.messaging.api.auditlog.AuditAccess;
import com.sap.engine.interfaces.messaging.api.auditlog.AuditLogStatus;

public class AuditLogHelper {

	private static final String DASH = "-";
	
	private static boolean isInitialize = false;
	
	private static AuditAccess auditAccess;

	private MessageKey messageKey;
	
	private static void initialize() throws Exception {
		auditAccess = PublicAPIAccessFactory.getPublicAPIAccess().getAuditAccess();
	}
	
	private AuditLogHelper(MessageKey messageKey) throws Exception {
		this.messageKey = messageKey;
	}

	public static AuditLogHelper getInstance(String messageId) throws Exception {
		
		if(!isInitialize)
			initialize();
		
		String msgUUID = messageId.substring(0, 8) + DASH + messageId.substring(8, 12) + DASH
				+ messageId.substring(12, 16) + DASH + messageId.substring(16, 18) + messageId.substring(18, 20) + DASH
				+ messageId.substring(20, 32);
		
		MessageKey messageKey = new MessageKey(msgUUID, MessageDirection.OUTBOUND);
		
		return new AuditLogHelper(messageKey);
	}

	public void log(String message, AuditLogStatus status) {
		auditAccess.addAuditLogEntry(messageKey, status, message);
	}

	public void setMessageKey(MessageKey messageKey) {
		this.messageKey = messageKey;
	}

}
  • Repository: Message Mapping – UDF – SetFileName

First rule logic from the requirement – FileName based in the XML tags:

Why you implement this logic just to setup the filename? Check the rules above.

  • Message Mapping – UDF – SetFileName

I set up the UDF in the ROOT of the XML – ROOT – LOGIC + UDF – ROOT.

UDF – setFileName:

MappingTrace trace;
trace = container.getTrace();
trace.addInfo("FileName: " + FName);

try
{
	DynamicConfiguration conf=(DynamicConfiguration) container.getTransformationParameters().get(StreamTransformationConstants.DYNAMIC_CONFIGURATION);

	// SAP standard
	DynamicConfigurationKey key=DynamicConfigurationKey.create("http://sap.com/xi/XI/System/File","FileName");
	if (conf != null)	{ 
			 conf.put(key,FName); 
	 }

	// SAP SFTP Standard
	DynamicConfigurationKey sapSFTPkey=DynamicConfigurationKey.create("http://sap.com/xi/XI/System","FileName");
	conf.put(sapSFTPkey,FName); 

	// SFTP Seeburger
	DynamicConfigurationKey sftpkey=DynamicConfigurationKey.create("http://seeburger.com/xi/common","dtSubject");
	conf.put(sftpkey,FName);

	DynamicConfigurationKey sftpAN=DynamicConfigurationKey.create("http://seeburger.com/xi/common","dtAttachmentName");
	conf.put(sftpAN,FName);

	// AS2 Seeburger
	
	DynamicConfigurationKey as2Key=DynamicConfigurationKey.create("http://seeburger.com/xi/AS2","dtAS2FileName");
	conf.put(as2Key,FName);

}
catch (Exception e)
{
	return ("ERROR");
}

return (FName);
  • Repository: Two Operation Mappings – First – XML – Second: Payloads – PDF

Set XML – The main payload will be set up here so no read the attachments

Set PDF – Message Mapping to generate the Dynamic Configuration of the PDF files and java mapping to rename the attachments correct based on this dynamic name definition:

Process steps – Directory:

  • ICO Receiver Interface

With this correct order first, write the PDF or PDF files with the same name as the main payload XML, which will be ok.

This is the tricky part to attend the requirement of first save the PDF(s) files related to the main XML before the XML always.

You just need to order the two mappings to be processed by the pipeline and mark (Maintain Order at Runtime) because in case of the receiver SFTP adapter receiver of PDF will be off, the messages will get stuck and will not store the XML file in the another SFTP adapter receiver.

  • ICO Outbound Processing SFTP Channels

Why two receiver channels?

Basically, it’s a tricky point, the name of XML and PDF must be the same in many conditions but the extension will be always different in this case it’s not possible to handle in only one channel because the name of PDF files will be always – File.xml.pdf

I believe you can solve it with a custom module adapter but I was without time.

Testing with SOAPUI Call with attachments – Simulating the PROXY with attachments:

SOAPUI with attachments:

Name of the attachments:

  • bilet_94186535.pdf
  • Bilet_elektroniczny_ohgyrc9d-7747__BiletomatPL.pdf

After the java mapping execution:

TagName:

  • <Dateiname> TEST BLOG JAVA MAPPING ATTACHMENTS

Attachments:

  • TEST BLOG JAVA MAPPING ATTACHMENTS_1.pdf
  • TEST BLOG JAVA MAPPING ATTACHMENTS_2.pdf

Logs from Audit Logger java:

SFTP Server:

Rating: 0 / 5 (0 votes)

Leave a Reply

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