Skip to Content

Overview

In a business scenario, a group of users send attachments to one mail-id. They can send multiple attachments per mail. So, here, we need to find out a way to extract all attachments with their original names from a mail and store it in some folder.

Using Sender-Mail adapter, we read mails with attachments.

For storing attachments to specific sap application directory, we use Receiver-File Adapter along with a custom java adapter module.

Note: Receiver-File-Adapter can store only 1st attachment, so, we create a custom adapter module for this channel which will store multiple attachments to folder.

Sender/Receiver Communication channels can be referred from below link:

 

Pre-requisites:

Pre-requisites to create a custom java adapter module form SAP PI 7.11 is as below:

  • SAP NetWeaver Developer Studio 7.1
  • Java Runtime Environment 1.6 (Jre 1.6)
  • SAP library (or jar) files for required for module development
    • sap.aii.af.lib.mod.jar                  : <bin>/ext/com.sap.aii.af.lib/lib
    • com~tc~logging~java~impl.jar  : <bin>/system
    • sap.aii.af.svc_api.jar                 : <bin>/services/com.sap.aii.af.svc/lib
    • sap.aii.af.cpa.svc_api.jar          : <bin>/services/com.sap.aii.af.cpa.svc/lib
    • sap.aii.af.ms.ifc_api.ja r            : <bin>/interfaces/com.sap.aii.af.ms.ifc/lib
  • Include above jar files in the library classpath of SAP Netweaver Developer Studio 7.1 via below steps:
    • Navigate to Windows → Preference → expand “Java” → select “Classpath Variables” → Click “New” to create a new variable entry: PI_AF_LIBS →
  • NwceTool
    • This will help to convert EAR files to SDA files
    • It uses JRE 1.6

 

Java Adapter Module Code:

  • Below java adapter module code is been written to achieve below functionality:
    • Get SAP- Directory path location with external module input variable ‘SapDirPath’
  • and Code is as below:
    /**
     * 
     */
    package com.sap.adaptermodule;
    
    import java.rmi.RemoteException;
    import javax.ejb.EJBException;
    import javax.ejb.SessionBean;
    import javax.ejb.SessionContext;
    import javax.ejb.TimedObject;
    import javax.ejb.Timer;
    
    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.Payload;
    import com.sap.engine.interfaces.messaging.api.auditlog.AuditLogStatus;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.util.Iterator;
    
    /**
     * @author User
     *
     */
    public class MAttachToDirBean implements SessionBean, TimedObject {
    
    	/* (non-Javadoc)
    	 * @see javax.ejb.SessionBean#ejbActivate()
    	 */
    	public void ejbActivate() throws EJBException, RemoteException {
    		// TODO Auto-generated method stub
    
    	}
    
    	/* (non-Javadoc)
    	 * @see javax.ejb.SessionBean#ejbPassivate()
    	 */
    	public void ejbPassivate() throws EJBException, RemoteException {
    		// TODO Auto-generated method stub
    
    	}
    
    	/* (non-Javadoc)
    	 * @see javax.ejb.SessionBean#ejbRemove()
    	 */
    	public void ejbRemove() throws EJBException, RemoteException {
    		// TODO Auto-generated method stub
    
    	}
    
    	/* (non-Javadoc)
    	 * @see javax.ejb.SessionBean#setSessionContext(javax.ejb.SessionContext)
    	 */
    	public void setSessionContext(SessionContext arg0) throws EJBException,
    			RemoteException {
    		// TODO Auto-generated method stub
    
    	}
    
    	/* (non-Javadoc)
    	 * @see javax.ejb.TimedObject#ejbTimeout(javax.ejb.Timer)
    	 */
    	public void ejbTimeout(Timer arg0) {
    		// TODO Auto-generated method stub
    
    	}
    
    	public void ejbCreate() throws javax.ejb.CreateException {
    		
    	}
    	
    	private SessionContext myContext;
    	MessageKey amk = null;		
    	public ModuleData process(ModuleContext moduleContext, ModuleData inputModuleData) throws ModuleException
    	{
    		Object obj = null;
    	    Message msg = null;
    	    String SapDirPath = null;		
    	    	    
    	    try
    		{
    			obj = inputModuleData.getPrincipalData();
    		    msg = (Message) obj;
    		    amk = new MessageKey(msg.getMessageId(),msg.getMessageDirection());	
    		    
    		    Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "JAM-MAttachToDir| Custom-Java-Adapter-Module (localejbs/MAttachToDir) to store mutliple attachments to directory");
    		    		    
    		    //Get user-input as a "module.key" parameters from communication channels		    
    		    //Input-1:	'SapDirPath' to get folder path where attachments will be stored		    
    		    SapDirPath = (String) moduleContext.getContextData("SapDirPath");  
    		    Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "JAM-MAttachToDir| Directory Path input (SapDirPath)= " + SapDirPath);
    		    		    		    
    		    //Get the input attachment from the source message)
    		    Iterator itr = msg.getAttachmentIterator();
    		    while(itr.hasNext()){
    		    	//handle attachment
    		    	Payload payload = (Payload) itr.next();		
    		    			    	
    		    	//get attachment name
    		    	String atchnm = payload.getContentType();	//this gives output like "application/octet-stream;name=""fnam1.csv"
    		    	atchnm = atchnm.replaceAll("\"", "");		//replace all quoteString (i.e. ") with blank
    		    	int i1 = atchnm.lastIndexOf("=") + 1;
    		    	String atchmntNm = atchnm.substring(i1,atchnm.length());
    		    	Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "JAM-MAttachToDir| Attachment found as " + atchmntNm);
    		    	
    		    	//Write file to directory
    		    	byte [] inpbyt = payload.getContent();
    		    	File path = new File(SapDirPath + "/" + atchmntNm);
    		    	FileOutputStream fos = new FileOutputStream(path);
    		    	fos.write(inpbyt);
    		        fos.flush();
    		        fos.close();
    		        
    		        Audit.addAuditLogEntry(amk, AuditLogStatus.SUCCESS, "JAM-MAttachToDir| " + atchmntNm + " copied to folder " + SapDirPath);
    		    }
    		}catch (Exception e) {
    		      ModuleException me = new ModuleException(e);
    		      throw me;
    	    }		
    		return inputModuleData;	       
    	}	
    }
    

 

