SAP PI Java Mapping to append File Contents
Overview
Here, we will see an example of SAP-PI Java Mapping, in which we come to know
- How to use Dyanmic Configuration variables in Java Map
- How to Print Trace log
- How to refer ResourceFile data included in JavaMap.Jar files
This SAP-PI Java map was required in below business scenario:
- One SAP-PI Soap Synchronous web-service has been hosted, where:
- In Soap-Request, client will send FileName starting key words
- and in Soap-Response message, SAP-PI has to return FileContents of one File found in SAP directory with same FileNameKey
- To achieve above, we use this example of JavaMap to populate Soap Response message.
- This Java map is been applied in Response-Tab of Operation Mapping
Functionality of given SAP-PI Java map:
- Get File-Name-Key from SoapRequest payload using Dynamic Configuration
- In Request Mapping, below UDF is been used to get FileNameKey from Soap Request Dynamic Configuration variable
-
String RequestDataStr = ""; RequestDataStr = ReqStr_FileName ; try { // set to dynamic config: DynamicConfiguration conf = (DynamicConfiguration) container .getTransformationParameters().get(StreamTransformationConstants.DYNAMIC_CONFIGURATION); DynamicConfigurationKey key = DynamicConfigurationKey.create("http://sap.com/xi/XI/System/SOAP", "FileName_StartKey" ); if ( conf != null){ conf.put(key, RequestDataStr); } } catch (Exception ex) { ; } return RequestDataStr;
- Get FolderPath details from Resource file ‘FolderPath_details.xml‘ which is included with Jar File itself
- Search directory for files having starting name as of ‘FileNameKey’ and having extension ‘.CSV’ or ‘.csv’
- ‘If file found as per above criteria, extract its content and append it to Target Message format
- And Archive read file to other directory
Pre-requisites:
- SAP-PI 7.1
- Java Map Library (aii_map_api.jar)
- Java Eclipse (to create Java Mapping program)
- Jre 1.6
Steps to create Java Map:
- Create a Java Project in Eclipse
- Import External jar lib file ‘aii_map_api.jar‘
- Go to -> right Click on Project fodler ‘JavaMap_Example-01’ -> Bulid Path -> Configure Build Path -> Tab ‘Libraries’ -> click button ‘Add External Jars’ to import file from local desktop
- Insert Resource File ‘FolderPath_details.xml’
- Insert xml file having path information
- Create one Java Class
- ight Click on Project fodler ‘JavaMap_Example-01’ -> src -> New -> Class -> create a new Java class
- and write JavaMap Source code as given below
-
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.HashMap; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; 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.Attr; import org.w3c.dom.CDATASection; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import com.sap.aii.mapping.api.AbstractTrace; import com.sap.aii.mapping.api.DynamicConfiguration; import com.sap.aii.mapping.api.DynamicConfigurationKey; import com.sap.aii.mapping.api.StreamTransformation; import com.sap.aii.mapping.api.StreamTransformationConstants; import com.sap.aii.mapping.api.StreamTransformationException; public class Example_01 implements StreamTransformation { private String ArchivalPath = ""; private String SourcePath = ""; private AbstractTrace trace = null; private Map param; public void setParameter(Map map){ param = map; if (param == null) { param = new HashMap(); } } public void execute(InputStream in, OutputStream out) throws StreamTransformationException{ try{ trace = (AbstractTrace) param.get(StreamTransformationConstants.MAPPING_TRACE); trace.addInfo("Starting JavaMap 'Example_01'"); //Get FileNameKey using DynamicConfig String FileNameKey = ""; FileNameKey = getFileNameKey(); trace.addInfo("FileName starting key found as: " + FileNameKey); //Get FolderPath from ResourceFile 'FolderPath_details.xml' getFolderPath(); trace.addInfo("SourcePath: " + SourcePath); trace.addInfo("ArchivalPath: " + ArchivalPath); //----Start:Read File from SAPDirectory & Append it to OutputXml ------- String FileName = ""; String FileContent = ""; String ErrorStr = ""; File theDir = new File(SourcePath); if (!theDir.exists()){ //Error message 'SourcePath not found' ErrorStr = "SourcePath '" + SourcePath + "' not found"; }else{ //If directory found, then check if it is empty File[] dirFileList = new File(SourcePath).listFiles(); if (dirFileList.length < 1){ //Error message 'No file found in SourcePath' ErrorStr = "No file found in SourcePath '" + SourcePath + "'"; }else{ //If folder is not empty, the search for files for (int i=0; i<dirFileList.length; i++){ FileName = dirFileList[i].getName(); //Get file name //check if file is having CSV extensions if ((FileName.indexOf(".CSV") != -1) || (FileName.indexOf(".csv") != -1)){ //Now check if FileName is having starting key word if(FileName.startsWith(FileNameKey)){ FileContent = getFileContent(SourcePath + FileName ); //Read file content //Archive file to other directory File file = new File(FileName); String arcFNm = ArchivalPath + "ARC_" + file.getName(); file.renameTo(new File(arcFNm)); ErrorStr = "File found and its content has been read"; break; //break the loop if file found | To return one fileContent at a time } }else{ ErrorStr = "No .CSV/.csv file found"; } } } } //----End :Read File from SAPDirectory & Append it to OutputXml ------- //----Start: Create output XML Document ------------------- DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder dbBuilder = dbFactory.newDocumentBuilder(); Document docOut = dbBuilder.newDocument(); //Create XML RootElement Element rootElmnt = docOut.createElement("ns0:MT_TargetMsg"); docOut.appendChild(rootElmnt); //Append rootElement to Output document //Set Attribute info to RootElement Attr attr = docOut.createAttribute("xmlns:ns0"); attr.setValue("http://Test-01"); rootElmnt.setAttributeNode(attr); //Create child Node Element Chld1 = docOut.createElement("Item"); rootElmnt.appendChild(Chld1); //Create sub child node Element subChld1 = docOut.createElement("FileName"); Chld1.appendChild(subChld1); Node nd1 = docOut.createTextNode(FileName); subChld1.appendChild(nd1); Element subChld2 = docOut.createElement("FileContent"); Chld1.appendChild(subChld2); CDATASection cdataFCS = docOut.createCDATASection(FileContent); subChld2.appendChild(cdataFCS); Element subChld3 = docOut.createElement("Error"); Chld1.appendChild(subChld3); Node nd3 = docOut.createTextNode(ErrorStr); subChld3.appendChild(nd3); //----End : Create output XML Document ------------------- trace.addInfo("Message: " + ErrorStr); //Transform Output Document trace.addInfo("Transforming results to output xml payload"); TransformerFactory tf = TransformerFactory.newInstance(); Transformer transform = tf.newTransformer(); transform.transform(new DOMSource(docOut), new StreamResult(out)); } catch (Exception e) { trace.addInfo(e.getMessage()); } } private void getFolderPath() throws IOException, ParserConfigurationException, SAXException { /* This function helps to get folder path details from resource 'FolderPath_details.xml' Jar file of this map will include resource file 'FolderPath_details.xml' */ //Get reference of ResourceFile 'FolderPath_details.xml' InputStream is_ShpCrd = getClass().getResourceAsStream("FolderPath_details.xml"); //Parse input to create document tree DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder dbBuilder = dbFactory.newDocumentBuilder(); Document xmlDoc_ShpCrd = dbBuilder.parse(is_ShpCrd); //Read XmlElement tag to fetch SharePoint_Credentials NodeList ndList_1 = xmlDoc_ShpCrd.getElementsByTagName("Path"); for(int i1 = 0; i1 < ndList_1.getLength(); i1++){ Node nd_1 = ndList_1.item(i1); for(Node nd_2 = nd_1.getFirstChild(); nd_2 != null; nd_2 = nd_2.getNextSibling()){ if(nd_2.getNodeName().equals("SourcePath")){ SourcePath = nd_2.getFirstChild().getNodeValue(); } if(nd_2.getNodeName().equals("ArchivalPath")){ ArchivalPath = nd_2.getFirstChild().getNodeValue(); } } } } private String getFileNameKey() throws IOException { /* This function helps to get FileName starting Key word using DynamicConfiguration variable which is set from SoapRequestPayload */ String FileNameKey = ""; try{ DynamicConfiguration conf = (DynamicConfiguration)param.get("DynamicConfiguration"); DynamicConfigurationKey key = DynamicConfigurationKey.create("http://sap.com/xi/XI/System/SOAP", "FileName_StartKey"); if(conf != null){ FileNameKey = conf.get(key); } }catch(Exception e) { trace.addInfo(e.getMessage()); } return FileNameKey; } private String getFileContent(String filePath) throws IOException { /* * This Function read file content into String * */ FileInputStream fin = new FileInputStream(new File(filePath)); java.util.Scanner scanner = new java.util.Scanner(fin,"UTF-8").useDelimiter("\\A"); String theString = scanner.hasNext() ? scanner.next() : ""; scanner.close(); return theString; } /* public static void main(String[] args) { try{ Example_01 myClass = new Example_01(); FileInputStream in = new FileInputStream("C:/Request_Input_2.xml"); FileOutputStream out = new FileOutputStream("C:/Output.xml"); myClass.execute(in, out); }catch (Exception e){ e.printStackTrace(); } } */ }
- Create Jar File of Java Map
- right Click on Project fodler ‘JavaMap_Example-01’ -> Export -> Java -> JAR File -> Click Next -> give Jar name -> select resource -> Finish
- Import JavaMap Jar file to SAP -PI as a ‘Imported Archive’
Hi,
Which adapter you have used in the receiver end?
Thanks,
Apu
Hi Apu,
Sorry for delayed response...
At receiver end we have used File-Adapter, that will create a File with fix name in to SAP-Directory, which will be overwritten for each processing. The purpose of this File-Receiver is to complete the scenario only.
Thanks & Regards,
Dilip
Hi Dilip!
It sounds a bit unclear. As I could understand you use Synchronous sender interface with file mask in request message and in response message you get the file contents if the file with given mask exists at defined location. Am I right? If so, what is the receiver of your synchronous reguest? And where do you use receiver file adapter?
Regards, Evgeniy.
Thanks for your reply.
How you maintain the paths in the FolderPath_details.xml.
What will be the path if my NFS directory is - /data/123/
/data/123/archive/
You can enhance this JAVA mapping further using FTPClient class to pull data content from FTP.
Thanks,
Apu
Dear Apu,
In FolderPath_details.xml, paths will be maintained as:
And thanks for your suggestions about FTPClient, will try for sure in next requirement.
Thanks & Regards,
Dilip
Hi Dilip,
I am still not sure about the path is required to maintain. What is /folder-sap/?
Can yoy please tell what will be exact path to maintain ?
Thanks,
Apu
Dear Apu,
Please do no get confused with '/folder-sap/' its only for example purpose. Let me explain in this manner:
In this case, in Java Map scenario:
Please note:
Thanks & Regards,
Dilip
Hi Dilip!
And when the path is changed by any case, we should make changes in resource file and import/transport that new jar between all PI systems involved?
Regards, Evgeniy.
Dear Evgeniy Kolmakov,
Thanks & Regards,
Dilip
Hi Dilip!
Thanks for the answer. And why not to use Operation mapping parameters instead? It can be changed on the fly.
Regards, Evgeniy.
Dear Evgeniy Kolmakov,
I have to check, how I can use Operation mapping parameters in this case.
Thanks for the hint.
Thanks & Regards,
Dilip
Hi Dilip!
This is very simple step: just define respective parameters in Operation mapping and assign it to your java mapping. In java mapping just read it.
Regards, Evgeniy.
Sure, will try it. Thanks for new info.
Thanks & Regards,
Dilip
Dear Evgeniy Kolmakov,
Let me put this scenario in below manner for more clarity:
Hope above helps...
Thanks & Regards,
Dilip