Skip to content

Toro Cloud Dev Center


FTP server endpoint

The FTP server endpoint allows developers to setup an FTP server that hosts the available services in a Martini package as virtual directories:

1
2
3
4
5
6
7
.
└── {package-name}
    └── {class-name}
        ├── {service1}
        ├── {service2}
        ├── ...
        └── {serviceN}

Credentials used to authenticate to the FTP server are configurable with users and groups.

Check files and directories using an FTP client

You can navigate the complete directory structure of the started FTP server using FTP clients such as FileZilla.

Files uploaded in the service virtual directories trigger the corresponding service that contains it. After a file gets processed, the output (or error) is written to the same directory, using the same filename appended with -output (or -error). For example, a processed employees.csv will produce a new file called employees.csv-output. These files are stored temporarily on disk, and the underlying Java Virtual Machine is configured to delete on exit.

Files are deleted

Uploaded files are deleted after the service is invoked.

Properties

General configuration

Property Default Description
Name (required) The name of the endpoint.
Document Type FTP Server The document type to be registered to Tracker when this endpoint is triggered.
Auto Start true Whether or not to automatically run the endpoint upon package startup.
Log to Tracker false Flag determining whether executions should be logged to Tracker.

FTP server-specific configuration

Property Default Description
Port 1 A valid port between 1 and 65535 (inclusive).
Users (none) The users allowed to login to the FTP server.
Groups (none) The groups allowed to login to the FTP server.

Service

When the endpoint is triggered, the following variables are exposed to the configured service:

General parameters

Name Type Description
$trackerId java.lang.String The Tracker document internal ID. If the endpoint was configured to not track, this value will be null.
$tracker io.toro.martini.tracker.Tracker The Tracker object. If the endpoint was configured to not track, this value will be null.
martiniPackage MartiniPackage The Martini package that contains the endpoint.
parameters java.util.Map A map containing all the endpoint specific parameters.
properties java.util.Map A map containing containing all the properties associated with the endpoint.

FTP server-specific parameters

Name Type Description
file java.nio.file.Path The file whose change triggered the endpoint.
filename java.lang.String The absolute path of the file.
inputStream java.io.InputStream An open InputStream, pointing to the file. The stream is automatically closed after the service executes.
reader java.io.Reader An open Reader, pointing to the file. The reader is automatically closed after the service executes.
multipartFile org.springframework.web.multipart.MultipartFile A multipart file pointing to the file.
bytes byte[] Contains all file data. This variable is only created if your method has a parameter that matches the name (therefore scripts will never have this variable since they don't declare variables).
content java.lang.String Contains all file data. This variable is only created if your method has a parameter that matches the name (therefore scripts will never have this variable since they don't declare variables).

Example

Gloop as service

This example demonstrates the invocation of a Gloop when a file is uploaded to its virtually-hosted directory:

Service gets triggered when file is uploaded

Want more examples?

The distribution ships with a Martini package called examples, which contains services (including the above example) demonstrating more use cases.

Groovy script as service

Consider this Groovy script named VarDump.groovy, which simply prints the available variables in the context:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[
    'file',
    'filename',
    'inputStream',
    'reader',
    'multipartFile',
    'internalId' ].each {

    println "$it\t : " + this[it]
}

Setting up an FTP server on package named ftpServerDemo gives us the following directory structure:

1
2
3
4
5
6
7
.
└── packages
    └── ftpServerDemo
        └── java-VarDump
            ├── <ommitted>
            ├── ...
            └── public java.lang.Object io.toro.martini.invoker.GroovyScriptService.main(java.util.Map<java.lang.String, java.lang.Object>)

Wrapped scripts

Since Groovy scripts aren't really classes, Martini wraps these files into a GroovyScriptService using the method main as entry point.

When the endpoint is triggered - in this case, the file hello.txt being uploaded to /packages/ftpServerDemo/groovy-VarDump/...main(java.util.Map<java.lang.String, java.lang.Object>) (name shortened for brevity) - the console will show logs similar to the following:

1
2
3
4
5
6
file     : <long path>/hello.txt
filename     : <long path/hello.txt
inputStream  : java.io.FileInputStream@65241d4c
reader   : java.io.InputStreamReader@38299aa6
multipartFile    : io.toro.martini.core.util.ESBMockMultipartFile@30b7ae2b
internalId   : 1ea5dd9c-a584-473a-b3fb-addb50754511

This also produces a file in the same directory called hello.txt-output.

Groovy method as service

By using a Groovy class method as the service configured to the endpoint, we get access to additional variables content and bytes. Consider the following script:

1
2
3
4
5
6
class FileExample {

    public String logContents( File file, String content ) {
        return "Got '${file}', containing '${content}'"
    }
}

This loads the content of the file to the variable content. When served over FTP, this produces following directory structure:

1
2
3
4
5
6
7
.
└── packages
    └── ftpServerDemo
        └── java-FileExample
            ├── <ommitted>
            ├── ...
            └── public java.lang.String FileExamples.logContents(java.io.File,java.lang.String)

Uploading a file called map.txt to that directory invokes the #logContents method, and produces a file called map.txt-output. The content of this output file (possibly) will be:

1
Got 'map.txt', containing 'x marks the spot'

Use inputStream or file if reading large files

The use of content and bytes is suited only for cases where the expected size of the file is small. Otherwise, reading via the inputStream, or accessing the file directly is recommended.