Skip to Content

In this doucment, I will show how we can zip the incoming attachments and create a new zip attachment during mapping step. We can also remove the original incoming attachments if they are not required. The concept is applicable from PI7.1 version onwards.

Create a java mapping with below code and use it as first mapping in your operation mapping step.


Java Mapping Code


  import java.io.*;
 import java.util.Map;
 import java.util.HashMap;
 import java.util.*;
 import java.util.zip.*;
 import com.sap.aii.mapping.api.AbstractTrace;
 import com.sap.aii.mapping.api.*;
 import com.sap.aii.mapping.api.AbstractTransformation;
 import com.sap.aii.mapping.api.TransformationInput;
 import com.sap.aii.mapping.api.TransformationOutput;
// import com.sap.aii.mapping.api.StreamTransformation;
// import com.sap.aii.mapping.api.StreamTransformationConstants;
 import com.sap.aii.mapping.api.StreamTransformationException;
 public class AttachmentsZipJM extends AbstractTransformation {
              private static final DynamicConfigurationKey contentIDSKey = DynamicConfigurationKey.create("http://test.com", "contentIDS");
        public void transform(TransformationInput in, TransformationOutput out) throws StreamTransformationException
                        {
                                    try
                                    {
                                                DynamicConfiguration conf = (DynamicConfiguration) in.getDynamicConfiguration();
                                                // get message ID
                                                String msgID = (String) in.getInputHeader().getMessageId();
                                                String s = null;
                                                int len = 0;
                                                Object[] arrayObj = null;
                                                byte[] buffer = new byte[1024];
                                                byte[] attachmentBuffer = new byte[1024];
                                                String attachmentID = null;
                                                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                                                ZipOutputStream zos = new ZipOutputStream(baos);
                                                ZipEntry anEntry = null;
                                                InputStream is = (InputStream) in.getInputPayload().getInputStream();
                                                while ((len = is.read(buffer)) > 0)
                                                {
                                                            out.getOutputPayload().getOutputStream().write(buffer, 0, len);                                                  
                                                }
                                                InputAttachments inputAttachments = in.getInputAttachments();
                                                if(inputAttachments.areAttachmentsAvailable())
                                                {                                                          
                                                            //gets the attachmentIds and store it in an Object array
                                                            Collection<String> collectionIDs = inputAttachments.getAllContentIds(true);
                                                            arrayObj = collectionIDs.toArray();
                                                            //Object[] arrayObj = collectionIDs.toArray();
                                                            String contentIDS = "";
                                                            //Loops at the input attachments to get the content of the attachment and then write it to zip output stream wrapper.
                                                            for(int i =0;i<arrayObj.length;i++)
                                                            {
                                                                        attachmentID =(String)arrayObj[i];
                                                                        contentIDS = contentIDS + (i+1) + ") " + attachmentID + "; ";
                                                                        Attachment attachment = inputAttachments.getAttachment(attachmentID);            
                                                                        byte[] attachmentBytes = attachment.getContent();
                                                                        zos.putNextEntry(new ZipEntry(attachmentID));
                                                                        zos.write(attachmentBytes);
                                                                        zos.closeEntry();           //Close each zipentry after writing it to stream
                                                                        //remove each attachment if required. Uncommonent below line
                                                                        //out.getOutputAttachments().removeAttachment(attachmentID);                                                 
                                                            }
                                                            zos.close();       //Close Zip Stream
                                                            conf.put(contentIDSKey, contentIDS);
                                                }
                                                Attachment newopAttachment = out.getOutputAttachments().create(msgID + ".zip", baos.toByteArray());
                                                out.getOutputAttachments().setAttachment(newopAttachment);
                                    }
                                    catch(Exception e)
                                    {
                                                e.printStackTrace();
                                    }
        }
 }

The same can be achieved in graphical mapping using below code. Use the UDF in between source and target root nodes. Ensure to explicitly mention java.util.zip.* package under import statements of UDF function.


/wp-content/uploads/2012/04/5_90801.jpg

Graphical Mapping UDF Code


