Enhancing FTP2SF with Custom Callbacks in Salesforce

Introducing custom functionality into your AppExchange package.

  • FTP2SF
  • 5 OCT 2023
  • blog

FTP2SF

FTP2SF is a powerful Salesforce framework for handling File based integrations operations seamlessly including:

  • FTP
  • SFTP
  • FTPS
  • AWS S3
  • Azure Blob
  • DropBox
  • MS Graph (OneDrive & Sharepoint Online)

One of its standout features is the ability to customise and extend functionality through the use of callbacks. In this article, we'll delve into the structure of these callbacks and explore how they can benefit users of FTP2SF and Salesforce developers looking to implement callbacks in their own projects.

You can download FTP2SF from the AppExchange here feel free to try it out and let us know what you think!


Understanding the Callback Structure

The FTP2SF callback structure is designed to make file based integration operations highly adaptable to specific requirements. It revolves around the concept of callback interfaces. These interfaces define a set of methods that are invoked at critical points during an operation, allowing developers to insert custom logic and behaviour.

First lets cover off the functions that FTP2SF supports, this will help show how these callbacks support extending this functionality empowering developers to add their own functionality and features to our AppExchange product.

Here's the list of supported functions provided:

  • FTP2SF.FTP.find
    Lists files and directories on the destination service.
  • FTP2SF.FTP.get
    Retrieves the contents of the file (as a Blob) from the destination service.
  • FTP2SF.FTP.put
    Saves the BLOB content to the file on the destination service.
  • FTP2SF.FTP.ren
    Renames a file or directory on the destination service.
  • FTP2SF.FTP.del
    Deletes a file on the destination service.
  • FTP2SF.FTP.exists
    Checks the existence of a file or directory on the destination service.
  • FTP2SF.FTP.mkdir
    Creates a directory on the destination service (if directory creation is supported).
  • FTP2SF.FTP.rmdir
    Removes a directory on the destination service (if directory removal is supported).
  • FTP2SF.FTP.append
    Appends content to an existing file on the destination service.
  • FTP2SF.FTP.trn
    Transfers the file (service to service) without receiving the file on Salesforce.
  • FTP2SF.FTP.rtr
    Retrieves the contents of the file from the destination service, breaking the file into chunks of data and calling the identified callback function.
  • FTP2SF.FTP.ping
    Attempts a connection to the destination service with a specified timeout.
As you can see from the above list we support a specific set of functionality that is available across the entire set of services making it easy for developers to code irrespective of the service type.

So now how does this work with the callbacks? Here's an overview of the callback interfaces provided by FTP2SF:

  • iFind
    Callbacks for finding files on a service.
  • iGet
    Callbacks for retrieving files from a service.
  • iPut
    Callbacks for uploading files to a service.
  • iRen
    Callbacks for renaming files or directories on a service.
  • iDel
    Callbacks for deleting files or directories on a service.
  • iExists
    Callbacks for checking the existence of a file or directory on a service.
  • iMkdir
    Callbacks for creating directories on a service.
  • iRmdir
    Callbacks for removing directories from a service.
  • iAppend
    Callbacks for appending content to an existing file on a service.
  • iTrn
    Callbacks for transferring files between FTP servers.
  • iRetrieve
    Callbacks for receiving data, possibly in chunks, from a service.
  • iPing
    Callbacks for checking the availability of a service with a specified timeout.


Walk through of the callbacks in action.

