Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions ballerina/Ballerina.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
org = "ballerina"
name = "ftp"
version = "2.15.1"
version = "2.16.0"
authors = ["Ballerina"]
keywords = ["FTP", "SFTP", "remote file", "file transfer", "client", "service"]
repository = "https://github.com/ballerina-platform/module-ballerina-ftp"
Expand Down Expand Up @@ -45,8 +45,8 @@ path = "./lib/commons-lang3-3.18.0.jar"
[[platform.java21.dependency]]
groupId = "io.ballerina.stdlib"
artifactId = "ftp-native"
version = "2.15.1"
path = "../native/build/libs/ftp-native-2.15.1.jar"
version = "2.16.0"
path = "../native/build/libs/ftp-native-2.16.0-SNAPSHOT.jar"

[[platform.java21.dependency]]
groupId = "io.ballerina.lib"
Expand Down
2 changes: 1 addition & 1 deletion ballerina/CompilerPlugin.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ id = "ftp-compiler-plugin"
class = "io.ballerina.stdlib.ftp.plugin.FtpCompilerPlugin"

[[dependency]]
path = "../compiler-plugin/build/libs/ftp-compiler-plugin-2.15.1.jar"
path = "../compiler-plugin/build/libs/ftp-compiler-plugin-2.16.0-SNAPSHOT.jar"
18 changes: 15 additions & 3 deletions ballerina/Dependencies.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,21 @@
dependencies-toml-version = "2"
distribution-version = "2201.12.0"

[[package]]
org = "ballerina"
name = "data.csv"
version = "0.8.1"
dependencies = [
{org = "ballerina", name = "jballerina.java"}
]
modules = [
{org = "ballerina", packageName = "data.csv", moduleName = "data.csv"}
]

