diff --git a/CHANGELOG.md b/CHANGELOG.md index db63a19..3cc69fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # CHANGELOG +## 1.5.0 - 2025-06-18 + +* Supports HTTP and SOCKS5 proxy +* Add example code `s3stream` for scanning an S3 object as an implementation of `AMaasReader` + ## 1.4.5 - 2025-03-03 * Support new region me-central-1 diff --git a/README.md b/README.md index 42f2b1d..85093e2 100644 --- a/README.md +++ b/README.md @@ -59,13 +59,17 @@ public static void main(String[] args) { try { // 1. Create an AMaaS Client object and configure it to carry out the scans in Vision One "us-east-1" region. AMaasClient client = new AMaasClient("us-east-1", "your-api-key"); - - // 2. Call ScanFile() to scan the content of a file. - String scanResult = client.scanFile("path-of-file-to-scan"); - - if (scanResult != null) { - // 3. Print out the JSON response from ScanFile() - System.out.println("scan result " + scanResult); + try { + // 2. Call ScanFile() to scan the content of a file. + String scanResult = client.scanFile("path-of-file-to-scan"); + + if (scanResult != null) { + // 3. Print out the JSON response from ScanFile() + System.out.println("scan result " + scanResult); + } + } finally { + // 4. Always close the client to release resources + client.close(); } } catch (AMaasException err) { info("Exception {0}", err.getMessage()); @@ -218,6 +222,26 @@ Scan a file for malware, add a list of tags to the scan result and retrieves res **_Return_** String the scanned result in JSON format. +#### ```public String scanRun(final AMaasReader reader, final String[] tagList, final boolean pml, final boolean feedback, final boolean verbose, final boolean digest) throws AMaasException``` + +Scan an AMaasReader for malware and retrieves response data from the API. This is the core scanning method that provides the most flexibility by accepting an AMaasReader interface, allowing for different types of data sources. + +**_Parameters_** + +| Parameter | Description | +| ------------- | ---------------------------------------------------------------------------------------- | +| reader | `AMaasReader` to be scanned. This can be an `AMaasFileReader` or any custom implementation you develop to support your specific data sources. | +| tagList | A list of strings to be used to tag the scan result. At most 8 tags with the maximum length of 63 characters. | +| pml | A flag to indicate whether to use predictive machine learning detection. | +| feedback | A flag to indicate whether to use Trend Micro Smart Protection Network's Smart Feedback. | +| verbose | A flag to enable log verbose mode. | +| digest | A flag to enable calculation of digests for cache search and result lookup. | + +**_Return_** +String the scanned result in JSON format. + +**_Note_**: For an example of implementing a custom AMaasReader, please refer to the `examples/s3stream/S3Stream.java` code which demonstrates a streaming implementation of the AMaasReader interface. + #### ```public String scanBuffer(final byte[] buffer, final String identifier) throws AMaasException``` Scan a buffer for malware and retrieves response data from the API. @@ -360,3 +384,72 @@ The File Security SDK consistently adopts TLS as the default communication chann For customers who need to enable TLS channel encryption without verifying the provided CA certificate, the `TM_AM_DISABLE_CERT_VERIFY` environment variable can be set. However, this option is only recommended for use in testing environments. When `TM_AM_DISABLE_CERT_VERIFY` is set to `1`, certificate verification is disabled. By default, the certificate will be verified. + +## Proxy Configuration + +The File Security Java SDK supports HTTP and SOCKS5 proxy configurations through environment variables. This allows the SDK to work in enterprise environments that require proxy servers for internet access. + +### Supported Environment Variables + +| Environment Variable | Required/Optional | Description | +| -------------------- | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `HTTP_PROXY` | Optional | HTTP proxy URL for HTTP connections (e.g., `http://proxy.example.com:8080`) | +| `HTTPS_PROXY` | Optional | Proxy URL for HTTPS connections (e.g., `https://proxy.example.com:8443` or `socks5://socks.example.com:1080`) | +| `NO_PROXY` | Optional | Comma-separated list of host names to bypass proxy (e.g., `localhost,127.0.0.1,*.local`). Use `*` to bypass proxy for all hosts | +| `PROXY_USER` | Optional | Username for proxy authentication (used with `Proxy-Authorization` header) | +| `PROXY_PASS` | Optional | Password for proxy authentication (used only when `PROXY_USER` is configured) | + +### Proxy Configuration Examples + +#### Basic HTTP Proxy +```bash +export HTTP_PROXY=http://proxy.company.com:8080 +export HTTPS_PROXY=http://proxy.company.com:8080 +``` + +#### SOCKS5 Proxy +```bash +export HTTPS_PROXY=socks5://socks-proxy.company.com:1080 +``` + +**Important:** When using SOCKS5 proxy, ensure you call `client.close()` to properly release network resources. The SDK creates background threads for SOCKS5 connections that must be explicitly closed. + +```java +AMaasClient client = new AMaasClient("us-east-1", "your-api-key"); +try { + // Perform scanning operations + String result = client.scanFile("file.txt"); +} finally { + // Always close the client when using SOCKS5 proxy + client.close(); +} +``` + +#### Proxy with Authentication +```bash +export HTTP_PROXY=http://proxy.company.com:8080 +export HTTPS_PROXY=https://secure-proxy.company.com:8443 +export PROXY_USER=username +export PROXY_PASS=password +``` + +#### Bypassing Proxy for Specific Hosts +```bash +export HTTP_PROXY=http://proxy.company.com:8080 +export NO_PROXY=localhost,127.0.0.1,*.internal.company.com +``` + +#### Disabling Proxy for All Connections +```bash +export NO_PROXY=* +``` + +### Notes + +- The SDK automatically detects and uses proxy settings from environment variables +- For HTTPS connections, `HTTPS_PROXY` takes precedence over `HTTP_PROXY` +- SOCKS5 proxies are supported by specifying `socks5://` in the proxy URL +- Proxy authentication requires both `PROXY_USER` and `PROXY_PASS` to be set +- The `NO_PROXY` variable supports wildcards (e.g., `*.local`) and exact matches +- No code changes are required - simply set the appropriate environment variables before running your application +- **Resource Management:** Always call `client.close()` when finished, especially when using SOCKS5 proxies, to ensure proper cleanup of network resources and prevent applications from hanging diff --git a/VERSION b/VERSION index e516bb9..bc80560 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.4.5 +1.5.0 diff --git a/examples/README.md b/examples/README.md index fbaf607..01ab655 100644 --- a/examples/README.md +++ b/examples/README.md @@ -34,6 +34,23 @@ There are 4 examples under the following sub-folders: 3. After a build, the targeted jar(s) will be created under a newly created `target` folder under the respective example folder. For instance, `examples/filescan/target`. +## Important: Resource Management + +All examples have been updated to properly manage AMaasClient resources. When using the SDK in your own applications, especially with SOCKS5 proxies, always ensure you call `client.close()` to release network resources: + +```java +AMaasClient client = new AMaasClient("us-east-1", "your-api-key"); +try { + // Perform scanning operations + String result = client.scanFile("file.txt"); +} finally { + // Always close the client to release resources + client.close(); +} +``` + +**Note:** Failure to properly close the client, particularly when using SOCKS5 proxies, may cause your application to hang as background network threads remain active. + ### Use CLI examples - `filescan`: This example is to scan a file or a folder sequentially. It takes 4 input options: diff --git a/examples/filescan/App.java b/examples/filescan/App.java index 7d443da..05dd955 100644 --- a/examples/filescan/App.java +++ b/examples/filescan/App.java @@ -52,7 +52,7 @@ static void scanFilesInSequential(final AMaasClient client, final String[] fList private static Options getCmdOptions() { Options optionList = new Options(); optionList.addRequiredOption("f", "filename", true, "File path or folder to be scanned"); - optionList.addRequiredOption("k", "apikey", true, "Cloud One API key"); + optionList.addRequiredOption("k", "apikey", true, "Vision One API key"); optionList.addRequiredOption("r", "region", true, "AMaaS service region to used. Ignore if self hosted."); optionList.addOption("a", "addr", true, "host ip address of self hosted AMaaS scanner. Ignore if to use Trend AMaaS service"); optionList.addOption("t", "timeout", true, "Per scan timeout in seconds"); @@ -146,13 +146,18 @@ public static void main(final String[] args) { } AMaasClient client = new AMaasClient(region, addr, apikey, timeout, true, caCertPath); - String[] listOfFiles = listFiles(pathname); - long totalStartTs = System.currentTimeMillis(); + try { + String[] listOfFiles = listFiles(pathname); + long totalStartTs = System.currentTimeMillis(); - scanFilesInSequential(client, listOfFiles, tagList, pmlFlag, feedbackFlag, verbose, digest); + scanFilesInSequential(client, listOfFiles, tagList, pmlFlag, feedbackFlag, verbose, digest); - long totalEndTs = System.currentTimeMillis(); - info("*************** Total scan time {0}", totalEndTs - totalStartTs); + long totalEndTs = System.currentTimeMillis(); + info("*************** Total scan time {0}", totalEndTs - totalStartTs); + } finally { + // Ensure client resources are properly closed + client.close(); + } } catch (ParseException err) { helper.printHelp("Usage:", optionList); } catch (NumberFormatException err) { diff --git a/examples/parallelscan/ConcurrentApp.java b/examples/parallelscan/ConcurrentApp.java index 811cfaa..59b3087 100644 --- a/examples/parallelscan/ConcurrentApp.java +++ b/examples/parallelscan/ConcurrentApp.java @@ -129,7 +129,7 @@ static void scanFilesInParallel(final AMaasClient client, final String[] fList, private static Options getCmdOptions() { Options optionList = new Options(); optionList.addRequiredOption("f", "filename", true, "File path or folder to be scanned"); - optionList.addRequiredOption("k", "apikey", true, "Cloud One API key"); + optionList.addRequiredOption("k", "apikey", true, "Vision One API key"); optionList.addRequiredOption("r", "region", true, "AMaaS service region"); optionList.addOption("t", "timeout", true, "Per scan timeout in seconds"); return optionList; @@ -167,11 +167,16 @@ public static void main(final String[] args) { timeout = Long.parseLong(cmd.getOptionValue("t")); } AMaasClient client = new AMaasClient(region, apikey, timeout); - String[] listOfFiles = listFiles(pathName); - long totalStartTs = System.currentTimeMillis(); - scanFilesInParallel(client, listOfFiles, timeout); - long totalEndTs = System.currentTimeMillis(); - info("*************** Total scan time {0}", totalEndTs - totalStartTs); + try { + String[] listOfFiles = listFiles(pathName); + long totalStartTs = System.currentTimeMillis(); + scanFilesInParallel(client, listOfFiles, timeout); + long totalEndTs = System.currentTimeMillis(); + info("*************** Total scan time {0}", totalEndTs - totalStartTs); + } finally { + // Ensure client resources are properly closed + client.close(); + } } catch (ParseException err) { helper.printHelp("Usage:", optionList); } catch (NumberFormatException err) { diff --git a/examples/pom.xml b/examples/pom.xml index 946e365..ac379b4 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -1,22 +1,17 @@ - - - + 4.0.0 - com.trend file-security-sdk-examples 1.0.0 pom - file-security-sdk-examples filescan parallelscan s3app s3lambda + s3stream - UTF-8 1.8 @@ -52,29 +47,28 @@ io.grpc grpc-stub - 1.68.0 + 1.73.0 io.grpc grpc-protobuf - 1.68.0 + 1.73.0 io.grpc grpc-netty - 1.68.0 + 1.73.0 com.trend file-security-java-sdk [1.0,) - - . - + + maven-clean-plugin diff --git a/examples/s3app/S3App.java b/examples/s3app/S3App.java index 9941aac..a488eae 100644 --- a/examples/s3app/S3App.java +++ b/examples/s3app/S3App.java @@ -66,7 +66,7 @@ private static Options getCmdOptions() { optionList.addRequiredOption("a", "awsregion", true, "AWS region"); optionList.addRequiredOption("b", "bucket", true, "S3 bucket name"); optionList.addRequiredOption("f", "S3key", true, "S3 key to be scanned"); - optionList.addRequiredOption("k", "apikey", true, "Cloud One API key"); + optionList.addRequiredOption("k", "apikey", true, "Vision One API key"); optionList.addRequiredOption("r", "region", true, "AMaaS service region"); optionList.addOption("t", "timeout", true, "Per scan timeout in seconds"); return optionList; @@ -79,7 +79,7 @@ private static Options getCmdOptions() { * -b S3 bucket name * -f S3 key to be scanned * -k the API key or bearer authentication token - * -r region where the C1 key/token was applied. eg, us-east-1 + * -r region where the V1 key/token was applied. eg, us-east-1 * -t optional client maximum waiting time in seconds for a scan. 0 or missing means default. */ public static void main(final String[] args) { @@ -105,10 +105,10 @@ public static void main(final String[] args) { keyName = cmd.getOptionValue("f"); } if (cmd.hasOption("r")) { - apikey = cmd.getOptionValue("r"); + amaasRegion = cmd.getOptionValue("r"); } if (cmd.hasOption("k")) { - amaasRegion = cmd.getOptionValue("k"); + apikey = cmd.getOptionValue("k"); } if (cmd.hasOption("t")) { timeout = Long.parseLong(cmd.getOptionValue("t")); @@ -117,10 +117,15 @@ public static void main(final String[] args) { byte[] bytes = downloadS3Object(awsRegion, bucketName, keyName); info("Completed downloading S3 Object...."); AMaasClient client = new AMaasClient(amaasRegion, apikey, timeout); - long totalStartTs = System.currentTimeMillis(); - client.scanBuffer(bytes, keyName); - long totalEndTs = System.currentTimeMillis(); - info("*************** Total scan time {0}", totalEndTs - totalStartTs); + try { + long totalStartTs = System.currentTimeMillis(); + client.scanBuffer(bytes, keyName); + long totalEndTs = System.currentTimeMillis(); + info("*************** Total scan time {0}", totalEndTs - totalStartTs); + } finally { + // Ensure client resources are properly closed + client.close(); + } } catch (ParseException err) { helper.printHelp("Usage:", optionList); } catch (NumberFormatException err) { diff --git a/examples/s3lambda/S3Lambda.java b/examples/s3lambda/S3Lambda.java index d2afe97..625f28d 100644 --- a/examples/s3lambda/S3Lambda.java +++ b/examples/s3lambda/S3Lambda.java @@ -108,7 +108,7 @@ private static void sequentialScan(final AMaasClient client, final S3Client s3cl * It can scan either a specific S3 key or a folder under a S3 bucket. * * TM_AM_AUTH_KEY the API key or bearer authentication token - * TM_AM_REGION region where the C1 key/token was applied. eg, us-east-1 + * TM_AM_REGION region where the V1 key/token was applied. eg, us-east-1 * TM_AM_SCAN_TIMEOUT_SECS client maximum waiting time in seconds for a scan. 0 or missing means default. * * S3_BUCKET_NAME S3 bucket name @@ -159,11 +159,16 @@ public String handleRequest(final Object input, final Context context) { } AMaasClient client = new AMaasClient(region, apikey, timeout); - long totalStartTs = System.currentTimeMillis(); - - sequentialScan(client, s3client, bucketName, keyList, tagList); - long totalEndTs = System.currentTimeMillis(); - info("*************** Total scan time {0}", totalEndTs - totalStartTs); + try { + long totalStartTs = System.currentTimeMillis(); + + sequentialScan(client, s3client, bucketName, keyList, tagList); + long totalEndTs = System.currentTimeMillis(); + info("*************** Total scan time {0}", totalEndTs - totalStartTs); + } finally { + // Ensure client resources are properly closed + client.close(); + } } catch (Exception err) { info("Exception encountered {0}", err); } diff --git a/examples/s3stream/S3Stream.java b/examples/s3stream/S3Stream.java new file mode 100644 index 0000000..508240a --- /dev/null +++ b/examples/s3stream/S3Stream.java @@ -0,0 +1,263 @@ +package com.trend.cloudone.amaas; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; + +import software.amazon.awssdk.core.ResponseInputStream; +import software.amazon.awssdk.core.exception.SdkException; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.GetObjectRequest; +import software.amazon.awssdk.services.s3.model.GetObjectResponse; +import software.amazon.awssdk.services.s3.model.HeadObjectRequest; +import software.amazon.awssdk.services.s3.model.HeadObjectResponse; + +import com.trend.cloudone.amaas.AMaasReader.HashType; + +/** + * S3Stream class implements the AMaasReader interface for S3 objects. + * It supports only S3 URI format (s3://bucket/key) and gets hash results directly from AWS SDK. + */ +public class S3Stream implements AMaasReader { + private static final Logger logger = Logger.getLogger(S3Stream.class.getName()); + private static final int CHUNK_SIZE_KB = 8; + private static final int BYTES_PER_KB = 1024; + + private String region; + private String bucket; + private String key; + private long fileSize; + private final S3Client s3Client; + private String sha1Hash; + private String sha256Hash; + + /** + * Create an S3 stream reader. Automatically creates S3Client with default configuration. + * + * @param region The AWS region where the S3 bucket is located. + * @param bucket The S3 bucket name. + * @param key The S3 object key. + * @throws AMaasException If the S3 client cannot be created or if the S3 object cannot be accessed. + */ + public S3Stream(final String region, final String bucket, final String key) throws AMaasException { + if (region == null || region.isEmpty() || bucket == null || bucket.isEmpty() || key == null || key.isEmpty()) { + throw new AMaasException(AMaasErrorCode.MSG_ID_ERR_FILE_NOT_FOUND, "s3://" + bucket + "/" + key); + } + + this.region = region; + this.bucket = bucket; + this.key = key; + + try { + // Create S3Client with default configuration and specified region + this.s3Client = S3Client.builder() + .region(Region.of(region)) + .build(); + } catch (Exception ex) { + throw new AMaasException(AMaasErrorCode.MSG_ID_ERR_UNEXPECTED, ex); + } + + try { + determineObjectMetadata(); + } catch (SecurityException err) { + throw new AMaasException(AMaasErrorCode.MSG_ID_ERR_FILE_NO_PERMISSION, "s3://" + this.bucket + "/" + this.key); + } + } + + /** + * Get the S3 object identifier (URI). + * @return the S3 URI as string + */ + @Override + public String getIdentifier() { + return "s3://" + this.bucket + "/" + this.key; + } + + /** + * Get the size of the S3 object. + * @return the size in bytes + */ + @Override + public long getLength() { + return this.fileSize; + } + + /** + * Read bytes from the S3 object starting from the given offset. + * @param offset starting offset to read from + * @param buff byte array to fill with content + * @return number of bytes read + * @throws IOException if read fails + */ + @Override + public int readBytes(final int offset, final byte[] buff) throws IOException { + final ByteBuffer byteBuffer = ByteBuffer.wrap(buff); + return readByteRange(offset, byteBuffer); + } + + /** + * Get hash from S3 object metadata. + * @param htype the type of hash (HASH_SHA1 or HASH_SHA256) + * @return the hash value as hex string with prefix (e.g., "sha1:abc123...") + */ + @Override + public String getHash(final HashType htype) { + switch (htype) { + case HASH_SHA1: + return (this.sha1Hash == null) ? "" : "sha1:" + this.sha1Hash; + case HASH_SHA256: + return (this.sha256Hash == null) ? "" : "sha256:" + this.sha256Hash; + default: + return ""; + } + } + + /** + * Gets the sha1, sha256 digest and size of the given S3 object in bytes. + */ + private void determineObjectMetadata() throws AMaasException { + try { + final HeadObjectRequest request = HeadObjectRequest.builder() + .bucket(this.bucket) + .key(this.key) + .build(); + + final HeadObjectResponse response = s3Client.headObject(request); + this.fileSize = response.contentLength(); + + // Get hash results directly from AWS SDK + if (response.checksumSHA1() != null) { + this.sha1Hash = response.checksumSHA1(); + } + if (response.checksumSHA256() != null) { + this.sha256Hash = response.checksumSHA256(); + } + } catch (SdkException ex) { + throw new AMaasException(AMaasErrorCode.MSG_ID_ERR_UNEXPECTED); + } + } + + /** + * Reads a byte range from a file served via S3 URI. + * + * @param startByte The starting byte (inclusive) + * @param byteBuffer The ByteBuffer to fill with the read data + * @return The number of bytes read + * @throws IOException if the connection fails or read fails + */ + private int readByteRange(final long startByte, final ByteBuffer byteBuffer) throws IOException { + if (startByte < 0 || fileSize < startByte) { + throw new IllegalArgumentException("Invalid byte range"); + } + + final long endByte = Math.min(startByte + byteBuffer.remaining() - 1, fileSize - 1); + + final GetObjectRequest getObjectRequest = GetObjectRequest.builder() + .bucket(this.bucket) + .key(this.key) + .range(String.format("bytes=%d-%d", startByte, endByte)) + .build(); + + int totalBytesRead = 0; + try (ResponseInputStream s3Stream = this.s3Client.getObject(getObjectRequest)) { + byte[] chunk = new byte[CHUNK_SIZE_KB * BYTES_PER_KB]; + int bytesRead; + while ((bytesRead = s3Stream.read(chunk)) != -1) { + byteBuffer.put(chunk, 0, bytesRead); + totalBytesRead += bytesRead; + } + } catch (SdkException | IOException ex) { + throw new RuntimeException("Failed to download S3 object range", ex); + } + return totalBytesRead; + } + + private static void info(final String msg, final Object... params) { + logger.log(Level.INFO, msg, params); + } + + private static Options getCmdOptions() { + Options optionList = new Options(); + optionList.addRequiredOption("a", "awsregion", true, "AWS region"); + optionList.addRequiredOption("b", "bucket", true, "S3 bucket name"); + optionList.addRequiredOption("f", "S3key", true, "S3 key to be scanned"); + optionList.addRequiredOption("k", "apikey", true, "Vision One API key"); + optionList.addRequiredOption("r", "region", true, "AMaaS service region"); + optionList.addOption("t", "timeout", true, "Per scan timeout in seconds"); + return optionList; + } + + /** + * The program takes 6 options and respecive values to configure the AMaaS SDK client. + * @param args Input options: + * -a AWS region + * -b S3 bucket name + * -f S3 key to be scanned + * -k the API key or bearer authentication token + * -r region where the V1 key/token was applied. eg, us-east-1 + * -t optional client maximum waiting time in seconds for a scan. 0 or missing means default. + */ + public static void main(final String[] args) { + String awsRegion = ""; + String bucketName = ""; + String keyName = ""; + String apikey = null; + String amaasRegion = ""; + long timeout = 0; + + DefaultParser parser = new DefaultParser(); + HelpFormatter helper = new HelpFormatter(); + Options optionList = getCmdOptions(); + try { + CommandLine cmd = parser.parse(optionList, args); + if (cmd.hasOption("a")) { + awsRegion = cmd.getOptionValue("a"); + } + if (cmd.hasOption("b")) { + bucketName = cmd.getOptionValue("b"); + } + if (cmd.hasOption("f")) { + keyName = cmd.getOptionValue("f"); + } + if (cmd.hasOption("r")) { + amaasRegion = cmd.getOptionValue("r"); + } + if (cmd.hasOption("k")) { + apikey = cmd.getOptionValue("k"); + } + if (cmd.hasOption("t")) { + timeout = Long.parseLong(cmd.getOptionValue("t")); + } + info("Creating S3Stream for S3 Object...."); + S3Stream s3Stream = new S3Stream(awsRegion, bucketName, keyName); + info("Completed creating S3Stream for S3 Object...."); + AMaasClient client = new AMaasClient(amaasRegion, apikey, timeout); + try { + long totalStartTs = System.currentTimeMillis(); + + // Use scanRun with the S3Stream AMaasReader + String scanResult = client.scanRun(s3Stream, null, false, false, false, true); + long totalEndTs = System.currentTimeMillis(); + info("Scan Result: {0}", scanResult); + info("*************** Total scan time {0}", totalEndTs - totalStartTs); + } finally { + client.close(); + } + } catch (ParseException err) { + helper.printHelp("Usage:", optionList); + } catch (NumberFormatException err) { + info("Exception parsing -t value must be a number"); + } catch (AMaasException err) { + info("AMaaS SDK Exception encountered: {0}", err.getMessage()); + } catch (Exception err) { + info("Unexpected exception encountered: {0}", err.getMessage()); + } + } +} diff --git a/examples/s3stream/pom.xml b/examples/s3stream/pom.xml new file mode 100644 index 0000000..0c6fd92 --- /dev/null +++ b/examples/s3stream/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + + com.trend + file-security-sdk-example-s3stream + 1.0.0 + + file-security-sdk-example-s3stream + + + com.trend + file-security-sdk-examples + 1.0.0 + + + + + + software.amazon.awssdk + bom + 2.20.66 + pom + import + + + + + + software.amazon.awssdk + s3 + + + commons-cli + commons-cli + 1.5.0 + + + diff --git a/pom.xml b/pom.xml index 28f2bf5..9023f2e 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.trend file-security-java-sdk - 1.4.5 + 1.5.0 file-security-java-sdk https://github.com/trendmicro/tm-v1-fs-java-sdk @@ -74,22 +74,30 @@ io.grpc grpc-stub - 1.68.0 + 1.73.0 io.grpc grpc-protobuf - 1.68.0 + 1.73.0 io.grpc grpc-netty - 1.68.0 + 1.73.0 + + io.netty* + + + + io.netty + netty-all + 4.1.121.Final io.grpc grpc-testing - 1.68.0 + 1.73.0 test