Skip to content

File Integration Using Samba

Ballerina is an open-source programming language that empowers developers to integrate their system easily with the support of connectors. In this guide, we are mainly focusing on how to use the WSO2 SMB Connector to create a Samba listener service using Ballerina. You can find other integration modules from the wso2-ballerina GitHub repository.

The WSO2 SMB Connector enables you to connect to a Samba server and perform operations on files and folders stored on the server. These operations include basic file operations such as reading, updating, and deleting files, and listening to the server to invoke operations when a file is created or deleted.

What you'll Build

To understand how to build a service to listen to a Samba server, let's consider the use case of a data center that uses a Samba server to store data files. When a new file is added to the server, the Samba listener will read the file and add the file name and size to a map, and when the file is deleted from the server, it will remove the entry from the map.

File integration using Samba

Before you begin

  • Download Ballerina Integrator for your operating system
  • Install Oracle JDK 1.8.*
  • Install a Text Editor or an IDE

    Tip: For a better development experience, use VS Code (which is the recommended editor for Ballerina Integrator) and install the Ballerina Integrator Extension.

  • A Samba Server (See here on how to setup a Samba server)

Get the code

Pull the module from Ballerina Central using the following command.

ballerina pull wso2/file_integration_using_smb

Alternately, you can download the ZIP file and extract the contents to get the code.

Download ZIP

Implementation

If you want to skip the basics, you can download the GitHub repo and directly move to the "Testing" section by skipping the "Implementation" section.

Create the project structure

Ballerina is a complete programming language that supports custom project structures. Use the following package structure for this guide.

file-integration-using-smb
    └── src
       └── file_integration_using_smb
           └── smb_listener.bal

Create the Ballerina project file-integration-using-smb and add the file_integration_using_smb module using the below commands.

$ ballerina new file-integration-using-smb
$ cd file-integration-using-smb
$ ballerina add file_integration_using_smb

The above package structure will be created for you. Create the smb_listener.bal file inside the Ballerina module.

Developing the Samba listener service

Let's start implementation by importing the WSO2 SMB Connector in the smb_listener.bal file which you just created. This will pull the SMB Connector from Ballerina Central.

import wso2/smb;

Next, let's create a Samba Listener instance by defining the configuration in the Ballerina.conf file. The SMB_HOST is the IP address of the Samba server, while the SMB_USERNAME and SMB_PASSWORD are credentials of a user that has permission to access the Samba server. The SMB_HOST is the port used to connect with the server, of which the default value is 21.

Then you can add the configurations for the type of files the listener should listen for. For instance, if listener should be invoked for text files, the config for SMB_FILE_NAME_PATTERN should be set as (.*).txt. Next, add the directory or location in Samba share to poll for files and how frequently the listener should poll for files, using the values SMB_LISTENER_PATH and SMB_POLLING_INTERVALrespectively.

listener smb:Listener dataFileListener = new({
    protocol: smb:SMB,
    host: config:getAsString("SMB_HOST"),
    port: config:getAsInt("SMB_LISTENER_PORT"),
    secureSocket: {
        basicAuth: {
            username: config:getAsString("SMB_USERNAME"),
            password: config:getAsString("SMB_PASSWORD")
        }
    },
    path: config:getAsString("SMB_LISTENER_PATH"),
    fileNamePattern: config:getAsString("SMB_FILE_NAME_PATTERN"),
    pollingInterval: config:getAsInt("SMB_POLLING_INTERVAL")
});

Create the service to listen to the Samba server using the above listener. When files are added or deleted on the server, this service will be invoked, and the files will be processed.

service dataFileService on dataFileListener {
    resource function processDataFile(smb:WatchEvent fileEvent) {

        foreach smb:FileInfo file in fileEvent.addedFiles {
            log:printInfo("Added file path: " + file.path);
            processNewFile(file.path);
        }
        foreach string file in fileEvent.deletedFiles {
            log:printInfo("Deleted file path: " + file);
            processDeletedFile(file);
        }
    }
}

Then implement the Samba Client, which will connect to the Samba server and get the details of new files to process.

smb:ClientEndpointConfig smbConfig = {
    protocol: smb:SMB,
    host: config:getAsString("SMB_HOST"),
    port: config:getAsInt("SMB_LISTENER_PORT"),
    secureSocket: {
     basicAuth: {
         username: config:getAsString("SMB_USERNAME"),
         password: config:getAsString("SMB_PASSWORD")
     }
    }
};

// Create Samba Client
smb:Client smbClient = new(smbConfig);

Declare a map to store the details of processed files.

map<int> fileMap = {};

Now, implement the processing of added and deleted files. When files are added to the server, the Samba client will retrieve the file size from the server, and the file name and its size will be added to the fileMap. When a file is removed from the server, the file will be removed from the map.

// Process newly added files to the server, by adding them to the map
function processNewFile(string filePath) {
    int|error fileSize = smbClient -> size(filePath);
    if(fileSize is int){
        fileMap[filePath] = fileSize;
        log:printInfo("Added file: " + filePath + " - " + fileSize.toString());
    } else {
        log:printError("Error in getting file size", fileSize);
    }
}

// Process deleted files from server, by removing them from the map
function processDeletedFile(string filePath) {
    if(fileMap.hasKey(filePath)){
        int removedElement = fileMap.remove(filePath);
        log:printInfo("Deleted file: " + filePath);
    }
}

Testing

Invoking the service

To begin with invoking the service, start the Samba server.

Navigate to file-integration-using-smb directory and run the following command to build the listener service in smb_listener.bal.

$ ballerina build file_integration_using_smb

The successful build of a service will show us something similar to the following output.

Compiling source
        wso2/file_integration_using_smb:0.1.0

Creating balos
        target/balo/file_integration_using_smb-2019r3-java8-0.1.0.balo

This will create the Ballerina executables inside the /target directory.

Then run the jar file created in the above step.

$ java -jar target/bin/file_integration_using_smb.jar --b7a.config.file=src/file_integration_using_smb/resources/ballerina.conf

Add and delete files in the Samba server, and check the logs to verify whether the service is working as expected.

Top