[[package]]
org = "ballerina"
name = "data.jsondata"
version = "1.1.2"
version = "1.1.3"
dependencies = [
{org = "ballerina", name = "jballerina.java"},
{org = "ballerina", name = "lang.object"}
Expand All @@ -34,8 +45,9 @@ modules = [
[[package]]
org = "ballerina"
name = "ftp"
version = "2.15.1"
version = "2.16.0"
dependencies = [
{org = "ballerina", name = "data.csv"},
{org = "ballerina", name = "data.jsondata"},
{org = "ballerina", name = "data.xmldata"},
{org = "ballerina", name = "io"},
Expand Down Expand Up @@ -163,7 +175,7 @@ modules = [
[[package]]
org = "ballerina"
name = "observe"
version = "1.5.0"
version = "1.5.1"
dependencies = [
{org = "ballerina", name = "jballerina.java"}
]
Expand Down
93 changes: 73 additions & 20 deletions ballerina/client_endpoint.bal
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@
// specific language governing permissions and limitations
// under the License.

import ballerina/io;
import ballerina/jballerina.java;
import ballerina/data.csv as _;
import ballerina/data.jsondata as _;
import ballerina/data.xmldata;
import ballerina/io;
import ballerina/jballerina.java;

# Represents an FTP client that intracts with an FTP server
# Represents an FTP client that interacts with an FTP server
public isolated client class Client {
private final readonly & ClientConfiguration config;

Expand All @@ -36,12 +37,11 @@ public isolated client class Client {
}

# Retrieves the file content from a remote resource.
# Deprecated: Use `getText`, `getJson`, `getXml`, `getCsv`, `getBytes`, or the streaming variants `getBytesAsStream`/`getCsvAsStream` instead.
# ```ballerina
# stream<byte[] & readonly, io:Error?>|ftp:Error channel = client->get(path);
# ```
#
# Deprecated: Use `getText` or `getJson` instead for retrieving file content.
#
# + path - The resource path
# + return - A byte stream from which the file can be read or `ftp:Error` in case of errors
@deprecated
Expand All @@ -59,7 +59,7 @@ public isolated client class Client {
# ```ballerina
# byte[] content = check client->getBytes(path);
# ```
#
#
# + path - The resource path
# + return - content as a byte array or `ftp:Error` in case of errors
remote isolated function getBytes(string path) returns byte[]|Error {
Expand All @@ -86,7 +86,7 @@ public isolated client class Client {
# + targetType - The target type of the json content
# (e.g., `json`, `record {}`, or a user-defined record type)
# + return - content as a json or `ftp:Error` in case of errors
remote isolated function getJson(string path, typedesc<json|record{}> targetType = <>) returns targetType|Error = @java:Method {
remote isolated function getJson(string path, typedesc<json|record {}> targetType = <>) returns targetType|Error = @java:Method {
name: "getJson",
'class: "io.ballerina.stdlib.ftp.client.FtpClient"
} external;
Expand All @@ -100,7 +100,7 @@ public isolated client class Client {
# + targetType - The target type of the xml content
# (e.g., `xml`, `record {}`, or a user-defined record type)
# + return - content as a xml or `ftp:Error` in case of errors
remote isolated function getXml(string path, typedesc<xml|record{}> targetType = <>) returns targetType|Error = @java:Method {
remote isolated function getXml(string path, typedesc<xml|record {}> targetType = <>) returns targetType|Error = @java:Method {
name: "getXml",
'class: "io.ballerina.stdlib.ftp.client.FtpClient"
} external;
Expand All @@ -110,12 +110,12 @@ public isolated client class Client {
# ```ballerina
# string[][] content = check client->getCsv(path);
# ```
#
#
# + path - The path to the file on the FTP server
# + targetType - The target type of the CSV content
# (e.g., `string[][]`, `record {}[]`, or an array of user-defined record type)
# + return - content as a string[][] or `ftp:Error` in case of errors
remote isolated function getCsv(string path, typedesc<string[][]|record{}[]> targetType = <>) returns targetType|Error = @java:Method {
remote isolated function getCsv(string path, typedesc<string[][]|record {}[]> targetType = <>) returns targetType|Error = @java:Method {
name: "getCsv",
'class: "io.ballerina.stdlib.ftp.client.FtpClient"
} external;
Expand All @@ -132,16 +132,29 @@ public isolated client class Client {
'class: "io.ballerina.stdlib.ftp.client.FtpClient"
} external;

# Retrieves the file content as a CSV stream from a remote resource.
# ```ballerina
# stream<string[], error?> response = check client->getCsvAsStream(path);
# ```
#
# + path - The path to the file on the FTP server
# + targetType - The target element type of the stream (e.g., `string[]` or `record {}`)
# + return - A stream from which the file can be read or `ftp:Error` in case of errors
remote isolated function getCsvAsStream(string path, typedesc<string[]|record {}> targetType = <>) returns stream<targetType, error?>|Error = @java:Method {
name: "getCsvAsStream",
'class: "io.ballerina.stdlib.ftp.client.FtpClient"
} external;

# Appends the content to an existing file in an FTP server.
# ```ballerina
# ftp:Error? response = client->append(path, channel);
# ```
# Deprecated: Use `putText`, `putJson`, `putXml`, `putCsv`, `putBytes` or `putCsvFromStream`
#
# + path - The resource path
# + content - Content to be written to the file in server
# + return - `()` or else an `ftp:Error` if failed to establish
# the communication with the FTP server
# Deprecated: Use `putText`, `putJson`, `putXml`, `putCsv`, `putBytes` or `putCsvAsStream` with option `APPEND`.
@deprecated
remote isolated function append(string path, stream<byte[] & readonly, io:Error?>|string|xml|json content)
returns Error? {
Expand All @@ -152,7 +165,6 @@ public isolated client class Client {
# ```ballerina
# ftp:Error? response = client->put(path, channel);
# ```
# Deprecated: Use `putText`, `putJson`, `putXml`, `putCsv`, `putBytes` or `putCsvFromStream`
#
# + path - The resource path
# + content - Content to be written to the file in server
Expand All @@ -161,6 +173,7 @@ public isolated client class Client {
# uploading
# + return - `()` or else an `ftp:Error` if failed to establish
# the communication with the FTP server
# Deprecated: Use `putText`, `putJson`, `putXml`, `putCsv`, `putBytes` or `putCsvAsStream`.
@deprecated
remote isolated function put(string path, stream<byte[] & readonly, io:Error?>
|string|xml|json content, Compression compressionType = NONE) returns Error? {
Expand All @@ -175,7 +188,7 @@ public isolated client class Client {
# ```ballerina
# ftp:Error? response = client->putBytes(path, content, option);
# ```
#
#
# + path - The resource path
# + content - Content to be written to the file in server
# + option - To indicate whether to overwrite or append the given content
Expand All @@ -189,7 +202,7 @@ public isolated client class Client {
# ```ballerina
# ftp:Error? response = client->putText(path, content, option);
# ```
#
#
# + path - The resource path
# + content - Content to be written to the file in server
# + option - To indicate whether to overwrite or append the given content
Expand All @@ -203,33 +216,73 @@ public isolated client class Client {
# ```ballerina
# ftp:Error? response = client->putJson(path, content, option);
# ```
#
#
# + path - The resource path
# + content - Content to be written to the file in server
# + option - To indicate whether to overwrite or append the given content
# + return - `()` or else an `ftp:Error` if failed to write
remote isolated function putJson(string path, json|record{} content, FileWriteOption option = OVERWRITE) returns Error? {
string jsonVal = content is json ? content.toJsonString() : content.toJsonString();
return putJson(self, path, jsonVal, option);
remote isolated function putJson(string path, json|record {} content, FileWriteOption option = OVERWRITE) returns Error? {
return putJson(self, path, content.toJsonString(), option);
}

# Adds a file to an FTP server with the specified write option.
# ```ballerina
# ftp:Error? response = client->putXml(path, content, option);
# ```
#
#
# + path - The resource path
# + content - Content to be written to the file in server
# + option - To indicate whether to overwrite or append the given content
# + return - `()` or else an `ftp:Error` if failed to write
remote isolated function putXml(string path, xml|record{} content, FileWriteOption option = OVERWRITE) returns Error? {
remote isolated function putXml(string path, xml|record {} content, FileWriteOption option = OVERWRITE) returns Error? {
xml|error xmldata = content is xml ? content : xmldata:toXml(content);
if xmldata is error {
return error Error("Failed to convert record to XML: " + xmldata.message());
}
return putXml(self, path, xmldata, option);
}

# Adds a CSV file to an FTP server with the specified write option.
# ```ballerina
# ftp:Error? response = client->putCsv(path, content, option);
# ```
#
# + path - The resource path
# + content - Content to be written to the file in server
# + option - To indicate whether to overwrite or append the given content
# + return - `()` or else an `ftp:Error` if failed to write
remote isolated function putCsv(string path, string[][]|record {}[] content, FileWriteOption option = OVERWRITE) returns Error? {
return putCsv(self, path, content, option);
}

# Adds a byte[] stream as a file to an FTP server with the specified write option.
# ```ballerina
# ftp:Error? response = client->putBytesAsStream(path, content, option);
# ```
#
# + path - The resource path
# + content - Content to be written to the file in server
# + option - To indicate whether to overwrite or append the given content
# + return - `()` or else an `ftp:Error` if failed to write
remote isolated function putBytesAsStream(string path, stream<byte[], error?> content, FileWriteOption option = OVERWRITE) returns Error? = @java:Method {
name: "putBytesAsStream",
'class: "io.ballerina.stdlib.ftp.client.FtpClient"
} external;

# Adds a CSV file from string[][] or record{}[] elements as a file to an FTP server with the specified write option.
# ```ballerina
# ftp:Error? response = client->putCsvAsStream(path, content, option);
# ```
#
# + path - The resource path
# + content - Content to be written to the file in server
# + option - To indicate whether to overwrite or append the given content
# + return - `()` or else an `ftp:Error` if failed to write
remote isolated function putCsvAsStream(string path, stream<string[]|record {}, error?> content, FileWriteOption option = OVERWRITE) returns Error? = @java:Method {
name: "putCsvAsStream",
'class: "io.ballerina.stdlib.ftp.client.FtpClient"
} external;

# Creates a new directory in an FTP server.
# ```ballerina
# ftp:Error? response = client->mkdir(path);
Expand Down
69 changes: 69 additions & 0 deletions ballerina/content_csv_record_stream.bal
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright (c) 2025 WSO2 LLC. (http://www.wso2.com) All Rights Reserved.
//
// WSO2 LLC. licenses this file to you under the Apache License,
// Version 2.0 (the "License"); you may not use this file except
// in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

import ballerina/jballerina.java;

# Represents the type of the record which returned from the contentByteStream.next() call.
#
# + value - The record
public type ContentCsvRecordStreamEntry record {|
record {} value;
|};

# `ContentCsvRecordStream` used to initialize a stream of type string[] for content callbacks.
public class ContentCsvRecordStream {

private boolean isClosed = false;
private Error? err;

public isolated function init(Error? err = ()) {
self.err = err;
}

# Reads and return the next CSV record as `record{}`.
#
# + return - A record containing a `record{}` value when the stream is available,
# `()` if the stream has reached the end or else an `error`
public isolated function next() returns record {|record {} value;|}|error? {
return externGetContentCsvRecordStreamEntry(self);
}

# Closes the stream. The primary usage of this function is to close the stream without reaching the end.
# If the stream reaches the end, the `contentByteStream.next` will automatically close the stream.
#
# + return - Returns `()` when the closing was successful or an `error`
public isolated function close() returns error? {
if !self.isClosed {
var closeResult = externCloseContentCsvRecordStream(self);
if closeResult is () {
self.isClosed = true;
}
return closeResult;
}
return ();
}
}

isolated function externGetContentCsvRecordStreamEntry(ContentCsvRecordStream iterator)
returns record {|record {} value;|}|error? = @java:Method {
'class: "io.ballerina.stdlib.ftp.ContentCsvStreamIteratorUtils",
name: "next"
} external;

isolated function externCloseContentCsvRecordStream(ContentCsvRecordStream iterator) returns error? = @java:Method {
'class: "io.ballerina.stdlib.ftp.ContentCsvStreamIteratorUtils",
name: "close"
} external;
Loading
Loading