Let's take a practical look at how these callbacks work with the find function, with the understanding that other callbacks follow a similar approach. The find function is used to search for files on a service and utilizes the iFind callback interface for customization. Here's a step-by-step explanation:

  • Step 1: Calling the find Function
    To initiate a file search, you call the FTP2SF.FTP.find() function. This function internally uses the classListingOf('%iFind%') method to identify classes that implement the iFind interface. These classes represent callbacks associated with the find operation.
  • Step 2: onStart Method Execution (Before Search)
    The find function iterates over the list of classes that implement the iFind interface obtained in Step 1. These callback instances represent various customisation points for the file search operation. For each iFind callback instance in the list, the onStart method is invoked.
    The onStart method allows for custom logic to be executed before the file search begins. It takes parameters siteName (service name), userName and searchPath matching the find criteria of the find function.
    You can implement custom validation, set up additional search criteria, or perform any other actions needed before the search.
  • Step 3: Executing the File Search
    After executing the onStart methods of all relevant callbacks, the find function constructs a search query and sends it to the destination service.
    The destination service processes the search query and returns a list of matching files within the custom class FTP2SF.FTP.Find, this wraps a list of the custom class FTP2SF.FTP.File within the items property.
  • Step 4: onFinish Method Execution (After Search)
    Once search results are received, the find function iterates over the list of iFind callback instances again, this time it executes the onFinish method of each callback. Parameters are similar to the above and include siteName (service name), userName and searchPath, but now also include the result (instance of FTP2SF.FTP.Find) from Step 3.
    The onFinish method allows for custom processing of the search results. You can parse and filter the results, log them, or perform any post-search actions as needed.
  • Step 5: Returning Search Results
    The find function compiles the final search results, which may have been modified or filtered by the onFinish methods of the callbacks. These results are returned to the calling code, which can then utilise them for further processing or display.

  • How does it work?

    As you can see from the above walk through, executing the callback from within the packaged functionality is extremely easy, you have a list of classes that support the iFind interface - your code within the onStart and onFinish is executed as part of the execution chain for each of these.

    The heavy lifting is provided by classListingOf('%iFind%') function, so what does this do? The code block is below and again this is amazingly simple to implement, we use a Search.query to select all ApexClass that contain the string identified, we ignore anything that is contained within the managed package before returning the list of ApexClass.

    
       private static List classListingOf(string findStr) {
            List result = new List();
            String query =  'FIND {'+ findStr + '}  RETURNING ApexClass (id, Name, Body, NamespacePrefix) LIMIT 2000';
            List> searchList = Search.query(query);
            if(searchList[0].size() > 0) {
                for(ApexClass infClass : (List)searchList[0]){
                if(infClass.NamespacePrefix != 'FTP2SF'){                                           
                        result.add(infClass);
                    }
                }
            }
            return result;
       }
                               

    Then each implementation of the callback functions utilises identical looking code to return the correctly instantiated classes, as per below, we wrap this in an exception handler so that anything that just includes the text but not the actual implementation is ignored.

    
        public static List find() {
            List result = new List();
            for(ApexClass rc : classListingOf('%iFind%')) {
                try
                {
                    result.add((iFind)Type.forName('', rc.Name).newInstance());
                }
                catch(System.TypeException ex)
                {
                    system.debug(ex.getTypeName());
                    throw ex;
                }
            }
            return result;
        }
                               
    What gets returned from this function is a list of instantiated classes each one that implements the required interface, and that's all you need to introduce a custom callback.

    The actual implementation of the call back itself depends on what logic you want to introduce, we give you the ability to interact with the AppExchange package functionality - how you use it is up to you!


    Use Cases and Benefits

    Let's explore some practical use cases and how the callback structure benefits FTP2SF users and Salesforce developers:

    • 1. Custom Validation
      Imagine you want to enforce specific naming conventions for files uploaded to your service. By implementing the iPut callback, you can perform validation checks on the file name and content before allowing the upload to proceed. This ensures data integrity and consistency.
    • 2. Logging and Auditing
      Callbacks can be used to log FTP2SF operations for auditing purposes. By adding logging logic in the onStart and onFinish methods of relevant callbacks, you can maintain a comprehensive audit trail of all activities.
    • 3. Error Handling
      Handling errors gracefully is crucial in any application. With callbacks, you can define error-handling mechanisms that suit your organization's needs. For example, in the iExists callback, you can specify how to handle cases where a file does not exist on the service.
    • 4. Security Enhancements
      Callbacks can be used to implement security measures such as encryption and access control. For instance, in the iGet callback, you can decrypt files before sending them to the requesting party, ensuring data confidentiality.
    • 5. Real-time Responses
      The iRetrieve callback allows you to receive data from a service in real-time, making it suitable for streaming large files or monitoring ongoing transfers.


    Implementing Callbacks in Salesforce

    If you're a Salesforce developer looking to implement callback functionality in your projects, consider adopting a similar approach to FTP2SF. Define callback interfaces that encapsulate specific actions or behaviours you want to customize, and then implement these interfaces in your code.

    The FTP2SF callback structure empowers users to tailor file based integration operations to their exact requirements, making it a valuable asset for Salesforce developers seeking customisation and extensibility. Whether it's adding custom validation, enhancing security, or improving error handling, callbacks provide a versatile and powerful toolset.

    By leveraging this structure and introducing callbacks in your own code, you can create more flexible and extensible solutions that cater to your unique business needs elevating your Salesforce applications to the next level, just like FTP2SF does for file based integration operations in Salesforce.

    As always thanks for reading and reach out if you need any help, always happy to hear how people use FTP2SF.