String attachmentID = null;
String msgID = null;
String contentIDS = "";
java.util.Map map;
AbstractTrace trace;
//gets the input attachment from the source message
GlobalContainer globalContainer = container.getGlobalContainer();
InputAttachments inputAttachments = globalContainer.getInputAttachments();
OutputAttachments outputAttachments = globalContainer.getOutputAttachments();
trace = container.getTrace();
map = globalContainer.getParameters();
msgID = (String) map.get(StreamTransformationConstants.MESSAGE_ID);
trace.addInfo("Message ID:" + msgID);
DynamicConfiguration conf = (DynamicConfiguration) map.get(StreamTransformationConstants.DYNAMIC_CONFIGURATION);
DynamicConfigurationKey contentIDSKey = DynamicConfigurationKey.create("http://test.com", "contentIDS");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(baos);
try
{
            //checks for the availability of attachments in the input message
            if(inputAttachments.areAttachmentsAvailable())
            {
                        trace.addInfo("Attachments Available");
                        //gets the attachmentIds and store it in an Object array
                        Collection<String> CollectionIDs = inputAttachments.getAllContentIds(true);
                        Object[] arrayObj = CollectionIDs.toArray();
                        //Loops at the input attachments to get the content of the attachment
                        for(int i =0;i<arrayObj.length;i++)
                        {
                                    attachmentID =(String)arrayObj[i];
                                    contentIDS = contentIDS + (i+1) + ") " + attachmentID + "; ";
                                    trace.addInfo("Attachment no: " + (i+1) + " & Name: " + attachmentID);
                                    Attachment attachment = inputAttachments.getAttachment(attachmentID);
                                    byte[] attachmentBytes = attachment.getContent();
                                    trace.addInfo("Creating Zip Entry for attachmet no: " + (i+1));
                                    zos.putNextEntry(new ZipEntry(attachmentID));
                                    zos.write(attachmentBytes);
                                    zos.closeEntry();           //Close each zipentry after writing it to stream
                                    //remove each attachment if required. Uncommonent below
                                    //trace.addInfo("Removing Attachment no: " + (i+1) + " & Name: " + attachmentID);
                                    //outputAttachments.removeAttachment(attachmentID);                                                              
                        }
                        zos.close();
                        conf.put(contentIDSKey, contentIDS);
                        trace.addInfo("Creating new Zip Attachment: " + msgID + ".zip");
                        Attachment newopAttachment = outputAttachments.create(msgID + ".zip", baos.toByteArray());
                        outputAttachments.setAttachment(newopAttachment);
            }          
}
catch (Exception e)
{
            e.printStackTrace();
}
return    var1; //return “1”;

I tested a sample SOAP to Mail scenario with above code and the results are as below.


/wp-content/uploads/2012/04/1_90797.jpg

2.JPG

3.JPG

In RWB for mail receiver adapter,


4.JPG

The zipping/unzipping of attachments can also be achieved at adapter level using PayloadZipBean module.

To report this post you need to login first.

3 Comments

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

  1. sanka perera

    Hi Praveen,

    I’m using Bytearrayoutputstream and gzipoutputstream classes with in a UDF, simmillar to what you’re doing with attachments. I’m passing whole xml message as a string to this UDF using “return as xml” option. Can this cause any space issues in PI DB? I have noticed, PI database is growing faster after implementing this solution. Following is my UDF code.

    public String msgcompress(String str, Container container) throws StreamTransformationException{

    ByteArrayOutputStream out = new ByteArrayOutputStream();

    try
    {

    //Compress Message
            GZIPOutputStream gzip = new GZIPOutputStream(out);
            gzip.write(str.getBytes(“UTF-8”));
            gzip.close();
            byte[] theZByteArray = out.toByteArray();

    //Convert Compressed binary into BASE64 string
            str = DatatypeConverter.printBase64Binary(theZByteArray);

    }

    catch (IOException uee) {
    uee.printStackTrace();
    }

    return str;
    }

    Thanks & Regards,

    Sanka.

    (0) 
    1. Praveen Gujjeti Post author

      Hi Sanka,

      Can you please raise your issue as a discussion, since you can get better answers from forum experts. As far as I see your code, I did not find any issues with your code, not sure why your PI DB space growing. What is the “return as xml” size? Did you tried this code in any other PI system.

      Regards,

      Praveen Gujjeti

      (0) 
      1. sanka perera

        Hi Praveen,

        Thanks a lot for the reply. I have already posted this issue as a discussion. So far didn’t get any reply. Return as xml size is around 7 MB. Around 400 messages are processed per day. I tried this code in test system first, there were space issues during testing. But message log deletion jobs were not worked properly in test system. so ignored space issues while testing. But last week same thing happened in PRD system. After using this for three days PRD db was full. In prd message retention period is 1 day, so production DB should be able to easily handle the load. We were able to use the same interface without compression for more than a year.

        Thanks & Regards,

        Sanka

        (0) 

Leave a Reply