Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
former_member183910
Participant

Hi friends,

I got a business requirement where SAP ECC is sending data using outbound ABAP Proxy to PI and PI is receiving the same and creating the file at FTP/SFTP server (Proxy to file scenario).  File name is supplied in the payload which is coming from Sender SAP system. To set filename in Dynamic Configuration (ASMA), I used XSLT mapping (and there were few transformations also). Variable Substitution didn’t work for me as the file name was not available until Receiver File/SFTP adapter (during transformation it was ignored, it was our business requirement)

I got to develop many interfaces which using the above mentioned flow, and I was writing the same XSLT code (to set the file name in dynamic configuration) in all the mapping so I decided to write the adapter module which perform the same task that XSLT code was doing. Once Adapter module is deployed, it can be used in any Communication Channel and any team member can reuse it just by supplying necessary configuration parameters.

This adapter module is developed using Enterprise Java Beans (EJB) 3.0. It expects the File Name XPath to be provided in adapter configuration. This XPath is used to get the file using regular expression (regex). The same implementation could be done using DOM parser too but DOM parser was performing slower for large files, so I am using regex which is better option as it is native to java.

This adapter module can be used in Sender or Receiver communication channel before “CallSapAdapter” module. I am using it in SOAP (XI3.0) ABAP Proxy Communication Channel.

Below is the java code for adapter module: As I am using EJB3.0, it is not necessary to implement Session bean. Only Module interface is required to implement.

Method getRegexFromXPath() returns the regular expression which is used in Bean class to match the pattern and find out the file name.

package com.sap.pi.adapter.module;

import java.io.InputStream;

import java.io.PrintWriter;

import java.io.StringWriter;

import javax.annotation.PostConstruct;

import javax.annotation.PreDestroy;

import javax.ejb.Local;

import javax.ejb.LocalHome;

import javax.ejb.Remote;

import javax.ejb.RemoteHome;

import javax.ejb.Stateless;

import com.sap.aii.af.lib.mp.module.Module;

import com.sap.aii.af.lib.mp.module.ModuleContext;

import com.sap.aii.af.lib.mp.module.ModuleData;

import com.sap.aii.af.lib.mp.module.ModuleException;

import com.sap.aii.af.lib.mp.module.ModuleHome;

import com.sap.aii.af.lib.mp.module.ModuleLocal;

import com.sap.aii.af.lib.mp.module.ModuleLocalHome;

import com.sap.aii.af.lib.mp.module.ModuleRemote;

import com.sap.engine.interfaces.messaging.api.Message;

import com.sap.engine.interfaces.messaging.api.MessageKey;

import com.sap.engine.interfaces.messaging.api.MessagePropertyKey;

import com.sap.engine.interfaces.messaging.api.PublicAPIAccessFactory;

import com.sap.engine.interfaces.messaging.api.XMLPayload;

import com.sap.engine.interfaces.messaging.api.auditlog.AuditAccess;

import com.sap.engine.interfaces.messaging.api.auditlog.AuditLogStatus;

import com.sap.engine.interfaces.messaging.api.exception.MessagingException;

/**

* Session Bean implementation class FileSetProperties

*/

@Stateless(name = "FileSetPropertiesBean")

@Local(value = { ModuleLocal.class })

@Remote(value = { ModuleRemote.class })

@LocalHome(value = ModuleLocalHome.class)

@RemoteHome(value = ModuleHome.class)

public class FileSetProperties implements Module {

      private AuditAccess audit;

      public FileSetProperties() {

      }

      @Override

      public ModuleData process(ModuleContext moduleContext, ModuleData inputModuleData) throws ModuleException {

            FunctionsLibrary functionLibrary = new FunctionsLibrary();

            Object obj = null;

            Message msg = null;

            MessageKey msgKey = null;

            String fileName = "";

            String fileXPath = "FileXPath";

            try {

                  obj = inputModuleData.getPrincipalData();

                  msg = (Message) obj;

                  msgKey = new MessageKey(msg.getMessageId(), msg.getMessageDirection());

                  addLog(msgKey, AuditLogStatus.SUCCESS, "***** Entering in FileSetProperties adapter module ******");

                  MessagePropertyKey fileKey = new MessagePropertyKey("FileName", "http://sap.com/xi/XI/System/File");

                  XMLPayload xmlPayload = msg.getDocument();

                  InputStream inputStream = xmlPayload.getInputStream();

                  String inString = functionLibrary.inputStreamToString(inputStream);

                  String regex = functionLibrary.getRegexFromXPath(moduleContext.getContextData(fileXPath));

                  addLog(msgKey, AuditLogStatus.SUCCESS, "Regular Expression: " + regex + " Input message parsing is done.");

//                addLog(msgKey, AuditLogStatus.SUCCESS, "Input message parsing is done. ");

                  if (inString.matches(regex)) {

                        fileName = inString.replaceAll(regex, "$" + functionLibrary.getRegexReplacementCount());

                        addLog(msgKey, AuditLogStatus.SUCCESS, "Supplied XPath in Communication Challel is: " + moduleContext.getContextData(fileXPath) + ". " + "File name from payload is: " + fileName + " Going to set this file name in ASMA");                  

                     

                        inputModuleData.setPrincipalData(msg);

                     

                  } else {

                        addLog(msgKey, AuditLogStatus.WARNING, "Input message does not matches with regex . " + regex);

                     

                        fileName = functionLibrary.getDefaultFileName();

                        addLog(msgKey, AuditLogStatus.SUCCESS, "Using default file Name " + fileName);

                  }

                  if (!"".equals(fileName)) {

                        msg.setMessageProperty(fileKey, fileName);

                        addLog(msgKey, AuditLogStatus.SUCCESS, "File name has been set in ASMA. You can access it from Dynamic Configuration." );

                        addLog(msgKey, AuditLogStatus.SUCCESS, "***** Exiting from FileSetProperties adapter module ******");

                  }

               

            } catch (Exception e) {

                  // e.printStackTrace();

                  addLog(msgKey, AuditLogStatus.ERROR, e.getMessage().toString());

                  addLog(msgKey, AuditLogStatus.ERROR, "***** Error occured. Exiting from FileSetProperties adapter module ****** ");

                  try {

                        handleException(msgKey, e);

                  } catch (Exception e1) {

                  }

            }

         

            //addLog(msgKey, AuditLogStatus.SUCCESS, "***** Exiting from FileSetProperties adapter module ******");

            return inputModuleData;

      }

      @PostConstruct

      public void initialiseResource() {

            try {

                  audit = PublicAPIAccessFactory.getPublicAPIAccess().getAuditAccess();

            } catch (MessagingException e) {

                  System.out.println("WARNING: Audit log not available in standalone testing");

            }

      }

      @PreDestroy

      public void ReleaseResource() {

      }

      private void addLog(MessageKey msgKey, AuditLogStatus status, String message) {

            if (audit != null) {

                  audit.addAuditLogEntry(msgKey, status, message);

            } else {

                  System.out.println("Audit Log: " + message);

            }

      }

      private void handleException(MessageKey msgKey, Exception e) throws Exception {

            // throw new Exception(comment + " " + getStackTraceAsString(e), e);

            addLog(msgKey, AuditLogStatus.ERROR, getStackTraceAsString(e));

      }

      public String getStackTraceAsString(Exception e) {

            StringWriter sw = new StringWriter();

            e.printStackTrace(new PrintWriter(sw));

            String stacktrace = sw.toString();

            return stacktrace;

      }

}

FileSetProperties class uses getRegexFromXPath()  which is written in FunctionsLibrary class.

package com.sap.pi.adapter.module;

import java.io.IOException;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.io.UnsupportedEncodingException;

import java.text.Format;

import java.text.SimpleDateFormat;

import java.util.Date;

public class FunctionsLibrary {

      int replacementCount = 3;

