The second blog on sftp adapter module, which I wanted to publish soon after the first one but couldn't do it but here I am now. In first blog I wrote about Receiver module which was quite easy as we just have to invoke our receiver channel to deliver the message which will in turn invoke the SFTP receiver module and write file on SFTP server. But in case of Sender scenario where we need to read files from SFTP server, our sender SFTP module won't work by itself because it cannot poll files and thus for that we will have to use "Trigger file". The trigger file is nothing but an empty file available on local drive, The sender File adapter will poll this trigger file on test mode at defined polling interval which will invoke SFTP module to read files from remote sftp server at same polling interval.
Now that we have read file from sftp server using module the standard file adapter would still try to send triger file content into message queue, whereas we want the content of file read from sftp server. For this we will have to replace the message content polled by standard file adapter with the content read from SFTP server and put that into messaging queue. The code below shows how that is handled, The remaining module parameters and other necessary functionality like file archiving are also needs to be included in module parameter and in the module code.
/** * */ package com.sap.adaptermodule; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringWriter; import java.io.Writer; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Vector; import javax.ejb.CreateException; import javax.ejb.SessionBean; import javax.ejb.SessionContext; import com.jcraft.jsch.Channel; import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.JSch; import com.jcraft.jsch.Session; import com.jcraft.jsch.SftpATTRS; 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.service.auditlog.Audit; 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.XMLPayload; import com.sap.engine.interfaces.messaging.api.auditlog.AuditLogStatus; /** * @author ambharti * */ public class SenderSFTPBean implements SessionBean, Module { // private Log logger = LogFactory.getLog(getClass()); private SessionContext myContext; public void ejbRemove() { } public void ejbActivate() { } public void ejbPassivate() { } public void setSessionContext(SessionContext context) { myContext = context; } public void ejbCreate() throws CreateException { } // Start custom function of SFTP @SuppressWarnings("unchecked") public ModuleData process(ModuleContext mc, ModuleData inputModuleData) throws ModuleException { Object obj = null; Message msg = null; MessageKey amk = null; InputStream bis = null; String lv_del_flag = null; try { // Retrieves the current principle data, usually the message , // Return type is Object obj = inputModuleData.getPrincipalData(); // A Message is what an application sends or receives when // interacting with the Messaging System. msg = (Message) obj; // MessageKey consists of a message Id string and the // MessageDirection amk = new MessageKey(msg.getMessageId(), msg.getMessageDirection()); // Reading file name from message header MessagePropertyKey mpk = new MessagePropertyKey("FileName", "http://sap.com/xi/XI/System/File"); String filename = msg.getMessageProperty(mpk); Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "Filename is " + filename); Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "Input file read successfully"); // Archiving target file on FTP server { String HostName = (String) mc.getContextData("HostName"); String Port = (String) mc.getContextData("Port"); String Directory = (String) mc.getContextData("Directory"); String Filename = (String) mc.getContextData("Filename"); String Username = (String) mc.getContextData("Username"); String Password = (String) mc.getContextData("pwd"); String PrivateKey = (String) mc.getContextData("PrivateKey"); String HostKey = (String) mc.getContextData("HostKey"); //Added for Archive String Archive = (String) mc.getContextData("ArchivePath"); //Added for Archive Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "Connecting to SFTP location " + HostName); int Portno = Integer.parseInt(Port); JSch jsch = new JSch(); Session session = null; // Use key authentication if it is set, else use password // authentication if (PrivateKey != null && PrivateKey != "") { Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "Authenticating key to SFTP"); if (Password != null && Password != "") { byte[] passphrase = Password.getBytes(); jsch.addIdentity(PrivateKey, passphrase); } else { jsch.addIdentity(PrivateKey); } session = jsch.getSession(Username, HostName, Portno); } else if (Password != null && Password != "") { Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "Authenticating password to SFTP"); session = jsch.getSession(Username, HostName, Portno); session.setPassword(Password); } if (HostKey != null) { Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "Authenticating Hostkey of SFTP server"); jsch.setKnownHosts(HostKey); session = jsch.getSession(Username, HostName, Portno); } else { session.setConfig("StrictHostKeyChecking", "no"); } session.setTimeout(15000); // Connecting to SFTP Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "Authenticating to SFTP"); session.connect(); Channel channel = session.openChannel("sftp"); channel.connect(); ChannelSftp sftpChannel = (ChannelSftp) channel; sftpChannel.cd(Directory); Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "Connection to SFTP location Successful"); // Check if file exists Boolean fileExists = false; try { Vector<ChannelSftp.LsEntry> list = sftpChannel.ls(Filename); Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "File listing is Successful"); for (ChannelSftp.LsEntry entry : list) { Filename = entry.getFilename(); Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "File found is : " + Filename ); fileExists = true; continue; } } catch (Exception ex) { Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "File listing is Unsuccessful"); } Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "File avaialbale :" + fileExists ); if (fileExists == true) { Vector<ChannelSftp.LsEntry> list = sftpChannel.ls(Filename); Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "File listing is Successful"); // Read file try { for (ChannelSftp.LsEntry entry : list) { bis = new BufferedInputStream(sftpChannel.get(entry .getFilename())); Filename = entry.getFilename(); continue; } // bis = new // BufferedInputStream(sftpChannel.get(Filename)); Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "File read sucessfully : " + Directory + "/" + Filename); // If file is available set message property filename MessagePropertyKey msz = new MessagePropertyKey( "FileName", "http://sap.com/xi/XI/System/File"); msg.setMessageProperty(msz, Filename); } catch (Exception e) { Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "Module Exception caught:"); // Set flag to not perform delete operation lv_del_flag = "X"; Audit.addAuditLogEntry(amk, AuditLogStatus.WARNING, "No such file exist"); } } try { XMLPayload xmlpayload = msg.getDocument(); String sXML = convert(bis); byte[] docContent = sXML.getBytes(); if (docContent != null) { Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "Inside DocContent"); xmlpayload.setContent(docContent); inputModuleData.setPrincipalData(msg); } else { Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "Data not parsed"); } } catch (Exception e) { ModuleException me = new ModuleException(e); throw me; } if (fileExists == true) { try { if (Archive != null && Archive != "") { // Archive file String pathname = sftpChannel.realpath(Directory) ; pathname = pathname + "/" + Filename; String archname = sftpChannel.realpath(Archive) ; /* Write time stamp to file*/ Date date = new Date(); // get the current date SimpleDateFormat dateFormatter = new SimpleDateFormat( "yyyyMMddHHmmssSSS"); // set the format for date String dfmt = dateFormatter.format(date); dfmt = dfmt + "_"; archname = archname + "/" + dfmt + Filename; //Filename = archname; sftpChannel.rename(pathname, archname); Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "File Archived in " + archname); } else{ // delete file from server sftpChannel.rm(Filename); Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "File " + Filename + " Deleted from " + Directory); } } catch (Exception e) { Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "Module Exception caught while deleting or archiving the file:" + Filename); ModuleException me = new ModuleException(e); throw me; } } sftpChannel.exit(); session.disconnect(); } } catch (Exception e) { Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "Module Exception caught:"); ModuleException me = new ModuleException(e); throw me; } return inputModuleData; } public String convert(InputStream is) { char[] buff = new char[1024]; Writer stringWriter = new StringWriter(); try { Reader bReader = new BufferedReader(new InputStreamReader(is, "UTF-8")); int n; while ((n = bReader.read(buff)) != -1) { stringWriter.write(buff, 0, n); } } catch (Exception e) { e.printStackTrace(); } return stringWriter.toString(); } }
The module parameter entries would like like -
And the communication channel logs -
References :