Mule Zip File and send zipped file towards FTP server

六眼飞鱼酱① 提交于 2019-12-02 04:53:48

问题


I know Mule has great support for gzip compression of data using the element. However the client now wants zip compression since the file has to be placed on an FTP as a zip compressed file :(

I encounter difficulties in mule with following scenario:

I created a Spring bean where a file comes in. I want to compress this file using the ZipOutputStream class and pass it towards our ftp.

This is my flow configuration:

<flow name="testFlow" initialState="stopped">
    <file:inbound-endpoint path="${home.dir}/out" moveToDirectory="${hip.dir}/out/hist" fileAge="10000" responseTimeout="10000" connector-ref="input"/>
    <component>
        <spring-object bean="zipCompressor"/>
    </component>
    <set-variable value="#[message.inboundProperties.originalFilename]" variableName="originalFilename" />
    <ftp:outbound-endpoint  host="${ftp.host}" port="${ftp.port}" user="${ftp.username}" password="${ftp.password}" path="${ftp.root.out}" outputPattern="#[flowVars['originalFilename']].zip" />
</flow>

This is the code of my zipCompressor:

@Component
public class ZipCompressor implements Callable {

    private static final Logger LOG = LogManager.getLogger(ZipCompressor.class.getName());

    @Override
    @Transactional
    public Object onCall(MuleEventContext eventContext)  throws Exception {

        if (eventContext.getMessage().getPayload() instanceof File) {
            final File srcFile = (File) eventContext.getMessage().getPayload();
            final String fileName = srcFile.getName();
            final File zipFile = new File(fileName + ".zip");

            try {

                // create byte buffer
                byte[] buffer = new byte[1024];
                FileOutputStream fos = new FileOutputStream(zipFile);
                ZipOutputStream zos = new ZipOutputStream(fos);
                FileInputStream fis = new FileInputStream(srcFile);
                // begin writing a new ZIP entry, positions the stream to the start of the entry data
                zos.putNextEntry(new ZipEntry(srcFile.getName()));
                int length;
                while ((length = fis.read(buffer)) > 0) {
                    zos.write(buffer, 0, length);
                }
                zos.closeEntry();
                // close the InputStream
                fis.close();
                // close the ZipOutputStream
                zos.close();
            }
            catch (IOException ioe) {
                LOG.error("Error creating zip file" + ioe);
            }
            eventContext.getMessage().setPayload(zipFile);
        }
        return eventContext.getMessage();
     }
 }

I wrote a unit test and the compression works great. A file is indeed transferred to the FTP with the correct name, but the zip file is invalid and by opening it in NotePad++, it contains just the original file name.

I think I'm doing something wrong with passing the zip file back to the mule flow, but I'm stuck at the moment so any help would be greatly appreciated!


回答1:


I have implemented the transformer for this

    package com.test.transformer;

import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.mule.api.MuleMessage;
import org.mule.api.transformer.TransformerException;
import org.mule.transformer.AbstractMessageTransformer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ZipTransformer
  extends AbstractMessageTransformer
{
  private static final Logger log = LoggerFactory.getLogger(ZipTransformer.class);
  public static final int DEFAULT_BUFFER_SIZE = 32768;
  public static byte[] MAGIC = { 'P', 'K', 0x3, 0x4 };

  public ZipTransformer()
  {
    registerSourceType(InputStream.class);
    registerSourceType(byte[].class);
  }

  public Object transformMessage(MuleMessage message, String outputEncoding)
    throws TransformerException
  {
    Object payload = message.getPayload();
    try{
        byte[] data;
        if (payload instanceof byte[])
        {
            data = (byte[]) payload;
        }
        else if (payload instanceof InputStream) {
            data = IOUtils.toByteArray((InputStream)payload);
        } 
        else if (payload instanceof String)
        {
            data = ((String) payload).getBytes(outputEncoding);
        }
        else
        {
            data = muleContext.getObjectSerializer().serialize(payload);
        }
        return compressByteArray(data);
    }catch (Exception ioex)
    {
        throw new TransformerException(this, ioex);
    }
  }

  public Object compressByteArray(byte[] bytes) throws IOException
  {
      if (bytes == null || isCompressed(bytes))
      {
          if (logger.isDebugEnabled())
          {
              logger.debug("Data already compressed; doing nothing");
          }
          return bytes;
      }

      if (logger.isDebugEnabled())
      {
          logger.debug("Compressing message of size: " + bytes.length);
      }

      ByteArrayOutputStream baos = null;
      ZipOutputStream  zos = null;

      try
      {
          baos = new ByteArrayOutputStream(DEFAULT_BUFFER_SIZE);
          zos = new ZipOutputStream(baos);
          zos.putNextEntry(new ZipEntry("test.txt"));
          zos.write(bytes, 0, bytes.length);
          zos.finish();
          zos.close();

          byte[] compressedByteArray = baos.toByteArray();

          baos.close();
          if (logger.isDebugEnabled())
          {
              logger.debug("Compressed message to size: " + compressedByteArray.length);
          }

          return compressedByteArray;
      }
      catch (IOException ioex)
      {
          throw ioex;
      }
      finally
      {
          IOUtils.closeQuietly(zos);
          IOUtils.closeQuietly(baos);
      }
  }

  public boolean isCompressed(byte[] bytes) throws IOException
  {
      if ((bytes == null) || (bytes.length < 4 ))
      {
          return false;
      }
      else
      {
          for (int i = 0; i < MAGIC.length; i++) {
                if (bytes[i] != MAGIC[i]) {
                 return false;
                }
          }
          return true;
      }
  }


}

Used it as

<custom-transformer class="com.test.transformer.ZipTransformer" doc:name="file zip transformer"/>

As of now sets file name as test.txt. you can change is using any property or variable.

Hope this helps.




回答2:


A simpler way to do it is to use the gzip transformer in mule to compress the file. Note that you have to do it through the xml.

<gzip-compress-transformer/>



回答3:


In the ZipTransformer constructor, the following is deprecated.

registerSourceType(InputStream.class);
registerSourceType(byte[].class);

Use this instead:

registerSourceType(DataTypeFactory.create(InputStream.class));
registerSourceType(DataTypeFactory.create(byte[].class));


来源:https://stackoverflow.com/questions/37731108/mule-zip-file-and-send-zipped-file-towards-ftp-server

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!