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:
- 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 .
- 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. - 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:
- Repository:
- Imported Archives – JavaMapping
- Message Mapping – UDF – SetFileName
- Two Operation Mappings – First – XML – Second: Payloads – PDF
- Imported Archives – JavaMapping
- Directory:
- ICO Receiver Interface
- ICO Outbound Processing SFTP Channels
- ICO Receiver Interface
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: