FileCatalyst provides many options for integration into 3rd party applications and workflows. Our SDK boasts a full range of components for a variety of development languages and environments.

Request Trial

Component Technology FileCatalyst Product
Client API Java, C++*, iOS*, Android*, .NET* Direct, Workflow
Java Applets, JavaScript API Any recent web browser with the Java Plug-in Direct
Remote Administration Java, REST Direct, Workflow
CLI / Shell Scripting Command Line* Direct, Workflow

*Transfer to and from Workflow and Webmail File Areas only.

The Development Kit is the foundation of our products; if you own any qualifying products, the Development Kit may be licensed as an add-on. For standalone development, the SDK is typically added on to FileCatalyst Direct; however, some components are designed to interact with FileCatalyst Workflow.

Watch SDK Webinar
Download accompanying example source code here

Client API

Our well-documented API gives access to every method needed to establish a connection to a FileCatalyst Server for accelerated file transfers. With a few short lines of code, you can be underway. Default values are used for most functions, with a full range of method calls allowing you to access advanced features.

The Client API also allows you to programmatically submit jobs and files to FileCatalyst Workflow or Webmail.

import unlimited.fc.client.api.*;
import java.io.*;

public class UploadSample {
  public static void main(String args[]) throws Exception {

    FCClient fc = new FCClient("192.168.1.30",21);
    fc.setShowConsoleLog(true);
    fc.initialize();
    fc.connect();
    fc.login("anonymous", "me@email.com");
    fc.setMode(TransferMode.UDP);

    //Set the start rate and target rate the same.  It will slow down if congestion encountered.
    fc.setStartRate(10000);
    fc.setTargetRate(10000);
    fc.setVerifyIntegrity(true);
    TransferHook upload = fc.upload(new File("c:/temp/500MB.zip"));

    while (!upload.isTransferComplete()) {
      // you could display some progress information here using the various methods in
      // the TransferHook object

      if (upload.getStatusCode()==upload.TRANSFERRING) {
        System.out.println(upload.getPercent() + "% "+upload.getRate()+" Kbps");
      }

      try {
        Thread.sleep(1000);
      }
      catch (InterruptedException ex) {
      }
    }

    // disconnect from the server
    fc.disconnect();

    // clean up
    fc.finish();
  }
}
import unlimited.fc.client.api.*;
import java.io.*;
import java.util.*;
import java.util.Observable;
import java.io.IOException;
import unlimited.fc.com.FCException;

/**
 * This example illustrates the use of Observables to monitor a TransferHook object.
 */

public class UploadSampleAdvanced implements Observer {

  TransferHook upload = null;

  public void go() throws IOException, FCException {

    FCClient fc = new FCClient("192.168.1.30", 2057);
    fc.setShowConsoleLog(true);
    fc.initialize();
    fc.connect();
    fc.login("anonymous", "me@email.com");

    // Let's auto detect the transfer mode.  Unless RTT is high enough, FTP gets used.
    fc.setMode(TransferMode.AUTO);

    // lets send at a constant 1500 Kbps, no congestion control.
    // the congestion control only comes into play if FC gets detected as the best transfer mode
    fc.setUseCongestionControl(false);
    fc.setTargetRate(1500);

    // verify the file afterwards
    fc.setVerifyIntegrity(true);
    upload = fc.upload(new File("c:/bigfiles/500MB"));
    upload.addObserver(this);

    try {
      synchronized (this) {
        wait();
      }
    }
    catch (InterruptedException ex) {
    }

    // disconnect from the server
    fc.disconnect();

    // clean up
    fc.finish();
  }

  public void update(Observable observable, Object object) {

    if (!upload.isTransferComplete() && !upload.isTransferCancelled() &&
        !upload.isTransferError()) {
      if (upload.getStatusCode() == upload.TRANSFERRING &&
          upload.getCurrentPercent() != 100) {
        printProgress(upload.getRate(), upload.getCurrentPercent());
      }
      else if (upload.getStatusCode() == upload.DONEFILE) {
        printProgress(upload.getRate(), 100);
      }
    }
    else {
      // all files complete
      synchronized (this) {
        notifyAll();
      }
    }
  }

  public void printProgress(int rate, int percent) {
    System.out.println(percent + "%");
    System.out.println(rate + " kbps");
  }

  public static void main(String args[]) throws Exception {
    new UploadSampleAdvanced().go();
  }
}

Server API

The Server API exposes every method needed to manage users and request session information on the FileCatalyst Server.