Steps to Create Java Adapter Module:

  1. Create an EJB project in “SAP NetWeaver Developer Studio 7.1
  2. Assign project names to the EJB and EAR projects
    • EJB Project Name: MAttachToDir_EJB.
    • EAR Project Name: MAttachToDir_EAR (check the option to add EAR project).
    • Click “Next”.
  3. Choose the correct EJB version.
    • Configure Module Project as → SAP EJB J2EE 1.4 Project.
    • Choose the EJB Module → 2.1.
    • Click “Next”.
    • Uncheck the flag to create the EJB client jar interfaces.
    • Click “Finish”
    • Please note, 2 projects will be created, an EJB project (MAttachToDir_EJB) and an EAR project (MAttachToDir_EAR).
  4. Create an Enterprise Bean in the EJB project
    • Right-click on the “MAttachToDir_EJB”.
    • Select: New → EnterpriseBean.
  5. Create the package and class for the EJB project
    • EJB Name                           : MAttachToDir
    • Bean Type                          : Select the dropdown “Stateless Session Bean”.
    • Give a default EJBPackage: com.sap.adaptermodule.
    • Uncheck option                   : generate default interfaces.
    • Check option                      : add optional interfaces.
    • Click “Next”.
  6. Assign user-module interfaces: Use the following values to assign to the parameters in the screen below:
    • Remote interface              : com.sap.aii.af.lib.mp.module.ModuleRemote
    • Home interface                 : com.sap.aii.af.lib.mp.module.ModuleHome
    • Local interface                  : com.sap.aii.af.lib.mp.module.ModuleLocal
    • LocalHome interface         : com.sap.aii.af.lib.mp.module.ModuleLocalHome
    • Uncheck option                 : Service End point
    • Click ‘Finish’
  7. Examine and verify the content of ejb-jar.xml
    • On the left panel, navigate: EJB project → ejbModule → META-INF.
    • Double click on the “ejb-jar.xml”.
    • When the “ejb-jar.xml” is displayed on the right panel, select the “Enterprise Beans” tab at the bottom.
    • Expand “Session Beans” and select “MAttachToDir”.
    • All the local and remote interfaces should be displayed.
    • The “Service endpoint” should be empty. If not, then go to “Source” and edit the tag “<service-endpoint>”with blank value
  8. Enter the JNDI name in the ejb-j2ee-engine.xml
    • On the left panel, double click on the “ejb-j2ee-engine.xml”.
    • “Ejb-j2ee-engine.xml” will be displayed on the right panel.
    • Expand “Session beans” and click on “MAttachToDir”.
    • Enter the JNDI Name: MAttachToDir.
    • Save the file.
  9. Include external libraries in the EJB project so the java class can be compiled
    • Right click on the EJB project.
    • Navigate to “Build Path”.
    • Select “Configure Build Path”.
    • In the Properties dialogue box, click the “Add Variable”.
    • Select the variable, “PI_AF_LIBS”, created earlier
    • Click on “Extend”.
  10. Enter the code for “MAttachToDirBean”
    • Copy and paste code from above to below project file
  11. Delete the package containing the Local and Remote interfaces from the build
    • Expand the “build” folder in the EJB project.
    • Delete all the folders created under build → classes → com → sap -> aii
    • Do not deletebuild → classes → com → sap -> adaptermodule”
  12. Configure the EAR project: The EAR file contains the following:
    • JAR file created from the EJB project.
    • It has configuration information of the libraries, services and interfaces that will be used by the user-module in the EJB.
    • It contains the SAP manifest file, which has unique identifiers for each specific EAR. The manifest information is generated uniquely each time it is modified.
    • Steps to Configure EAR:
      • Expand the EAR project.
      • Double-click on the “application-j2ee-engine.xml” file.
      • In the right panel, click on the “Reference” and then on the “+” sign to “Add Elements”.
      • Click “Create New” in the dialog.
      • Add below elements as given in table
      • Reference target Reference type Reference target type Provider name
        engine.security.facade hard service sap.com
        engine.j2ee14.facade hard library sap.com
        com.sap.aii.af.svc.facade hard service sap.com
        com.sap.aii.af.ifc.facade hard interface sap.com
        com.sap.aii.af.lib.facade hard library sap.com
        com.sap.base.technology.facade hard library sap.com
      • Check the option “Failover Mode”.
      • Save the file.
  13. Exporting SAP EAR File
    • Right Click on EAR project -> Export -> SAP EAR File
  14. Custom java adapter module has been created as EAR file “MAttachToDir_EAR.ear

 

