Code sample - Using a callback for post upload/download logic

In this example I will show how to implement a callback object to perform proprietary logic on a file after is has been uploaded or downloaded.

First you have to create a callback object. You can do it by either implementing the DataConnectionCallback interface or extending the EmptyDataConnectionCallback class. The extension will be a better choice as you can omit implementing methods you don't need.

public class MyCallback extends EmptyDataConnectionCallback {

  public void onTransferComplete(DataConnection source) {
    System.out.println("Dummy callback");
  }

}
  

Now to declare this class in your beans.xml file:

<bean id="myCallback" class="example.MyCallback"/>
  

And hook it into your existing data connection (I used a data connection from the Intelligent Pack plug-in in this sample):

<bean id="dataConnection"
      class="com.coldcore.coloradoftp.plugin.intellipack.connection.IntelDataConnection"
  .........
  <property name="dataConnectionCallback" ref="myCallback"/>
</bean>
  

Now this MyCallback object will be called by every data connection when file transfer completes. All that is left is to implement a single method in the callback to operate on a file. But how can you get a reference to a file from a data connection passed as a parameter into the callback? It is important that you understand the difference between virtual and real filenames and how one maps to other, read the brief explanation below.

Virtual / Real filenames

A virtual filename is user's input (as a user enters it into a command) and a real filename is an actual path on your hard drive or database or whatever. The core knows nothing about how to map a virtual filename to its real path. It is up to your file system implementation to determine correct mappings and provide file streams into the core to perform the transfer.

A data connection is only aware about a virtual filename of a file being transferred (as a user enters it in a STOR/RETR command). The command stores this virtual filename in user's session AS IS under the SessionAttributeName.DATA_CONNECTION_FILENAME key.

To get the real path of a file you have to take advantage of your file system plug-in. Currently there is only one plug-in providing this functionality - Hard File System, so I will cover just that.

Hard File System plug-in maps a virtual filename to its real path and saves a File object into user's session under the transferred.file key. After a data connection terminates its session will contain this attribute pointing to an actual file on your hard drive, the file that has just been uploaded/downloaded. Just the thing you need!

public void onTransferComplete(DataConnection source) {
  Session session = source.getControlConnection().getSession();
  Object f = session.getAttribute("transferred.file");
  if (f instanceof File) {
    System.out.println("Transferred file: "+((File)f).getAbsolutePath());
  }
}
  

And one thing you definitely want is to distinguish between uploads and downloads. This can be done by querying the mode of a data connection which is also stored in user's session under the SessionAttributeName.DATA_CONNECTION_MODE key. Uploads set the mode to STOR or STOU while downloads set it to RETR.

public void onTransferComplete(DataConnection source) {
  Session session = source.getControlConnection().getSession();
  DataConnectionMode mode = (DataConnectionMode)
               session.getAttribute(SessionAttributeName.DATA_CONNECTION_MODE);
  Object f = session.getAttribute("transferred.file");

  if (f instanceof File) {
    if (mode == DataConnectionMode.STOR || mode == DataConnectionMode.STOU) {
      System.out.println("Uploaded file: "+((File)f).getAbsolutePath());
    }
    if (mode == DataConnectionMode.RETR) {
      System.out.println("Downloaded file: "+((File)f).getAbsolutePath());
    }
  }
}
  

The callback is now complete, just insert your own logic into it. That was not that hard, or was it?

sitemap