With the introduction of a brand-new Java module in Mule 4, it is now possible to invoke Java classes in a more straightforward manner from the flow or in Dataweave 2.0 itself.
Here is a simple demonstration of file manipulation using custom Java classes and methods in Mule Anypoint Studio 7.1. This step-by-step tutorial shows how to:
1. Create a custom java class to list files recursively for a local or shared network path
2. Invoking this class from Mulesoft Dataweave 2.0 transformations, and filter information.
Here is a simple demonstration of file manipulation using custom Java classes and methods in Mule Anypoint Studio 7.1. This step-by-step tutorial shows how to:
1. Create a custom java class to list files recursively for a local or shared network path
2. Invoking this class from Mulesoft Dataweave 2.0 transformations, and filter information.
There is a dependency on apache commons-io, log4j and joda-time as I will be reusing some methods for file manipulation.
You can find the jar file or maven references here:
https://mvnrepository.com/artifact/commons-io/commons-io/2.6https://mvnrepository.com/artifact/joda-time/joda-time
https://mvnrepository.com/artifact/log4j/log4j
1. Create your Mule project and add maven dependency
Download the apache commons-io jar file, or alternatively include the reference in your maven pom.xml file.
For this example, I am going to include it as a maven dependency. Copy and paste the code below and include it between the dependencies node in pom.xml, before the closing node:
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
Side note: In my custom class I am also making use of log4j and joda so those are included as maven dependencies as well.
<!-- https://mvnrepository.com/artifact/joda-time/joda-time -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
Next, create a custom Java class in your Mule project by right clicking on the src/main/java/ folder -> New -> Class
I am going to name my class CustomFileUtils with the namespace customUtils.
Inside my class I am going to declare 3 static methods: listFilesByExtension, listOldFiles, deleteOldFiles
(Now do take note that Mule4 does have a comprehensive File List component that does the same thing (list files in a directory). It returns a collection of File objects. However, I prefer something more lightweight, e.g. returning just the file paths for further manipulation. Besides, I wanted to be able to traverse sub folders as well.)
My custom Java class:
package customUtils;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.AgeFileFilter;
import org.apache.commons.io.filefilter.TrueFileFilter;
import org.joda.time.DateTime;
import org.apache.log4j.Logger;
public class CustomFileUtil {
private static Logger log = Logger.getLogger(CustomFileUtil.class);
// List files by passing in extensions to filter on
public static ArrayList<String> listFileNames(String path, String[] extensions, boolean recursive) {
File src = new java.io.File(path);
if (!src.exists()) return null;
Collection<File> files = FileUtils.listFiles(src, extensions, recursive);
ArrayList<String> classes = new ArrayList<String>();
for (File file : files) {
classes.add(file.getPath());
}
return classes;
}
// A way to clear files in any directory by passing in the days
public static ArrayList<String> deleteOldFiles(String dir, int daysToRemainFiles) {
File src = new java.io.File(dir);
if (!src.exists()) return null;
ArrayList<String> deletedFiles = new ArrayList<String>();
int failedDeletion = 0;
// List files older than x days
Collection<File> filesToDelete = FileUtils.listFiles(src,
new AgeFileFilter(DateTime.now().withTimeAtStartOfDay().minusDays(daysToRemainFiles).toDate()),
TrueFileFilter.TRUE); // include sub dirs
for (File file : filesToDelete) {
deletedFiles.add(file.getPath());
boolean success = FileUtils.deleteQuietly(file);
if (!success) {
// log to Mule's log4j
log.info("Failed to delete file " + file.getPath());
failedDeletion += 1;
}
}
// Log total files processed and deleted
log.info("Total files found: " + filesToDelete.size() + ", failed to delete " + failedDeletion);
return deletedFiles;
}
// List files in any directory by passing in the days
public static ArrayList<String> listOldFiles(String dir, int daysToRemainFiles) {
File src = new java.io.File(dir);
if (!src.exists()) return null;
ArrayList<String> oldFiles = new ArrayList<String>();
// List files older than x days
Collection<File> filesToDelete = FileUtils.listFiles(src,
new AgeFileFilter(DateTime.now().withTimeAtStartOfDay().minusDays(daysToRemainFiles).toDate()),
TrueFileFilter.TRUE); // include sub dirs
for (File file : filesToDelete) {
oldFiles.add(file.getPath());
}
return oldFiles;
}
}
In order to include this as a reference in my project, I need to add the namespace to mule-artifact.json as below:
Below is a simple flow with a HTTP listener which will accept a POST value named path containing the full path to a folder or network directory.
To reference a custom Java class, you need to add the import java!:: statement. In the example below, I reference a public static method exposed by the custom Class. To recap, the method was:
public static ArrayList listFileNames(String path, String[] extensions, boolean recursive) {}
** Take note that at the time of writing, Dataweave 2.0 does not support having period (.) in the package name.
For example, if my class name was com.something.CustomFileUtil instead of CustomFileUtil, the Dataweave parsing will throw an error.
The complete flow xml:
<flow name="listFilesWithDataweaveFlow" doc:id="22bac947-3406-484e-bb61-2cd418aac08d" >
<http:listener doc:name="Listener" doc:id="247a6d13-5750-43e4-80ac-96ff23064799" config-ref="HTTP_Listener_config" path="list-files" allowedMethods="POST"/>
<ee:transform doc:name="Transform Message" doc:id="4ba2a858-0b3c-4d2d-9c5c-71b509147bdb" >
<ee:message >
<ee:set-payload ><![CDATA[%dw 2.0
import java!customUtils::CustomFileUtil
output application/json
---
{
files: CustomFileUtil::listFileNames(payload.path as String, ["txt", "pdf"], false)
}]]></ee:set-payload>
</ee:message>
</ee:transform>
</flow>
5. Test your flow
Test it in a tool such as POSTMAN and you should be able to retrieve a list of file paths matching the txt or pdf extension like below.
The request headers:
Response:
Thank you for taking the time to read this article!
Next : a postreusing the same Java custom class, but this time with the Java Invoke methodinstead of using Dataweave.
Next : a postreusing the same Java custom class, but this time with the Java Invoke methodinstead of using Dataweave.
3 comments:
Thank you for sharing wonderful information with us.
MuleSoft Online Training
MuleSoft Training in Hyderabad
Very informative post for mulesoft developers.You can also visit goformule.com for mulesoft stuff.
This is good information and really helpful for the people who need information about this.
oracle training in chennai
oracle training institute in chennai
oracle training in bangalore
oracle training in hyderabad
oracle training
hadoop training in chennai
hadoop training in bangalore
Post a Comment