Dynamic Sender File Pickup based on Current Date
Introduction
Recently one of the requirement is to pick up the file based on current date, the monthly files are placed in respective year folder in the sender FTP server like below. Monthly files for 2015:
Monthly files for year 2016:
So we need to pick up the file from folder 2016 which is current year and need to pick up May.txt which is current month. You can find the discussion here SAP PI 7.31 – Dynamic Sender File Pickup based … | SCN
Sender file adapter does not support dynamic file name and dynamic directory only it supports in the receiver side. So the approach is to use enhanced receiver determination using java mapping, with in the java mapping if the file name and folder are in current month and year then set the receiver otherwise don’t set the receiver then all other files will be ignored by PI without creating the message. this is one of the way to do this requirement without any further custom developments. This is the reference document to consider this option in future for this kind of similar requirements.
Design
The file is not a XML file, it will be binary file so i am using below data type for both sender and receiver, we can use any data type because i am using java mapping for this scenario because we cannot use message mapping.
I am using below message type for both sender and receiver and service interfaces.
I am using interface pattern Stateless (XI30-Compatible) because we picking up binary file and if we use other interface pattern at run time system will try to read the root node of the message and we will get an error because our file is not an XML.
I am using below operation mapping for dynamic receiver in ICO. Sender service interface which we created above and receiver interface is standrad ReceiverDetermination from SAP BASIS software component.
Java mapping is to read the sender file name and directory using dynamic configuration and compare with current date and current month, if both are equal then i am setting the receiver otherwise i am not setting the receiver, so only for current month file will have the receiver all other files will be ignored because of no receiver.
import com.sap.aii.mapping.api.AbstractTrace;
import com.sap.aii.mapping.api.AbstractTransformation;
import com.sap.aii.mapping.api.DynamicConfiguration;
import com.sap.aii.mapping.api.DynamicConfigurationKey;
import com.sap.aii.mapping.api.OutputPayload;
import com.sap.aii.mapping.api.StreamTransformationException;
import com.sap.aii.mapping.api.TransformationInput;
import com.sap.aii.mapping.api.TransformationOutput;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class FileNameFilterJavaMap
extends AbstractTransformation
{
public void transform(TransformationInput transformationInput, TransformationOutput transformationOutput)
throws StreamTransformationException
{
try
{
DynamicConfiguration conf = transformationInput.getDynamicConfiguration();
String fileName = conf.get(DynamicConfigurationKey.create("http://sap.com/xi/XI/System/File", "FileName"));
String dir = conf.get(DynamicConfigurationKey.create("http://sap.com/xi/XI/System/File", "Directory"));
Date date = new Date();
String month = new SimpleDateFormat("MMM").format(date);
String year = new SimpleDateFormat("yyyy").format(date);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setIgnoringElementContentWhitespace(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document outputDoc = builder.newDocument();
Element receivers = outputDoc.createElement("Receivers");
receivers.setAttribute("ns0", "http://sap.com/xi/XI/System");
outputDoc.appendChild(receivers);
Element receiver = outputDoc.createElement("Receiver");
receivers.appendChild(receiver);
Element service = outputDoc.createElement("Service");
if ((fileName.startsWith(month)) && (dir.endsWith(year))) {
service.setTextContent("BC_RECEIVER");
}
receiver.appendChild(service);
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty("indent", "yes");
transformer.transform(new DOMSource(outputDoc), new StreamResult(transformationOutput.getOutputPayload()
.getOutputStream()));
}
catch (Exception e)
{
getTrace().addDebugMessage(e.getMessage());
throw new StreamTransformationException(e.getMessage());
}
}
}
Configuration
I have created below IFlow using dynamic receiver with above created java mapping.
Select the operation mapping which we created above in Dynamic Routing section in IFlow properties.
Configure the routing behavior like below routing technique as Dynamic Message Router and if the receiver not found Ignore this error option.
Mention multiple folders in the sender channel using additional source file selection option like below.
We are not going to delete the files in the source directory so mention the processing mode as Test
Enable File Name and Directory in the sender channel under Adapter-Specific Message Properties
Mention the receiver directory and file name as * or %FileName% because it will be ignored by the adapter as we are using dynamic configuration.
Enable File Name attribute in Adapter-Specific Message Properties of receiver channel.
We can schedule the sender channel to run every month to pick up the respective file from respective folder.
Testing
When we run the scenario the adapter will read all the files and ignore the files which is not current moth and year because of no receiver could be determined, we can see in the channel logs like below.
It only create the message for current month and current year which is May.txt from 2016 folder, as you can see in the audit log only May.txt file only sent to the receiver directory.
We can find the current month file in target directory.
Conclusion
By using enhanced receiver determination in ICO we can ignore all other unrelated files and only pick up the the file based on current date. it will be useful for who ever get this kind of similar requirement in future.
Nice and useful one Praveen.
Thanks Praveen !! That's an awesome blog.
Fantastic solution, Praveen! Really great out-of-the-box thinking to resolve such an uncommon requirement.
Thanks Eng/Kiran/Ragu for the positive feedback.
Thanks for sharing such a clean approach for such requirement.
Praveen,
Great blog, but by mentioning processing mode as test the same file may get processed again? For this I guess we need to enable duplicate check at channel level.
Hi Manoj,
I already mentioned in the blog we need to schedule the sender channel monthly so that the channel pick up the different file every month, it wont be duplicates
"We can schedule the sender channel to run every month to pick up the respective file from respective folder."
Regards,
Praveen.
Oh i forgot to see the pool interval you have set as 24 hour (86400 sec) ..
Hi Manoj,
Nice blog... But I have doubt on Directory side that is fixed right?
Regards
Gagan
Hi Praveen
Thanks for sharing the information. It was very informative.
However, I can see that you have hardcoded the directory paths with the year.
/home/xi/test/out/2016
/home/xi/test/out/2015.
I was wondering if we can do something like /home/xi/test/out/* in order to cater to the all the directories generated for all the future years too.
I tried using * as wild card but it doesn't work. Any thoughts?
Regards
Sonal
Hi Praveen,
We have got a similar requirement with slight modification. This doesn't involve any mapping as we need file transfer of .zip file. The file will be something like "Test_20200226_T.zip" and we want to use enhanced receiver determination to send the file based on system date. So, if filename contains system date only then it should be sent to receiver else ignored.
My question is, will this java mapping work for .zip type file as well? if not can you suggest what changes we should do handle for .zip file?
Thanks