      public String getRegexFromXPath(String XPath) {

            StringBuffer sb = new StringBuffer();

            try {

                  if (XPath != null) {

                        XPath = XPath.replace("//", "");

                        if (XPath.length() > 0) {

                              sb.append("(?s)");

                              String arg[] = XPath.split("/");

                              for (int i = 0; i < arg.length; i++) {

                                    if (arg[i].length() > 0) {

                                          sb.append("(.*?)(");

                                          sb.append(arg[i]).append(")");

                                          replacementCount = replacementCount + 2;

                                          if (i == arg.length - 1) {

                                                sb.append("(.*?)(>)(.*?)(<)(.*?)(").append(arg[i]).append(">)(.*)");

                                          }

                                    }

                              }

                        } else {

                        }

                  }                

            } catch (Exception e) {

            }

            return sb.toString();

      }

      public int getRegexReplacementCount() {

            return this.replacementCount;

      }

      public String inputStreamToString(InputStream in) {

            // read in stream into string.

            StringBuffer buf = new StringBuffer();

            try {

                  InputStreamReader isr = null;

                  // try UTF-8 conversion

                  try {

                        isr = new InputStreamReader(in, "UTF-8");

                  } catch (UnsupportedEncodingException e) {

                        // or atleast in natural encoding

                        isr = new InputStreamReader(in);

                  }

                  int c = 0;

                  while ((c = isr.read()) != -1) {

                        buf.append((char) c);

                  }

                  in.close();

                  isr.close();

            } catch (IOException e) {

                  e.printStackTrace();

            }

            return buf.toString();

      }

      public String getDefaultFileName() {

            Format formatter = new SimpleDateFormat("yyyyMMdd-hhmmss");

            Date d = new Date();

            String fileName = "Unknown_" + formatter.format(d) + ".xml";

            return fileName;

      }

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

            // TODO Auto-generated method stub

            String XPath = "//text/text1/FileName";

            FunctionsLibrary functionLibrary = new FunctionsLibrary();

            System.out.println(functionLibrary.getRegexFromXPath(XPath));

            // System.out.println(functionLibrary.getDefaultFileName());

            System.out.println(functionLibrary.getRegexReplacementCount());

      }

}

Use FileSetPropertiesBean in ejb-j2ee-engine.xml  and assign JNDI name. JNDI name is used in Communication Channel in Module tab.

<?xml version="1.0" encoding="UTF-8"?>

<ejb-j2ee-engine xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ejb-j2ee-engine_3_0.xsd">

      <enterprise-beans>

            <enterprise-bean>

                  <ejb-name>FileSetPropertiesBean</ejb-name>

                  <jndi-name>FileSetProperties</jndi-name>

            </enterprise-bean>

      </enterprise-beans>

</ejb-j2ee-engine>

Edit application-j2ee-engine.xml in EAR project and use the below xml

<?xml version="1.0" encoding="UTF-8"?>

<application-j2ee-engine xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="application-j2ee-engine.xsd">

      <reference reference-type="hard">

            <reference-target target-type="service" provider-name="sap.com">engine.security.facade</reference-target>

      </reference>

      <reference reference-type="hard">

            <reference-target target-type="library" provider-name="sap.com">engine.j2ee14.facade</reference-target>

      </reference>

            <reference reference-type="hard">

            <reference-target target-type="service" provider-name="sap.com">com.sap.aii.af.svc.facade</reference-target>

      </reference>

            <reference reference-type="hard">

            <reference-target target-type="interface" provider-name="sap.com">com.sap.aii.af.ifc.facade</reference-target>

      </reference>

            <reference reference-type="hard">

            <reference-target target-type="library" provider-name="sap.com">com.sap.aii.af.lib.facade</reference-target>

      </reference>

            <reference reference-type="hard">

            <reference-target target-type="library" provider-name="sap.com">com.sap.base.technology.facade</reference-target>

      </reference>

            <fail-over-enable xsi:type="fail-over-enableType_disable"

                  mode="disable" />

</application-j2ee-engine>

8 Comments
Labels in this area