// Example below is sample code in which the application tries to create a user and
 // wraps up logic for reconnection attempts should the communication between the ServerAPI
 // and the Server be severed.

 // Call to setup initial connection to FileCatalyst Server
 public void init() throws Exception {
   FCServer fcserver = new FCServer();
   // connection parameters
   fcserver.setHostname("localhost");
   fcserver.setPort(12400);
   fcserver.setUserName("admin");
   fcserver.setPassword("system");
   // connect
   fcserver.connect();
 }

 // attempts a reconnection
 private void reconnect () throws Exception {
   try {
     fcserver.disconnect();
   } catch (Exception e) {
   }
   fcserver.connect();
 }

 //
 // Method to modify login credentials for a user.  If the user does not yet exist, create the
 // user as well.
 // @param fcUserName FTP Login name
 // @param fcPassword Password the user wants to have
 // @throws Exception If you cannot connect to the server after 3 attempts, or the server is not allowing you to
 //                   create/modify the user.
 //
 public void createOrModifyUserCredentials(String fcUserName, String fcPassword) throws Exception {
   // Get the FileCatalyst user.
   int MAXATTEMPTS = 3;
   UserContainer fcUser = null;
   int retryAttempts = 0;
   while (fcUser == null && retryAttempts < MAXATTEMPTS ) {
     // try to connect if we've lost the connection
     if (!fcserver.isConnected()) {
       reconnect();
     }
     try {
       fcUser = fcserver.getUser(fcUserName);
       if (fcUser == null) {
         // null return indicates user does not exist -- create
         fcserver.addUser(fcUserName, fcPassword);
         // test to see if the user is really there
         fcserver.resynchConfigurationFiles();
         fcUser = fcserver.getUser(fcUserName);
         if (fcUser == null) {
           throw new Exception("FileCatalyst user could not be created with user name '" + fcUserName + "'");
         }
         return;
       } else {
         fcserver.modUserPassword(fcUserName, fcPassword);
         return;
       }
     } catch (AdminConnectionException e) {
       // conection foobared.  Let's try again
       retryAttempts++;
     }
   }
   throw new Exception("Cannot connect to FCServer, reached max attempts");
}

Mobile APIs

Easily create fast file transfer apps for Apple iOS and Google Android. FileCatalyst provides a native Objective-C API for iOS and a Java API for Android Dalvik.

Built using the mobile API, our FileCatalyst app is now available for Android and iOS.

//
//  FCAViewController.m
//  example
//
//  Copyright (c) 2012 Unlimi-Tech Software Inc.. All rights reserved.
//
//  This sample code will upload and then download a file named
//  "nature-q-c-320-320-7.jpg" (bundled with the SDK)

#import "FCAViewController.h"
#import "NSString+FCAUtils.h"

@interface FCAViewController ()

@property (strong, nonatomic) FCAControl *control;

@end

@implementation FCAViewController
@synthesize connectionStatusLabel;
@synthesize connectionDetailLabel;
@synthesize transferStatusLabel;
@synthesize transferDetailLabel;
@synthesize cancelButton;
@synthesize downloadButton;
@synthesize uploadButton;
@synthesize connectButton;
@synthesize control;


- (void)reportError:(NSError*)error {
    if (!error) return;

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error"
                                                    message:error.localizedDescription
                                                   delegate:nil
                                          cancelButtonTitle:@"OK"
                                          otherButtonTitles:nil];
    [alert show];
}

// Basic file upload. The control instance has its own private work queue that all commands (except cancelTransfer) must
// be executed on. To do this, there are two helper methods, performBlock:completion: and performBlockAndWait:
// If any command inside the block fails, it will be reported in the NSError instance passed to the completion block,
// or returned from the performBlockAndWait: call.

- (IBAction)uploadAction:(id)sender {
    [self.uploadButton setTitle:@"Uploading..." forState:UIControlStateNormal];
    self.uploadButton.enabled = NO;

    [self.control performBlock:^{
        NSString *filename = @"nature-q-c-320-320-7.jpg";
        NSURL *fileURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"nature-q-c-320-320-7" ofType:@"jpg"]];

        [control uploadFile:fileURL toPath:filename transferStarted:^(FCAFileTransferStats *stats) {
            // this callback is invoked on the main queue
            self.transferStatusLabel.text = filename;
            self.cancelButton.hidden = NO;
            NSLog(@"transfer has started");
        } transferCompleted:^(FCAFileTransferStats *stats) {
            // this callback is invoked on the main queue
            NSLog(@"transfer has completed");
            self.transferStatusLabel.text = [NSString stringWithFormat:@"%@ finished", filename];
            self.cancelButton.hidden = YES;
        }];

    } completion:^(NSError *error) {
        [self reportError:error];
        [self.uploadButton setTitle:@"Test Upload" forState:UIControlStateNormal];
        self.uploadButton.enabled = YES;
    }];
}

