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 Universal 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
Filetransfer com.swiftmq.filetransfer Provides the Filetransfer client.
FiletransferException com.swiftmq.filetransfer A filetransfer exception class.
ProgressListener com.swiftmq.filetransfer Provides information about the progress of a file transfer.

javadoc and Samples

The Filetransfer client is part of swiftmq.jar, release 9.4.0 or higher. Look HERE to view the complete javadoc.

There are also 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
JMS_SWIFTMQ_FT_USERNAME String The JMS user who sent the file.
JMS_SWIFTMQ_FT_FILENAME String The original filename
JMS_SWIFTMQ_FT_SIZE long File size in bytes
JMS_SWIFTMQ_FT_EXPIRATION long The absolute expiration time in ms (since 01/01/1970)
JMS_SWIFTMQ_FT_DIGESTTYPE String The digest type, e.g. "SHA1".
JMS_SWIFTMQ_FT_STORETIME long The absolute store time in ms (since 01/01/1970)
JMS_SWIFTMQ_FT_DELAFTDL int The number of downloads after which the file will be deleted.
JMS_SWIFTMQ_FT_DOWNLOADCOUNT String The current number of downloads.

The sender can add arbritary 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 which 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<String, Object> props = new HashMap<String, Object>();
     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 receive 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 (since 9.4.1)

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.