Create zip file in memory and on Disk

In context of Mule3, if we need to create zip file with n number of files in it, where n will keep changing as per our requirement.

2 ways in which we can achieve this

  1. Create a unique folder per request, and dump all the required files inside this folder, which will finally be zipped.
  2. Create ByteArrayOutputStream, attach it to ZipOutputStream and then create a ZipEntry associate every ZipEntry (Write) to ZipOutputStream, finally ByteArrayOutputStream would be our stream of zipfile content.

 

Approach 1 :

  • Numerous ways of doing this one of the way is using walk file tree feature of Java NIO, where in we can zip the entire directory and sub-directory, exactly what we need.
  • For Indepth understanding one of the good write ups, https://www.baeldung.com/java-nio2-file-visitor

Sample Code :

import java.io.FileOutputStream;

import java.io.IOException;

import java.nio.file.*;

import java.nio.file.attribute.BasicFileAttributes;

import java.util.zip.ZipEntry;

import java.util.zip.ZipOutputStream;

 

public class ZipCompress {

public static void compress(String dirPath) {

final Path sourceDir = Paths.get(dirPath);

String zipFileName = dirPath.concat(“.zip”);

try {

final ZipOutputStream outputStream = new ZipOutputStream(new FileOutputStream(zipFileName));

Files.walkFileTree(sourceDir, new SimpleFileVisitor<Path>() {

@Override

public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) {

try {

Path targetFile = sourceDir.relativize(file);

outputStream.putNextEntry(new ZipEntry(targetFile.toString()));

byte[] bytes = Files.readAllBytes(file);

outputStream.write(bytes, 0, bytes.length);

outputStream.closeEntry();

} catch (IOException e) {

e.printStackTrace();

}

return FileVisitResult.CONTINUE;

}

});

outputStream.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

  • Another easy one is Apache Commons Inbuild Library to write file to a specific directory, then use ZipOutputStream to finally Zip it.

Sample Code :

FileUtils.copyInputStreamToFile(inputStream, folderLocationToPlaceTheFile);

  • Common thing here would be to use ZipOutputStream, to finally zip the entire directory.
  • Writing and reading files involved IO operation, which would be little slower, depending how many files we need to read / write.

 

Approach 2 :

  • Suppose say as in the scenario described in approach 1, if we are getting file from an Objectstore (S3, Apache Minio, DB ..) and we are getting one file at a time, instead of writing everything to file system if we can zip the file in Memory would be lot faster.
  • From Memory Consumption point of view, files should definetly not be huge, in one of the scenario I worked on, we needed to zip pdf files size hardly in 10’s of KB, so even if anypoint we were getting 1000’s of PDF for a particular client, we would not be even going to 100 MB (Load Testing Result), in this scenario, performance was more important and with different system interacting (as in our case) we decided to go with In Memory Zipping of the file.

Code Sample :

// In the below example, JavaPojoObject is a simple Pojo class, having relevant details

// about the filename, storeLocation etc. I feel this convenient to play around by

// creating list which could easily converted to Json back to Java or any other format.

try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {

try (ZipOutputStream zos = new ZipOutputStream(baos);) {

for (JavaPojoObject obj : javaPojoObjectList) {

String filename = obj.getFileName();

byte[] fileContent = yourImplementation

ToGetFileFromYourObjectStore();

ZipEntry individualEntry = new ZipEntry(filename);

individualEntry.setSize(fileContent.length);

zos.putNextEntry(individualEntry);

zos.write(fileContent);

zos.closeEntry();

}

 

}

// baos – now has the entire zip file content, wisely do things you need to ..

}

 

Rabbit MQ Setup and SSL Connectivity with Mule

Parallel Processing

There are different ways in which we can achieve this, but my personal favorite is using some kind of external Queuing Mechanism, which will help us do the processing at all the Server node levels within a Cluster (We should have a Cluster setup, and in Enterprise world that would always be the case).

 

Although Mule has its own VM Queue, it’s in Memory, and could be used for say Reliability Pattern or Inter Flow Communication, basically we need to make sure that there is not huge data we are trying to store in VM Queues, and if we are really want to do parallel processing for Heavy Objects and just for the topping it takes time for processing (This comes with the flavor of our Architecture as we need to make sure that our system when doing Parallel Processing is Fault Tolerant and we cannot lose a single message, means we need to release a message from Queue only when we want to – Will talk about the entire Design of Highly Scalable System in another post).

 

Here, we will be writing only about the setup of RabbitMQ and how to use it in Mule.

 

Rabbit MQ – SSL Connectivity with Mule.

 

  1. First we need to have a Rabbit MQ Server with SSL and TLS enabled.
  2. Follow this site from rabbit mq to set up the server accordingly.

Refrence : https://www.rabbitmq.com/ssl.html

Nice Article depicting the same : http://yuanmengblog.blogspot.com/2015/08/use-mule-amqps-ssl-to-connect-to.html

 

  1. Once the Certs are installed on Rabbit MQ Server, we will have to tell Rabbit MQ, use this SSL and allow connectivity only if Request is coming with a valid .jks and .p12 file.
  2. We can enable this by going to /etc/rabbitmq/conf

Enable below option, ssl_options.fail_if_no_peer_cert = true

 

Complete Configuration, related to SSL.

 

## TLS configuration.

##

## Related doc guide: http://rabbitmq.com/ssl.html.

##

 

ssl_options.cacertfile = /etc/rabbitmq/testca/cacert.pem

ssl_options.certfile = /etc/rabbitmq/server/cert.pem

ssl_options.keyfile = /etc/rabbitmq/server/key.pem

ssl_options.verify = verify_peer

ssl_options.fail_if_no_peer_cert = true

 

ssl_options.versions.1 = tlsv1.2

ssl_options.versions.2 = tlsv1.1

 

Steps to Set up Mule to Connect to Rabbit MQ with SSL Enabled

  1. Generate Truststore using .pem file from Server (we will have .pem in client and test ca as well, we need to select server file here).
  2. Use .p12 file from client, and associated password which should be provided if you were not the one who set up SSL on Rabbit MQ Server, if you yourself did the SSL Set up on Rabbit MQ, you know it .

 

Example:

<amqps:connector name=”AMQPS_0_9_Connector1″ validateConnections=”true” host=”10.20.30.40″ username=”app_admin” password=”somepassword” doc:name=”AMQPS-0-9 Connector”>

<amqps:ssl-key-store path=”/Users/vashists/Documents/rabbitmq-ssl-ananth/rabbit-ssl-config/client/keycert.p12″ keyPassword=”MySecretPassword” storePassword=”MySecretPassword” type=”pkcs12″ algorithm=”SunX509″/>

<amqps:ssl-trust-store path=”/Users/vashists/Documents/rabbitmq-ssl-ananth/rabbit-ssl-config/trustStore.jks” storePassword=”abc123″ type=”jks” algorithm=”SunX509″/>

</amqps:connector>

 

 

 

Reload Mule App Properties without Restarting or RedeployingApp

This is something which I liked, as we had the requirement (not discussing the requirement here) where in Admin Team will change the Mule Properties file, and Running Application should be able to pick this up at Runtime.

Basic Idea here is, to load property from Spring Bean, as all the SpringBeans will be available in Mule Registry, so if we need to reload, at regular time (Poll Mechanism) we should be able to read the same Spring Bean and update the Mule Registry.

Step 1: Define Spring Bean

<spring:bean id=“PropertyFileReader” name=“PropertyFileReader” class=“com.util.PropertyFileReader” scope=“singleton”/>

Step 2:

Java Code to Read Properties file

Step 3:

Poll Component to poll at regualar intervals, this flow will invoke the Java Class defined in Step 2.

New Java Component will call Java Class defined in Step 2, and will set it in registry.

This is it !!!

Only thing we need to understand is how Mule handles Spring in Mule Registry, so basically we are just playing with the Bean already registered in Mule Registry.