Skip to Content

Through this demo I would like to show that majority of the complex scenarios in SAP PI/PO can be implemented without a  Netweaver BPMN. However this requires good knowledge of Java Mapping.

In this demo I have used a java mapping to achieve the complex functionality instead of Netweaver BPMN. Hopefully this demo helps resources who are comfortable in java mapping.

Below is the flow of complex scenario :

Steps Implemented In Java Map:

1) Have attached the java map for your reference. I am making an effort to explain the steps I did in the java map to achieve the above functionality.

2) The first point I would like to highlight in the java map is that I have declared “transform” method as synchronized.

Normally this method will be as below :

public void  transform(TransformationInput arg0, TransformationOutput arg1)                throws StreamTransformationException {}

 

In this scenario I have added  “synchronized” keyword to this method .The reason being in real time or production  multiple files will be coming at the same time .So adding “synchronized” keyword ensures that all  files processing is in sequence.

public synchronized void  transform(TransformationInput arg0, TransformationOutput arg1)                throws StreamTransformationException {}

3) Next step in the java map is to create the trace instance.This helps in debugging during development and testing in UAT.One needs to comment these lines before moving to the production.

trace = this.getTrace();

4) Next  step is to create DOM parser instance.Input stream is passed as parameter for the Dom parser.

  //create instance of document builder factory
    DocumentBuilderFactory domBuilderFactory=DocumentBuilderFactory.newInstance();

                                               

  //from document builder factory build dom builder.                  

  DocumentBuilder domBuilder=domBuilderFactory.newDocumentBuilder();

                                               

//from document builder,parse the input stream
Document dom=domBuilder.parse(arg0.getInputPayload().getInputStream());
5)Next step is to set the value of class variable “ isSales=NO” . After reading each file ,based on the file type this value will be set.

6)Next step is to call the method “traversingXML” . To this method  dom instance is passed as parameter.This method is recursive method i.e., calls itself until the entire xml payload is read.

 

String result=traversingXML(dom);

 

The objective of this method is to determine the type of file :

6.1)  Sales file will contain node names as “RetailTransaction” or “WN:BSCMTransaction” or “ControlTransaction”. Once these node names are found set the  variable   isSales=”YES”,msgType=”SALES”.

 

if(nodeName.equals(“RetailTransaction”)||nodeName.equals(“WN:BSCMTransaction”)||nodeName.equals(“ControlTransaction”)){

                             isSales=”YES”;                                                                         msgType=”SALES”;                             }

 

6.2)  SOQ file will contain node names as “SOQ” Once these node names are found set the  variable   isSales=”NO”,msgType=”SOQ”.

 

else if(nodeName.equals(“SOQ”)){

                                                                                isSales=”NO”;

                                                                                msgType=”SOQ”;

                                                                }

6.3)  EODConfirmation file will contain node names as “EODConfirmation.Once these node names are found set the  variable   isSales=”NO”,msgType=”inventorycount”.

 

else if(nodeName.equals(“EODConfirmation”)){

                                                                                isSales=”NO”;

                                                                                msgType=”inventorycount”;

                                                                }

6.4) Other files  contain nodevalues as  “goodsreceipt” or  “poreturn” or etc… .

 

7) Now the file is determined ,next step is to place the file in appropriate folder:

Here  dynamic configuration parameters are used.

 

If the  file is sales file then  directory is set as “poslogsales”

 

If the file not sales ,then the transaction in file is checked for duplicity.This is done by calling RFC.

 

//RFC call to check the Transaction duplicity. 

String returnValue = performRFCLookup(bDate, fileName, bTime, seuquenceNo, storeNo, workstationId,SERVICE,CHANNEL_NAME,messageType);

 

If the RFC returns “4”  then it means transaction is duplicate and file is placed in duplicate folder.

else if(returnValue.equals(“4”)){
directory=”/”+posDir+”/”+dupDir;  }

 

If the RFC returns “0”  then it means transaction is not duplicate and file is placed in respective folder.

if(returnValue.equals(“0”)){                                                                                                                            

 if(msgType.equals(“goodsreceipt”)){

directory=”/”+posDir+”/goodsreceipt”;                                                                                                       

}   }
Configuration Screenshot:

Below is the complete Java Code :

package iris_call_rfc_removeduplicatefiles;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

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.StreamTransformationException;
import com.sap.aii.mapping.api.TransformationInput;
import com.sap.aii.mapping.api.TransformationOutput;
import com.sap.aii.mapping.lookup.LookupService;

