Filetransfer Client
Introduction
The SwiftMQ Filetransfer client is an easy-to-use client to transfer files of unlimited size between JMS clients and a SwiftMQ Router. It uses an existing JMS connection and can be easily integrated with any JMS application.
The client API consists of only 3 classes:
Class | Package | Description |
---|---|---|
| com.swiftmq.filetransfer | Provides the Filetransfer client. |
| com.swiftmq.filetransfer | A filetransfer exception class. |
| com.swiftmq.filetransfer | Provides information about the progress of a file transfer. |
Samples
There are several example programs provided under the SwiftMQ distribution's directory "samples/filetransfer". Please have a look!
Protecting Files
A file can be protected by a password that needs to be specified during receive. A file can also be declared as private. Links to private files are not returned from a query, rather the link needs to be known.
File Expiration
Similar to JMS messages, a file can have an expiration which is specified in milliseconds. The file is automatically deleted after it has expired.
Maximum Downloads
The maximum number of downloads can be specified for a file. The file is automatically deleted after this number has been reached.
Message Properties and Selectors
The following message properties are automatically set during send:
Property | Type | Value |
---|---|---|
|
| The JMS user who sent the file. |
|
| The original filename |
|
| File size in bytes |
|
| The absolute expiration time in ms (since 01/01/1970) |
|
| The digest type, e.g. "SHA1". |
|
| The absolute store time in ms (since 01/01/1970) |
|
| The number of downloads after which the file will be deleted. |
|
| The current number of downloads. |
The sender can add arbitrary custom JMS message properties to a file, e.g. by setting an "orderid" property to mark a file containing a purchase order.
In addition to the Filetransfer
properties listed above, all custom properties can be used in a message selector, too. For example, if custom property "orderid" was set as a custom property and one wants to get all PDF files for a particular order id, a query might look like this:
orderid = 12345 and JMS_SWIFTMQ_FT_FILENAME like '%.pdf'
To select all zip-files of a particular customerId range which are bigger than 1 MB, use this selector:
JMS_SWIFTMQ_FT_FILENAME like '%.zip'
and customerid between 10000 and 11500
and JMS_SWIFTMQ_FT_SIZE > 1024 * 1024
Sending Files
The most basic usage of a Filetransfer
object to send files is to create it, set the file to send, send and close it:
Filetransfer filetransfer = Filetransfer.create(connection, routerName, cacheName);
String link = filetransfer.withFile(file).send();
filetransfer.close();
A Filetransfer
object can be used to send multiple files sequentially but can not be used by multiple threads (use a dedicated Filetransfer
object per thread, see Filetransfer
samples):
Filetransfer filetransfer = Filetransfer.create(connection, routerName, cacheName);
for (int i=0; i < files.length; i++)
filetransfer.withFile(file[i]).send();
filetransfer.close();
Various other settings can be applied in a builder style fashion:
Filetransfer filetransfer = Filetransfer.create(connection, routerName, cacheName);
String link = filetransfer.withDigestType("SHA1")
.withFileIsPrivate(isPrivate)
.withPassword("Cheers")
.withFile(file)
.send();
filetransfer.close();
In addition to a bunch of message properties that are automatically set from the Filetransfer
, custom message properties can be added to each file that can be used to select them through a message selector:
Map props = new HashMap();
props.put("orderid", orderId);
props.put("customerid", customerId);
props.put("documenttype", docType);
Filetransfer filetransfer = Filetransfer.create(connection, routerName, cacheName);
String link = filetransfer.withDigestType("SHA1")
.withFileIsPrivate(isPrivate)
.withPassword("Cheers")
.withProperties(props)
.withFile(file)
.send();
filetransfer.close();
A ProgressListener
can be used too:
Filetransfer filetransfer = Filetransfer.create(connection, routerName, cacheName);
String link = filetransfer.withFile(file).send(new ProgressListener()
{
public void progress(String filename, int chunksTransferred,
long fileSize, long bytesTransferred,
int transferredPercent)
{
System.out.println(" " + filename + ": " + chunksTransferred +
" chunks, "+ bytesTransferred + " of " + fileSize +
" transferred (" + transferredPercent + "%)");
}
});
filetransfer.close();
Receiving Files
The most basic usage of a Filetransfer
object to receiving a file is to create it with a link, set the output file, receive and close it:
Filetransfer.create(connection, link)
.withFile(file)
.receive()
.close();
To delete the file at the file cache after receive, call:
Filetransfer.create(connection, link)
.withFile(file)
.receive()
.delete()
.close();
One can also use the original filename. In that case the output directory needs to be specified:
Filetransfer.create(connection, link)
.withOutputDirectory(outDir)
.withOriginalFilename(true)
.receive()
.delete()
.close();
The password needs to be specified if file is protected:
Filetransfer.create(connection, link)
.withOutputDirectory(outDir)
.withOriginalFilename(true)
.withPassword("Cheers")
.receive()
.delete()
.close();
A ProgressListener
can be used too:
Filetransfer.create(connection, link)
.withOutputDirectory(outDir)
.withOriginalFilename(true)
.receive(new ProgressListener()
{
public void progress(String filename, int chunksTransferred,
long fileSize, long bytesTransferred,
int transferredPercent)
{
System.out.println(" " + filename + ": " + chunksTransferred +
" chunks, "+ bytesTransferred + " of " + fileSize +
" transferred (" + transferredPercent + "%)");
}
}).delete().close();
Querying Links
There are 2 ways to get a link to a file:
The sending client sends it to the receiving client by using JMS (e.g. sends a JMS
TextMessage
). This is required for private files.The receiving client queries the file cache.
To query a file cache, any existing or a new Filetransfer
object can be used:
Filetransfer filetransfer = Filetransfer.create(connection, routerName, cacheName);
List<String> result = filetransfer.query();
filetransfer.close();
final CountDownLatch countDownLatch = null;
if (result != null && result.size() > 0)
{
countDownLatch = new CountDownLatch(result.size());
for (int i = 0; i < result.size(); i++)
{
final String link = result.get(i);
executorService.execute(new Runnable()
{
public void run()
{
transfer(link); // Uses a dedicated Filetransfer object to receive a file
countDownLatch.countDown();
}
});
}
}
if (countDownLatch != null)
countDownLatch.await();
A JMS message selector can be used to select specific files:
Filetransfer filetransfer = Filetransfer.create(connection, routerName, cacheName);
List<String> result = filetransfer.withSelector(selector).query();
filetransfer.close();
// ....
Querying Properties
Sometimes it is necessary to retrieve the properties of a file before the file itself will be downloaded. This can be done as follows:
Filetransfer filetransfer = Filetransfer.create(connection, routerName, cacheName);
Map<String, Map<String, Object>> result = filetransfer.queryProperties();
// ....
filetransfer.close();
A Map
is returned where the keys are links and the values are another Map
with the properties. The properties contain those listed in the above section as well as all custom properties.
A JMS message selector can be used to select specific files:
Filetransfer filetransfer = Filetransfer.create(connection, routerName, cacheName);
Map<String, Map<String, Object>> result = filetransfer.withSelector(selector).queryProperties();
// ....
filetransfer.close();
To query the properties of a particular file, specify the link:
Filetransfer filetransfer = Filetransfer.create(connection, routerName, cacheName);
Map<String, Map<String, Object>> result = filetransfer.withLink(link).queryProperties();
// ....
filetransfer.close();
If the file cache contains many files it is recommended to use a selector or a link to reduce the result because the result is returned in a single message internally which becomes quite big.