- (IBAction)downloadAction:(UIButton *)sender {
    [self.downloadButton setTitle:@"Downloading..." forState:UIControlStateNormal];
    self.downloadButton.enabled = NO;

    [self.control performBlock:^{
        NSString *filename = @"nature-q-c-320-320-7.jpg";
        NSURL *documentsDirectory = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
                                                                            inDomains:NSUserDomainMask] lastObject];
        NSURL *fileURL = [documentsDirectory URLByAppendingPathComponent:filename];

        [control downloadFile:filename
                        toURL:fileURL
              transferStarted:^(FCAFileTransferStats *stats) {
                  self.transferStatusLabel.text = filename;
                  self.cancelButton.hidden = NO;

              } transferCompleted:^(FCAFileTransferStats *stats) {
                  self.transferStatusLabel.text = [NSString stringWithFormat:@"%@ finished", filename];
                  self.cancelButton.hidden = YES;
              }];
    } completion:^(NSError *error) {
        [self reportError:error];
        [self.downloadButton setTitle:@"Test Download" forState:UIControlStateNormal];
        self.downloadButton.enabled = YES;
    }];
}

// This method shows how to use the nonblocking connect/disconnect calls
- (IBAction)connectAction:(UIButton *)sender {
    if ([self.control isConnected]) {
        sender.enabled = NO;
        [sender setTitle:@"Disconnecting..." forState:UIControlStateNormal];

        [self.control performBlock:^{
            [self.control disconnect];
        } completion:^(NSError *error) {
            sender.enabled = YES;
            [self reportError:error];
        }];
    } else {
        sender.enabled = NO;
        [sender setTitle:@"Connecting..." forState:UIControlStateNormal];

        [self.control performBlock:^{
            [self.control connect];
        } completion:^(NSError *error) {
            sender.enabled = YES;
            [self reportError:error];
        }];
    }
}

- (IBAction)cancelAction:(UIButton *)sender {
    [self.control cancelTransfer];
}


- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // create an FCAControl instance and set the connection options
        self.control = [[FCAControl alloc] init];
        self.control.username = @"user";
        self.control.password = @"test";
        self.control.hostname = @"10.0.1.2";
        self.control.port = 8123;

        // some options that are not required to set
        control.useSSL = NO;
        control.autoResumeEnabled = NO;
        control.fileExistsOverride = YES;
    }
    return self;
}

- (void)configureControlStats {
    self.connectionDetailLabel.text = [NSString stringOfTransferRate:self.control.bitsPerSecondAverageTransferRate];
}

- (void)configureView {
    NSString *connectionStatus = nil;

    if ([self.control isConnected]) {
        [self.connectButton setTitle:@"Disconnect" forState:UIControlStateNormal];
        self.uploadButton.hidden = NO;
        self.downloadButton.hidden = NO;
        connectionStatus = @"connected";
    } else {
        [self.connectButton setTitle:@"Connect" forState:UIControlStateNormal];
        self.uploadButton.hidden = YES;
        self.downloadButton.hidden = YES;
        connectionStatus = @"not connected";
    }

    self.connectionStatusLabel.text = [NSString stringWithFormat:@"%@:%d (%@)",
                                       self.control.hostname, self.control.port, connectionStatus];
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    // there are notifications for the connect and disconnect events
    [[NSNotificationCenter defaultCenter] addObserverForName:FCAControlConnectedKey
                                                      object:self.control
                                                       queue:[NSOperationQueue mainQueue]
                                                  usingBlock:^(NSNotification *note) {
                                                      [self configureView];
                                                  }];

    [[NSNotificationCenter defaultCenter] addObserverForName:FCAControlDisconnectedKey
                                                      object:self.control
                                                       queue:[NSOperationQueue mainQueue]
                                                  usingBlock:^(NSNotification *note) {
                                                      [self configureView];
                                                  }];

    // during transfers, the Control instance will periodically send out a notification with updated
    // connection statistics
    [[NSNotificationCenter defaultCenter] addObserverForName:FCAControlUpdatedKey
                                                      object:self.control
                                                       queue:[NSOperationQueue mainQueue]
                                                  usingBlock:^(NSNotification *note) {
                                                      [self configureControlStats];
                                                  }];


    [self configureView];
}

- (void)viewDidUnload
{
    [self setConnectionStatusLabel:nil];
    [self setConnectionDetailLabel:nil];
    [self setTransferStatusLabel:nil];
    [self setTransferDetailLabel:nil];
    [self setCancelButton:nil];
    [self setDownloadButton:nil];
    [self setUploadButton:nil];
    [self setConnectButton:nil];
    [super viewDidUnload];
    // Release any retained subviews of the main view.
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
        return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
    } else {
        return YES;
    }
}

@end
  