public class RemoveDuplicateFiles_Through_RFC_Call_JavaMap extends AbstractTransformation {

public StringBuffer endResult = new StringBuffer();
public String isSales=””;
public String msgType=””;
public String msgFct=””;
public String inputFileName=””;
// Enable tracing
private static com.sap.aii.mapping.api.AbstractTrace trace = null;
public synchronized void transform(TransformationInput arg0, TransformationOutput arg1)
throws StreamTransformationException {

try
{
trace = this.getTrace();
//create instance of document builder factory
DocumentBuilderFactory domBuilderFactory=DocumentBuilderFactory.newInstance();

//from document builder factory build dom builder.
DocumentBuilder domBuilder=domBuilderFactory.newDocumentBuilder();

//from document builder,parse the input stream
Document dom=domBuilder.parse(arg0.getInputPayload().getInputStream());

isSales=”NO”;

String result=traversingXML(dom);

String posDir=(String)arg0.getInputParameters().getString(“posDir”);
String newDir=(String)arg0.getInputParameters().getString(“newDir”);
String dupDir=(String)arg0.getInputParameters().getString(“dupDir”);
String SERVICE = (String)arg0.getInputParameters().getString(“SERVICE”); // Name of service defined in XI configuration
String CHANNEL_NAME = (String)arg0.getInputParameters().getString(“CHANNEL_NAME”); ; // Name of communication channel defined for service

DynamicConfiguration conf = arg0.getDynamicConfiguration();
DynamicConfigurationKey KEY_FILENAME =
DynamicConfigurationKey.create(“http://sap.com/xi/XI/System/File”,”FileName”);

DynamicConfigurationKey KEY_DIRECTORY =
DynamicConfigurationKey.create(“http://sap.com/xi/XI/System/File”,”Directory”);

DynamicConfigurationKey KEY_SourceFileTimeStamp =
DynamicConfigurationKey.create(“http://sap.com/xi/XI/System/File”,”SourceFileTimestamp”);

inputFileName=conf.get(KEY_FILENAME);

String SourceFileTimeStamp=conf.get(KEY_SourceFileTimeStamp);

String directory=””;

if(msgType.equals(“goodsreceipt”))
{
isSales=”NO”;
}

if(isSales.equals(“YES”)){
//directory= posDir+”/”+newDir;

if(msgType.equals(“SALES”)){
directory=”/”+posDir+”/poslogsales”;
inputFileName=convertTimeTewelveHoursBack(SourceFileTimeStamp)+”_”+inputFileName;
conf.put(KEY_FILENAME,inputFileName );
}

}else{

String fileName=inputFileName;

NodeList transactionList= dom.getElementsByTagName(“Transaction”);
for(int k=0;k<transactionList.getLength();k++){
String businessDate= “”;
businessDate=((Element)transactionList.item(k)).getElementsByTagName(“BeginDateTime”).item(0).getFirstChild().getTextContent();
String obj[]=businessDate.split(“T”);
String bDate=obj[0].replaceAll(“-“, “”).trim();
String bTime=obj[1].replaceAll(“:”, “”).trim();

String messageType= msgType;

String seuquenceNo= ((Element)transactionList.item(k)).getElementsByTagName(“SequenceNumber”).item(0).getFirstChild().getTextContent();

String storeNo= ((Element)transactionList.item(k)).getElementsByTagName(“RetailStoreID”).item(0).getFirstChild().getTextContent();

String workstationId= ((Element)transactionList.item(k)).getElementsByTagName(“WorkstationID”).item(0).getFirstChild().getTextContent();

trace.addWarning(bDate+”*”+fileName+”*”+bTime+”*”+seuquenceNo+”*”+storeNo+”*”+workstationId+”*”+SERVICE+”*”+CHANNEL_NAME+”*”+messageType);

//RFC call to check the Transaction duplicity.

String returnValue = performRFCLookup(bDate, fileName, bTime, seuquenceNo, storeNo, workstationId,SERVICE,CHANNEL_NAME,messageType);

if(returnValue.equals(“0”)){
//directory= posDir+”/”+newDir;

if(msgType.equals(“goodsreceipt”)){
directory=”/”+posDir+”/goodsreceipt”;

}else if(msgType.equals(“poreturn”)){
directory=”/”+posDir+”/poreturn”;

}else if(msgType.equals(“storetransfer”)){
directory=”/”+posDir+”/storetransfer”;

}else if(msgType.equals(“sloctosloctransfer”)){
directory=”/”+posDir+”/sloctosloctransfer”;

}else if(msgType.equals(“dailyadjustments”)){
directory=”/”+posDir+”/dailyadjustments”;

}else if(msgType.equals(“stocktake”)){
directory=”/”+posDir+”/stocktake”;

}else if(msgType.equals(“Nonconsumableorder”)){
directory=”/”+posDir+”/nonconsumableorder”;
}else if(msgType.equals(“consumableorder”)){
directory=”/”+posDir+”/consumableorder”;
}else if(msgType.equals(“SOQ”)){
directory=”/”+posDir+”/SOQ”;
}else if(msgType.equals(“inventorycount”)){
directory=”/”+posDir+”/inventorycount”;
}
}else if(returnValue.equals(“4″)){
directory=”/”+posDir+”/”+dupDir;
}

}

}
conf.put(KEY_DIRECTORY,directory );

//arg1.getOutputPayload().getOutputStream().write(result.getBytes());

//arg1.getOutputPayload().getOutputStream().write(result.getBytes());
byte[] b = new byte[arg0.getInputPayload().getInputStream().available()];
arg0.getInputPayload().getInputStream().read(b);

arg1.getOutputPayload().getOutputStream().write(b);

}catch(Exception e){

}

}

private synchronized String performRFCLookup(String bDate,String fileName,String bTime,String seuquenceNo,String storeNo,String workstationId,String SERVICE1,String CHANNEL_NAME1,String messageType)
{
//String result=”4”;

String result1=new String();

String SERVICE = SERVICE1; // Name of service defined in XI configuration
String CHANNEL_NAME = CHANNEL_NAME1; // Name of communication channel defined for service
String SAP_RFC_NAMESPACE = “urn:sap-com:document:sap:rfc:functions”, // Namespace for SAP RFC definitions
FUNCTION_MODULE = “Z_FM_DUPLICATE_CHECK”, // Name of the function module called
VALUE_NOT_FOUND = “”; // Default return value in case something goes wrong

// Create document builder to create DOM XML document
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = null;
factory.setNamespaceAware(false);
factory.setValidating(false);

try {
// Create XML document using document builder
builder = factory.newDocumentBuilder();
} catch (Exception e) {
trace.addWarning(“Error creating DocumentBuilder – ” +
e.getMessage());
// return null;
}

trace.addWarning(“*message type is*”+messageType);
String rfcXML = “<?xml version=\”1.0\” encoding=\”UTF-8\”?>” +
“<ns0:Z_FM_DUPLICATE_CHECK xmlns:ns0=\”urn:sap-com:document:sap:rfc:functions\”>” +
“<IV_BDATE>”+bDate+”<IV_BDATE/>” +
“<IV_BTIME>”+bTime+”<IV_BTIME/>” +
“<IV_WERKS>”+storeNo+”<IV_WERKS/>”+
“<IV_WSTID>”+workstationId+”<IV_WSTID/>”+
“<IV_SEQNO>” +seuquenceNo+”<IV_SEQNO/>” +
“<IV_MESTYP>”+messageType+”<IV_MESTYP/>” +
“<IV_FILEN>”+fileName+”<IV_FILEN/>” +
“</ns0:Z_FM_DUPLICATE_CHECK>”;

// Prepare and perform RFC Lookup …
com.sap.aii.mapping.lookup.RfcAccessor accessor;
com.sap.aii.mapping.lookup.Payload result=null;

try {
// Determine a communication channel (Business system + Communication channel)
com.sap.aii.mapping.lookup.Channel channel = LookupService.getChannel(SERVICE, CHANNEL_NAME);

// Get a RFC accessor for the channel.
accessor = LookupService.getRfcAccessor(channel);

// Create an XML input stream that represents the RFC request message.
java.io.InputStream is = new java.io.ByteArrayInputStream(rfcXML.getBytes());

// Create the XML Payload
com.sap.aii.mapping.lookup.XmlPayload payload = LookupService.getXmlPayload(is);

// Execute the lookup.
result = accessor.call(payload);

accessor.close();

if (result == null) {
trace.addWarning(“result of RFC call is null”);
}

} catch (com.sap.aii.mapping.lookup.LookupException e) {
trace.addWarning(“Error during lookup – ” + e);
}

// Parsing RFC Response Document
Document docResponse = null;
java.io.InputStream in = result.getContent();
String returnValue = VALUE_NOT_FOUND;
NodeList poItems = null;

try {

docResponse = builder.parse(in);
if (docResponse == null) {
trace.addWarning(“docResponse is null”);
}

NodeList transactionList= docResponse.getElementsByTagName(“rfc:Z_FM_DUPLICATE_CHECK.Response”);

trace.addWarning(“success1″);
String endResult=””;
for(int k=0;k<transactionList.getLength();k++){
String EV_SUBRC= ((Element)transactionList.item(k)).getElementsByTagName(“EV_SUBRC”).item(0).getFirstChild().getTextContent();
trace.addWarning(“success2″+EV_SUBRC);
result1=EV_SUBRC;
}
}
catch (Exception e) {
trace.addWarning(“Error when parsing RFC Response – ” + e.getMessage());
}

trace.addWarning(“result1 is – ” + result1);
return result1;
}
private String convertTimeTewelveHoursBack(String dateToConvert){

String output=””;
try
{

dateToConvert=dateToConvert.replaceAll(“T”, “”);
dateToConvert=dateToConvert.replaceAll(“Z”, “”);

DateFormat gmtFormat = new SimpleDateFormat(“yyyyMMddHHmmss”);
Date date = gmtFormat.parse(dateToConvert);
//TimeZone gmtTime = TimeZone.getTimeZone(“UTC”);
//gmtFormat.setTimeZone(gmtTime);

Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.add(Calendar.HOUR,+8);
Date tewelveHourBack = cal.getTime();

DateFormat gmtFormat1 = new SimpleDateFormat(“yyyyMMdd_HHmmss”);

output=gmtFormat1.format(tewelveHourBack);

}catch(Exception e){
e.printStackTrace();
}

return output;
}
private String traversingXML(Node node) {
NodeList children=node.getChildNodes();
NamedNodeMap attributes;
Node attrnode;
for(int j=0;j<children.getLength();j++){
Node child=children.item(j);
short childType=child.getNodeType();
String attrName=”NA”;
if(childType==Node.ELEMENT_NODE){
String nodeName=child.getNodeName();

StringBuffer tempNodeName=new StringBuffer();
tempNodeName.append(“<“+nodeName);
NamedNodeMap attr=child.getAttributes();
for(int k=0;k<attr.getLength();k++){
Node attrvalue=attr.item(k);
attrvalue.getNodeName();
attrvalue.getNodeValue();
tempNodeName.append(” “+attrvalue.getNodeName()+”=”+”\””+attrvalue.getNodeValue()+”\””);
}
tempNodeName.append(“>”);

endResult.append(tempNodeName);

traversingXML(child);
endResult.append(“</”+nodeName+”>”);

if(nodeName.equals(“RetailTransaction”)||nodeName.equals(“WN:BSCMTransaction”)||nodeName.equals(“ControlTransaction”)){
isSales=”YES”;
msgType=”SALES”;
}else if(nodeName.equals(“SOQ”)){
isSales=”NO”;
msgType=”SOQ”;
}else if(nodeName.equals(“EODConfirmation”)){
isSales=”NO”;
msgType=”inventorycount”;
}

}else if(childType==Node.TEXT_NODE){
String nodeValue=child.getNodeValue();
nodeValue=nodeValue.replaceAll(“&”, “&amp;”);
nodeValue=nodeValue.replaceAll(“<“, “&lt;”);
endResult.append(nodeValue);

if(nodeValue.equals(“goodsreceipt”)){
isSales=”NO”;
msgType=”goodsreceipt”;
}else if(nodeValue.equals(“PGR”)||nodeValue.equals(“WPO”)){
isSales=”YES”;
msgFct=nodeValue;
}
else if(nodeValue.equals(“poreturn”)){
isSales=”NO”;
msgType=”poreturn”;
}else if(nodeValue.equals(“storetransfer”)){
isSales=”NO”;
msgType=”storetransfer”;
}else if(nodeValue.equals(“sloctosloctransfer”)){
isSales=”NO”;
msgType=”sloctosloctransfer”;
}else if(nodeValue.equals(“dailyadjustments”)){
isSales=”NO”;
msgType=”dailyadjustments”;
}else if(nodeValue.equals(“stocktake”)){
isSales=”NO”;
msgType=”stocktake”;
}else if(nodeValue.equals(“Nonconsumableorder”)){
isSales=”NO”;
msgType=”Nonconsumableorder”;
}else if(nodeValue.equals(“consumableorder”)){
isSales=”NO”;
msgType=”consumableorder”;
}
}

}
return endResult.toString();
}

}

To report this post you need to login first.

2 Comments

You must be Logged on to comment or reply to a post.

  1. Shabarish Vijayakumar

    I have always been a fan of the “KISS” principle. Hence even though your blog demonstrates a work around, the implementation would have been much more simple and maintainable if it was done using the BPMN capabilities.

    Keep blogging!

    (1) 
    1. varun boyina Post author

      Hi Shabarish ,

       

      Thanks for your comments. I worked with you in Celestica project.You were in Canada and I was with IBM Hyderabad. It was during the migration of interfaces from Extricity middleware tool to SAP PI. As it was an old tool it was zipping using .tar format .Hope you remember me 😉

      (0) 

Leave a Reply