Steps to Covert EAR files to SDA Files using NWCE-Tool:

  • From above steps, java adapter module EAR file “MAttachToDir_SDA.ear” gets created.
  • To use this module in SAP-PI, we need to convert it in to SDA file format with “.sda” extension.
  • Pr-requisites for EAR to SDA file conversion:
    • Java Jre1.6      Check Java Jre1.6 Directory (here C:\Program Files\Java\jre1.6.0_01)
    • nwcetool          Copy nwcetool folder in to C:\NWDS
    • Any local Windows system
  • Command line steps for EAR to SDA file conversion:
    • cmd>cd \
    • cd C:\NWDS\NWCE_TOOLS\tools\nwcetool
    • SET JAVA_HOME=C:\Program Files (x86)\Java\jre6
    • SET NWCETOOLLIB=C:\NWDS\NWCE_TOOLS\tools\lib
    • nwcetool.bat
    • createsda -n MAttachToDir -v sap.com -l MAttachToDir -c 2 -type J2EE C:\Users\User\Desktop\bLOG_jAM\MAttachToDir_EAR.ear C:\Users\User\Desktop\bLOG_jAM\MAttachToDir_SDA
    • Where
      • createsda -n JNDI-Name -v Vendor-Name -l JNDI-Name -c 2 -type J2EE Source of \EAR_file_path Destination of\SDA_file_Path
  • Now rename file “MAttachToDir_SDA.ear” to “MAttachToDir_SDA.sda

 

Steps to Deploy SDA files in PI-Server:

  • SDA File deployment using Telnet in SAP-PI:
    1. Place the sda file (MAttachToDir_SDA.sda) in directory ‘/usr/sap/trans/EPS/in/’
    2. Update the file ‘/usr/sap/trans/EPS/in/deploylist.txt’ with the file to be deployed
    3. Use below commands
      • telnet localhost <port>
      • Username: <enter j2ee_admin user>
      • Passwrod: <*******>
      • deploy list=/usr/sap/trans/EPS/in/deploylist.txt version_rule=all
    4. Post Deployment, SDA file gets extracted in below SAP-PI’s folder path, having folder name as of JNDI-Name ‘MAttachToDir
      • /usr/sap/<systemID>/<instance>/j2ee/cluster/apps/sap.com/MAttachToDir/
    5. In SAP-PI’s NWA, we can check deployed modules as below:
      • SAP-PI’s NWA url: http://<sap-pi-host>:<sap-pi-port>/nwa
      • Go to -> NWA -> Problem Management -> Java -> JNDI Browser Operation Management -> System -> Start & Stop -> Java EE Applications
To report this post you need to login first.

6 Comments

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

  1. Manoj K

    Nice one Dilip. Clearly explained Step by Step.

    But i believe this module will work only in case NFS isn’t it? Because i can see in your module implementation you are just building FilePath to the local server. In case you need to drop it to external server you need to implement FTP/SFTP connection to the server in the module code itself.

     

    (0) 
    1. Evgeniy Kolmakov

      Hi Dilip!

      And why not to use SFTP adapter for that at receiver’s side? As I could see from your code, you consider your PI OS to be the Unix OS (by the way, avoid using hardcoded file path separators in any code, your module will raise exception on Windows OS, for example. Use “File.separator” instead).

      Regards, Evgeniy.

      (0) 
      1. Dilip Kumar KrishnaDev Pandey Post author

        Dear Evgeniy Kolmakov

        • Thanks for suggestion on filePath check, in module code we can give a condition if directory exists then proceed or throw module exception with message as “Directory not found”.
        • We can use SFTP adapter at receiver side as this adapter supports multiple attachments, here no need of any custom module.
        • But in my case, I have to work with SAP-ECC-Directory which is accessible from SAP-PI using filePath reference only, so I have to use File-Receiver Channel and module is to make it compatible to handle multiple attachments.

        Thanks & Regards,

        Dilip.

        (0) 
        1. Evgeniy Kolmakov

          Hi Dilip!

          1. I just wanted to point on the way to create more flexible, reusable and robust applications.

          2. Since you have access to your resource using java IO, this means that it is mounted to PI’s file system. And most of Unix/Linux systems provide access to its file system using SSH by default. So you could use SFTP adapter to access PI file system without any additional SFTP server software required.

          Regards, Evgeniy.

          (0) 

Leave a Reply