For Dalvik code, please see the Client API sample.

Java Applets / JavaScript API

FileCatalyst applets are based on nearly a decade of experience in enabling browser-based file transfer. Web developers can easily embed the applet with a simple <script> tag, and configure it with a JavaScript file. Use the dynamic language of your choice (PHP, JavaScript, ASP) to configure the applets on-demand, or control the upload or download applet with our JavaScript API.

<script>
    var browsePath = "";

    function browseAndAdd() {
      browsePath = document.FileCatalyst.browseLive(true);
    }

    function upload() {
      document.FileCatalyst.uploadLive();
    }

    function clearQueue() {
      document.FileCatalyst.clearQueue();
    }
  </script>

<!--Uses onClick for demonstration only-->
<form id="uploadform">
  <!--Launch a browse dialog and add the selected file to the queue-->
  <input type=button onClick="javascript:browseAndAdd();" value="Browse and Add to Queue" />

  <!-- Force upload of whatever is currently found in the transfer queue -->
  <input type=button onClick="javascript:upload();" value="Upload">

  <!-- Clear transfer queue (can be called only if no transfers are in progress) -->
  <input type=button onClick="javascript:clearQueue();" value="Clear Queue">
</form>

REST API

A RESTful API for FileCatalyst Workflow exposes a number of management functions through the web. These include:

  • Add/Edit/Delete Users
  • Add/Edit/Delete Groups
  • Add/Edit/Delete Order forms
  • Add/Edit/Delete FTP Sites
  • List Job Fields

.NET Wrapper

The .NET wrapper offers transparent and thread-safe access to the FileCatalyst command-line in .NET. One potential application is to use FileCatalyst technology to develop within the Microsoft development framework. The .NET wrapper requires an official Java runtime and FileCatalyst CLI.

click to view sample screenshot

Command Line Interface

Using the CLI, access FileCatalyst functionality through virtually any scripting language, or from many other programming languages. Any tool able to output to the command line can be used to trigger FileCatalyst file transfers.

C++ Native Client Library

FileCatalyst products are built using Java as the main programming language. This has always allowed us to keep a centralized code base and be compatible across multiple platforms and browsers (via Java Applet Plugin). 95% of systems (desktop/laptop/servers) found on the market today, including Windows, MacOSX, Linux, Solaris, and AIX, can utilize our existing software.

However, there are certain systems where Java is not available. In many set top boxes and embedded systems (network appliance, gaming consoles), Java is not installed or available. This ecosystem was unable to take advantage of our solutions.

In light of this, we have developed a C++ client solution. Available as both a native C++ API or as a native command-line executable (.exe for Windows, 32 or 64-bit binary for Linux), our FileCatalyst C++ client will allow file transfer acceleration on systems that do not have Java installed.

#include 
#include 


int main( int argc, char *argv[] )
{
    int rc = 0;
    std::cout << "Transfer a file and then print out some statistics." << std::endl;

    try
    {
        // Setup the FTP connection:
        fc::Options options;
        options.setFtpServer( "192.168.1.80" );
        options.setUsernameAndPassword( "user", "test" );
        options.setBandwidth( 20000 );

        fc::Control ftp( options );
        ftp.connect();

        // Transfer a file via UDP
        std::cout << "Downloading a file..." << std::endl;
        ftp.downloadFile( "numbers.txt", "numbers.txt" );

        // Display some statistics
        const fc::TransferStats &stats = ftp.getTransferStats();

        std::cout    << "Timestamp (begin):                           " << stats.timeTransferBegan            << std::endl
                    << "Timestamp (finish):                          " << stats.timePreviousBlockFinished    << std::endl
                    << "Blocks remaining:                            " << stats.blocksRemaining                << std::endl
                    << "Blocks completed:                            " << stats.blocksCompleted                << std::endl
                    << "Bytes expected:                              " << stats.ulPayloadBytesExpected        << std::endl
                    << "Bytes received:                              " << stats.ulPayloadBytesReceived        << std::endl
                    << "Packets received from the FTP server:        " << stats.ulPacketsReceived            << std::endl
                    << "Packets sent to the FTP server:              " << stats.ulPacketsSent                << std::endl
                    << "Packets dropped due to duplicates received:  " << stats.ulDuplicatePacketDropped    << std::endl
                    << "Packets that had to be manually requested:   " << stats.ulRequestRetransmit            << std::endl;
    }
    catch( const fc::Exception &e )
    {
        e.display();
        rc = 1;
    }

    return rc;
}

We have currently ported the library to the following platforms:

  • Linux 32 bit
  • Linux 64-bit
  • Windows 32-bit
  • Windows 64-bit

If you require a port to a specific platform, contact us with the details.

Request Trial