Creating a temporary file in a Mendix Java Action
Introduction
Over the past few months I've had to create a number of Java Actions that had to deal with files. In most cases you can directly use the Java InputStream from the Mendix FileDocument but there are some libraries and methods that only works with a java.io.File. As the logic to create a temporary file can easily be made reusable, I created a helper class to encapsulate all of my custom logic for file handling.
Design
Normally when you create additional methods for a Java Action they go into the EXTRA CODE section of the Java class that Mendix generates. While methods placed here are technically reusable within the project a better approach is to create a new folder to store all of your reusable code. I have a folder called shared in the javasource folder where I place all of my reusable Java classes. This folder can be easily transported between different Mendix projects making the code fully reusable.
Java Code
ReadStreamIntoTemporaryFile Method
public static java.io.File ReadStreamIntoTemporaryFile(IContext mxContext, String filename, String extension, IMendixObject mendixFile) throws Exception
{
InputStream iStream = Core.getFileDocumentContent(mxContext, mendixFile);
java.io.File file = java.io.File.createTempFile(filename, extension);
try
{
FileOutputStream outputStream = new FileOutputStream(file, false);
int read = 0;
byte[] bytes = new byte[1024];
while ((read = iStream.read(bytes)) != -1)
{
outputStream.write(bytes, 0, read);
}
outputStream.flush();
outputStream.close();
return file;
}
catch (Exception exception)
{
file.delete();
throw(exception);
}
}
The method takes the following parameters.
- mxContext which is the Mendix context to use for retrieving the file.
- filename to use for naming our temporary file. This name should not include the file extension. Note that creating a temporary file will use the filename as well as some form of a GUID to guarantee uniqueness. As such this method can be called multiple times with the same name and each will create a separate file.
- extension for the temporary file, this should include the ".", so for example ".pdf".
- mendixFile is the IMendixObject that contains our FileDocument.
We first retrieve the file's stream from Mendix using the getFileDocumentContent method. Then we create a new temporary file using the createTempFile method from the java.io.File class. Next we create a FileOutputStream for the temporary file and proceed to write all the bytes from the InputStream to it. Once all the data has been read from the InputStream we flush and close the OutputStream and return the file.
In addition, if an exception occurs, we delete the temporary file we created and then rethrow the exception to the calling method. This makes sure that we don't get a buildup of unused temporary files.
WriteTemporaryFileToMendixFile Method
In most cases, once the changes have been made to the file we want to store the updated file in Mendix. The logic to do this is trivial, but I decided to create a method for this as well so I don't have to remember how to do it every time.
public static void WriteTemporaryFileToMendixFile(IContext mxContext, java.io.File file, IMendixObject mxFile) throws Exception
{
FileInputStream inputStream = new FileInputStream(file);
Core.storeFileDocumentContent(mxContext, mxFile, inputStream);
inputStream.close();
}
The parameters for the method are as follows.
- mxContext which is the Mendix context to use for storing the file.
- file that we want to persist to Mendix.
- mxFile is the IMendixObject containing the FileDocument to which we will persist the data.
The method creates a FileInputStream for the provided file and then stores it to Mendix using the storeFileDocumentContent method. Once done we simply close the stream.
Conclusion
We now have a fully reusable class that provides us with methods that can be used to create a temporary java.io.File and one to write the file back to a Mendix FileDocument. The class can be easily reused in other Mendix projects/modules that needs to create a java.io.File.