S3Properties.java
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF 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.
package org.apache.doris.datasource.property.storage;
import org.apache.doris.cloud.proto.Cloud;
import org.apache.doris.cloud.proto.Cloud.CredProviderTypePB;
import org.apache.doris.cloud.proto.Cloud.ObjectStoreInfoPB.Provider;
import org.apache.doris.common.DdlException;
import org.apache.doris.datasource.property.ConnectorPropertiesUtils;
import org.apache.doris.datasource.property.ConnectorProperty;
import org.apache.doris.thrift.TCredProviderType;
import org.apache.doris.thrift.TS3StorageParam;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProviderChain;
import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider;
import software.amazon.awssdk.auth.credentials.InstanceProfileCredentialsProvider;
import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider;
import software.amazon.awssdk.auth.credentials.SystemPropertyCredentialsProvider;
import software.amazon.awssdk.auth.credentials.WebIdentityTokenFileCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sts.StsClient;
import software.amazon.awssdk.services.sts.auth.StsAssumeRoleCredentialsProvider;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Stream;
public class S3Properties extends AbstractS3CompatibleProperties {
public static final String USE_PATH_STYLE = "use_path_style";
private static final String[] ENDPOINT_NAMES_FOR_GUESSING = {
"s3.endpoint", "AWS_ENDPOINT", "endpoint", "ENDPOINT", "aws.endpoint", "glue.endpoint",
"aws.glue.endpoint"
};
private static final String[] REGION_NAMES_FOR_GUESSING = {
"s3.region", "glue.region", "aws.glue.region", "iceberg.rest.signing-region"
};
@Setter
@Getter
@ConnectorProperty(names = {"s3.endpoint", "AWS_ENDPOINT", "endpoint", "ENDPOINT", "aws.endpoint", "glue.endpoint",
"aws.glue.endpoint"},
required = false,
description = "The endpoint of S3.")
protected String endpoint = "";
@Setter
@Getter
@ConnectorProperty(names = {"s3.region", "AWS_REGION", "region", "REGION", "aws.region", "glue.region",
"aws.glue.region", "iceberg.rest.signing-region"},
required = false,
description = "The region of S3.")
protected String region = "";
@Getter
@ConnectorProperty(names = {"s3.access_key", "AWS_ACCESS_KEY", "access_key", "ACCESS_KEY", "glue.access_key",
"aws.glue.access-key", "client.credentials-provider.glue.access_key", "iceberg.rest.access-key-id",
"s3.access-key-id"},
required = false,
description = "The access key of S3. Optional for anonymous access to public datasets.")
protected String accessKey = "";
@Getter
@ConnectorProperty(names = {"s3.secret_key", "AWS_SECRET_KEY", "secret_key", "SECRET_KEY", "glue.secret_key",
"aws.glue.secret-key", "client.credentials-provider.glue.secret_key", "iceberg.rest.secret-access-key",
"s3.secret-access-key"},
required = false,
sensitive = true,
description = "The secret key of S3. Optional for anonymous access to public datasets.")
protected String secretKey = "";
@Getter
@ConnectorProperty(names = {"s3.session_token", "session_token", "s3.session-token"},
required = false,
description = "The session token of S3.")
protected String sessionToken = "";
@Getter
@ConnectorProperty(names = {"s3.session-token-token-expires-at-ms"},
required = false,
description = "The session token expiration time in milliseconds since epoch.")
protected String sessionTokenExpiresAtMs = "";
@Getter
@ConnectorProperty(names = {"s3.connection.maximum",
"AWS_MAX_CONNECTIONS"},
required = false,
description = "The maximum number of connections to S3.")
protected String maxConnections = "50";
@Getter
@ConnectorProperty(names = {"s3.connection.request.timeout",
"AWS_REQUEST_TIMEOUT_MS"},
required = false,
description = "The request timeout of S3 in milliseconds,")
protected String requestTimeoutS = "3000";
@Getter
@ConnectorProperty(names = {"s3.connection.timeout",
"AWS_CONNECTION_TIMEOUT_MS"},
required = false,
description = "The connection timeout of S3 in milliseconds,")
protected String connectionTimeoutS = "1000";
@Setter
@Getter
@ConnectorProperty(names = {USE_PATH_STYLE, "s3.path-style-access"}, required = false,
description = "Whether to use path style URL for the storage.")
protected String usePathStyle = "false";
@ConnectorProperty(names = {"force_parsing_by_standard_uri"}, required = false,
description = "Whether to use path style URL for the storage.")
@Setter
@Getter
protected String forceParsingByStandardUrl = "false";
@ConnectorProperty(names = {"s3.sts_endpoint"},
supported = false,
required = false,
description = "The sts endpoint of S3.")
protected String s3StsEndpoint = "";
@ConnectorProperty(names = {"s3.sts_region"},
supported = false,
required = false,
description = "The sts region of S3.")
protected String s3StsRegion = "";
@ConnectorProperty(names = {"s3.role_arn", "AWS_ROLE_ARN"},
required = false,
description = "The iam role of S3.")
protected String s3IAMRole = "";
@ConnectorProperty(names = {"s3.external_id", "AWS_EXTERNAL_ID"},
required = false,
description = "The external id of S3.")
protected String s3ExternalId = "";
public static S3Properties of(Map<String, String> properties) {
S3Properties propertiesObj = new S3Properties(properties);
ConnectorPropertiesUtils.bindConnectorProperties(propertiesObj, properties);
propertiesObj.initNormalizeAndCheckProps();
return propertiesObj;
}
/**
* Pattern to match various AWS S3 endpoint formats and extract the region part.
* <p>
* Supported formats:
* - s3.us-west-2.amazonaws.com => region = us-west-2
* - s3.dualstack.us-east-1.amazonaws.com => region = us-east-1
* - s3-fips.us-east-2.amazonaws.com => region = us-east-2
* - s3-fips.dualstack.us-east-2.amazonaws.com => region = us-east-2
* - s3express-control.us-west-2.amazonaws.com => region = us-west-2 (S3 Directory Bucket Regional)
* - s3express-usw2-az1.us-west-2.amazonaws.com => region = us-west-2 (S3 Directory Bucket Zonal)
* <p>
* Group(1), Group(2), or Group(3) in the pattern captures the region part if available.
* <p>
* For Glue https://docs.aws.amazon.com/general/latest/gr/glue.html
*/
private static final Set<Pattern> ENDPOINT_PATTERN = ImmutableSet.of(
Pattern.compile(
"^(?:https?://)?(?:"
+ "s3(?:[-.]fips)?(?:[-.]dualstack)?[-.]([a-z0-9-]+)|" // Standard S3 endpoints
+ "s3express-control\\.([a-z0-9-]+)|" // Directory bucket regional
+ "s3express-[a-z0-9-]+\\.([a-z0-9-]+)" // Directory bucket zonal
+ ")\\.amazonaws\\.com(?:/.*)?$",
Pattern.CASE_INSENSITIVE),
Pattern.compile(
"^(?:https?://)?glue(?:-fips)?\\.([a-z0-9-]+)\\.(amazonaws\\.com(?:\\.cn)?|api\\.aws)$",
Pattern.CASE_INSENSITIVE));
public S3Properties(Map<String, String> origProps) {
super(Type.S3, origProps);
}
@Override
public void initNormalizeAndCheckProps() {
super.initNormalizeAndCheckProps();
if (StringUtils.isNotBlank(s3ExternalId) && StringUtils.isBlank(s3IAMRole)) {
throw new IllegalArgumentException("s3.external_id must be used with s3.role_arn");
}
convertGlueToS3EndpointIfNeeded();
}
/**
* Guess if the storage properties is for this storage type.
* Subclass should override this method to provide the correct implementation.
*
* @return
*/
protected static boolean guessIsMe(Map<String, String> origProps) {
String endpoint = Stream.of(ENDPOINT_NAMES_FOR_GUESSING)
.map(origProps::get)
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
/**
* Check if the endpoint contains "amazonaws.com" to determine if it's an S3-compatible storage.
* Note: This check should not be overly strict, as a malformed or misconfigured endpoint may
* cause the type detection to fail, leading to missed recognition of valid S3 properties.
* A more robust approach would allow further validation downstream rather than failing early here.
*/
if (StringUtils.isNotBlank(endpoint)) {
return endpoint.contains("amazonaws.com");
}
// guess from URI
Optional<String> uriValue = origProps.entrySet().stream()
.filter(e -> e.getKey().equalsIgnoreCase("uri"))
.map(Map.Entry::getValue)
.findFirst();
if (uriValue.isPresent()) {
return uriValue.get().contains("amazonaws.com");
}
// guess from region
String region = Stream.of(REGION_NAMES_FOR_GUESSING)
.map(origProps::get)
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
if (StringUtils.isNotBlank(region)) {
return true;
}
return false;
}
@Override
protected Set<Pattern> endpointPatterns() {
return ENDPOINT_PATTERN;
}
@Override
public Map<String, String> getBackendConfigProperties() {
Map<String, String> backendProperties = generateBackendS3Configuration();
if (StringUtils.isNotBlank(s3IAMRole)) {
backendProperties.put("AWS_ROLE_ARN", s3IAMRole);
}
if (StringUtils.isNotBlank(s3ExternalId)) {
backendProperties.put("AWS_EXTERNAL_ID", s3ExternalId);
}
return backendProperties;
}
private void convertGlueToS3EndpointIfNeeded() {
if (this.endpoint.contains("glue")) {
this.endpoint = "https://s3." + this.region + ".amazonaws.com";
}
}
@Override
public AwsCredentialsProvider getAwsCredentialsProvider() {
AwsCredentialsProvider credentialsProvider = super.getAwsCredentialsProvider();
if (credentialsProvider != null) {
return credentialsProvider;
}
if (StringUtils.isNotBlank(s3IAMRole)) {
StsClient stsClient = StsClient.builder()
.region(Region.of(region))
.credentialsProvider(InstanceProfileCredentialsProvider.create())
.build();
return StsAssumeRoleCredentialsProvider.builder()
.stsClient(stsClient)
.refreshRequest(builder -> {
builder.roleArn(s3IAMRole).roleSessionName("aws-sdk-java-v2-fe");
if (StringUtils.isNotBlank(s3ExternalId)) {
builder.externalId(s3ExternalId);
}
}).build();
}
// For anonymous access (no credentials required)
//fixme: should return AwsCredentialsProviderChain
if (StringUtils.isBlank(accessKey) && StringUtils.isBlank(secretKey)) {
return AnonymousCredentialsProvider.create();
}
return AwsCredentialsProviderChain.of(SystemPropertyCredentialsProvider.create(),
EnvironmentVariableCredentialsProvider.create(),
WebIdentityTokenFileCredentialsProvider.create(),
ProfileCredentialsProvider.create(),
InstanceProfileCredentialsProvider.create());
}
@Override
public void initializeHadoopStorageConfig() {
super.initializeHadoopStorageConfig();
//Set assumed_roles
//@See https://hadoop.apache.org/docs/r3.4.1/hadoop-aws/tools/hadoop-aws/assumed_roles.html
if (StringUtils.isNotBlank(s3IAMRole)) {
//@See org.apache.hadoop.fs.s3a.auth.AssumedRoleCredentialProvider
hadoopStorageConfig.set("fs.s3a.assumed.role.arn", s3IAMRole);
hadoopStorageConfig.set("fs.s3a.aws.credentials.provider",
"org.apache.hadoop.fs.s3a.auth.AssumedRoleCredentialProvider");
if (StringUtils.isNotBlank(s3ExternalId)) {
hadoopStorageConfig.set("fs.s3a.assumed.role.external.id", s3ExternalId);
}
}
}
@Override
protected String getEndpointFromRegion() {
if (!StringUtils.isBlank(endpoint)) {
return endpoint;
}
if (StringUtils.isBlank(region)) {
return "";
}
return "https://s3." + region + ".amazonaws.com";
}
/**
* ===========================================
* NOTICE:
* This parameter is still used for Cloud-related features,
* although it is no longer recommended.
*
* Reason:
* - Cloud may access S3-compatible object storage via the S3 protocol.
* - The exact behavior has not yet been fully clarified.
*
* Therefore:
* - We cannot directly replace it with the new parameter.
* - This redundant parameter is temporarily kept for compatibility.
* ===========================================
*/
public static final String S3_PREFIX = "s3.";
public static final String ENDPOINT = "s3.endpoint";
public static final String EXTERNAL_ENDPOINT = "s3.external_endpoint";
public static final String REGION = "s3.region";
public static final String ACCESS_KEY = "s3.access_key";
public static final String SECRET_KEY = "s3.secret_key";
public static final String SESSION_TOKEN = "s3.session_token";
public static final String MAX_CONNECTIONS = "s3.connection.maximum";
public static final String REQUEST_TIMEOUT_MS = "s3.connection.request.timeout";
public static final String CONNECTION_TIMEOUT_MS = "s3.connection.timeout";
public static final String ROLE_ARN = "s3.role_arn";
public static final String EXTERNAL_ID = "s3.external_id";
public static final String ROOT_PATH = "s3.root.path";
public static final String BUCKET = "s3.bucket";
public static final String VALIDITY_CHECK = "s3_validity_check";
public static final List<String> REQUIRED_FIELDS = Arrays.asList(ENDPOINT);
public static class Env {
public static final String PROPERTIES_PREFIX = "AWS";
// required
public static final String ENDPOINT = "AWS_ENDPOINT";
public static final String REGION = "AWS_REGION";
public static final String ACCESS_KEY = "AWS_ACCESS_KEY";
public static final String SECRET_KEY = "AWS_SECRET_KEY";
public static final String TOKEN = "AWS_TOKEN";
// required by storage policy
public static final String ROOT_PATH = "AWS_ROOT_PATH";
public static final String BUCKET = "AWS_BUCKET";
// optional
public static final String MAX_CONNECTIONS = "AWS_MAX_CONNECTIONS";
public static final String REQUEST_TIMEOUT_MS = "AWS_REQUEST_TIMEOUT_MS";
public static final String CONNECTION_TIMEOUT_MS = "AWS_CONNECTION_TIMEOUT_MS";
public static final String DEFAULT_MAX_CONNECTIONS = "50";
public static final String DEFAULT_REQUEST_TIMEOUT_MS = "3000";
public static final String DEFAULT_CONNECTION_TIMEOUT_MS = "1000";
public static final String ROLE_ARN = "AWS_ROLE_ARN";
public static final String EXTERNAL_ID = "AWS_EXTERNAL_ID";
public static final List<String> REQUIRED_FIELDS = Arrays.asList(ENDPOINT);
public static final List<String> FS_KEYS = Arrays.asList(ENDPOINT, REGION, ACCESS_KEY, SECRET_KEY, TOKEN,
ROOT_PATH, BUCKET, MAX_CONNECTIONS, REQUEST_TIMEOUT_MS, CONNECTION_TIMEOUT_MS);
}
public static void requiredS3Properties(Map<String, String> properties) throws DdlException {
// Try to convert env properties to uniform properties
// compatible with old version
convertToStdProperties(properties);
if (properties.containsKey(Env.ENDPOINT)
&& !properties.containsKey(ENDPOINT)) {
for (String field : Env.REQUIRED_FIELDS) {
checkRequiredProperty(properties, field);
}
} else {
for (String field : REQUIRED_FIELDS) {
checkRequiredProperty(properties, field);
}
}
if (StringUtils.isNotBlank(properties.get(StorageProperties.FS_PROVIDER_KEY))) {
// S3 Provider properties should be case insensitive.
if (!PROVIDERS.stream().anyMatch(s -> s.equals(properties.get(FS_PROVIDER_KEY).toUpperCase()))) {
throw new DdlException("Provider must be one of OSS, OBS, AZURE, BOS, COS, S3, GCP");
}
}
}
public static final List<String> PROVIDERS = Arrays.asList("COS", "OSS", "S3", "OBS", "BOS", "AZURE", "GCP", "TOS");
public static void checkRequiredProperty(Map<String, String> properties, String propertyKey)
throws DdlException {
String value = properties.get(propertyKey);
if (StringUtils.isBlank(value)) {
throw new DdlException("Missing [" + propertyKey + "] in properties.");
}
}
public static void requiredS3PingProperties(Map<String, String> properties) throws DdlException {
requiredS3Properties(properties);
checkRequiredProperty(properties, BUCKET);
}
public static void convertToStdProperties(Map<String, String> properties) {
if (properties.containsKey(Env.ENDPOINT)) {
properties.putIfAbsent(ENDPOINT, properties.get(Env.ENDPOINT));
}
if (properties.containsKey(Env.REGION)) {
properties.putIfAbsent(REGION, properties.get(Env.REGION));
}
if (properties.containsKey(Env.ACCESS_KEY)) {
properties.putIfAbsent(ACCESS_KEY, properties.get(Env.ACCESS_KEY));
}
if (properties.containsKey(Env.SECRET_KEY)) {
properties.putIfAbsent(SECRET_KEY, properties.get(Env.SECRET_KEY));
}
if (properties.containsKey(Env.TOKEN)) {
properties.putIfAbsent(SESSION_TOKEN, properties.get(Env.TOKEN));
}
if (properties.containsKey(Env.MAX_CONNECTIONS)) {
properties.putIfAbsent(MAX_CONNECTIONS, properties.get(Env.MAX_CONNECTIONS));
}
if (properties.containsKey(Env.REQUEST_TIMEOUT_MS)) {
properties.putIfAbsent(REQUEST_TIMEOUT_MS,
properties.get(Env.REQUEST_TIMEOUT_MS));
}
if (properties.containsKey(Env.CONNECTION_TIMEOUT_MS)) {
properties.putIfAbsent(CONNECTION_TIMEOUT_MS,
properties.get(Env.CONNECTION_TIMEOUT_MS));
}
if (properties.containsKey(Env.ROOT_PATH)) {
properties.putIfAbsent(ROOT_PATH, properties.get(Env.ROOT_PATH));
}
if (properties.containsKey(Env.BUCKET)) {
properties.putIfAbsent(BUCKET, properties.get(Env.BUCKET));
}
if (properties.containsKey(USE_PATH_STYLE)) {
properties.putIfAbsent(USE_PATH_STYLE, properties.get(USE_PATH_STYLE));
}
if (properties.containsKey(Env.ROLE_ARN)) {
properties.putIfAbsent(ROLE_ARN, properties.get(Env.ROLE_ARN));
}
if (properties.containsKey(Env.EXTERNAL_ID)) {
properties.putIfAbsent(EXTERNAL_ID, properties.get(Env.EXTERNAL_ID));
}
}
private static final Pattern IPV4_PORT_PATTERN = Pattern.compile("((?:\\d{1,3}\\.){3}\\d{1,3}:\\d{1,5})");
public static String getRegionOfEndpoint(String endpoint) {
if (IPV4_PORT_PATTERN.matcher(endpoint).find()) {
// if endpoint contains '192.168.0.1:8999', return null region
return null;
}
String[] endpointSplit = endpoint.replace("http://", "")
.replace("https://", "")
.split("\\.");
if (endpointSplit.length < 2) {
return null;
}
if (endpointSplit[0].contains("oss-")) {
// compatible with the endpoint: oss-cn-bejing.aliyuncs.com
return endpointSplit[0];
}
return endpointSplit[1];
}
public static void optionalS3Property(Map<String, String> properties) {
properties.putIfAbsent(MAX_CONNECTIONS, Env.DEFAULT_MAX_CONNECTIONS);
properties.putIfAbsent(REQUEST_TIMEOUT_MS, Env.DEFAULT_REQUEST_TIMEOUT_MS);
properties.putIfAbsent(CONNECTION_TIMEOUT_MS, Env.DEFAULT_CONNECTION_TIMEOUT_MS);
// compatible with old version
properties.putIfAbsent(Env.MAX_CONNECTIONS, Env.DEFAULT_MAX_CONNECTIONS);
properties.putIfAbsent(Env.REQUEST_TIMEOUT_MS, Env.DEFAULT_REQUEST_TIMEOUT_MS);
properties.putIfAbsent(Env.CONNECTION_TIMEOUT_MS, Env.DEFAULT_CONNECTION_TIMEOUT_MS);
}
public static Cloud.ObjectStoreInfoPB.Builder getObjStoreInfoPB(Map<String, String> properties) {
Cloud.ObjectStoreInfoPB.Builder builder = Cloud.ObjectStoreInfoPB.newBuilder();
if (properties.containsKey(S3Properties.ENDPOINT)) {
builder.setEndpoint(properties.get(S3Properties.ENDPOINT));
}
if (properties.containsKey(S3Properties.REGION)) {
builder.setRegion(properties.get(S3Properties.REGION));
}
if (properties.containsKey(S3Properties.ACCESS_KEY)) {
builder.setAk(properties.get(S3Properties.ACCESS_KEY));
}
if (properties.containsKey(S3Properties.SECRET_KEY)) {
builder.setSk(properties.get(S3Properties.SECRET_KEY));
}
if (properties.containsKey(S3Properties.ROOT_PATH)) {
Preconditions.checkArgument(!Strings.isNullOrEmpty(properties.get(S3Properties.ROOT_PATH)),
"%s cannot be empty", S3Properties.ROOT_PATH);
builder.setPrefix(properties.get(S3Properties.ROOT_PATH));
}
if (properties.containsKey(S3Properties.BUCKET)) {
builder.setBucket(properties.get(S3Properties.BUCKET));
}
if (properties.containsKey(S3Properties.EXTERNAL_ENDPOINT)) {
builder.setExternalEndpoint(properties.get(S3Properties.EXTERNAL_ENDPOINT));
}
if (properties.containsKey(StorageProperties.FS_PROVIDER_KEY)) {
// S3 Provider properties should be case insensitive.
builder.setProvider(Provider.valueOf(properties.get(StorageProperties.FS_PROVIDER_KEY).toUpperCase()));
}
if (properties.containsKey(S3Properties.USE_PATH_STYLE)) {
String value = properties.get(S3Properties.USE_PATH_STYLE);
Preconditions.checkArgument(!Strings.isNullOrEmpty(value), "use_path_style cannot be empty");
Preconditions.checkArgument(value.equalsIgnoreCase("true")
|| value.equalsIgnoreCase("false"),
"Invalid use_path_style value: %s only 'true' or 'false' is acceptable", value);
builder.setUsePathStyle(value.equalsIgnoreCase("true"));
}
if (properties.containsKey(S3Properties.ROLE_ARN)) {
builder.setRoleArn(properties.get(S3Properties.ROLE_ARN));
if (properties.containsKey(S3Properties.EXTERNAL_ID)) {
builder.setExternalId(properties.get(S3Properties.EXTERNAL_ID));
}
builder.setCredProviderType(CredProviderTypePB.INSTANCE_PROFILE);
}
return builder;
}
public static TS3StorageParam getS3TStorageParam(Map<String, String> properties) {
TS3StorageParam s3Info = new TS3StorageParam();
if (properties.containsKey(S3Properties.ROLE_ARN)) {
s3Info.setRoleArn(properties.get(S3Properties.ROLE_ARN));
if (properties.containsKey(S3Properties.EXTERNAL_ID)) {
s3Info.setExternalId(properties.get(S3Properties.EXTERNAL_ID));
}
s3Info.setCredProviderType(TCredProviderType.INSTANCE_PROFILE);
}
s3Info.setEndpoint(properties.get(S3Properties.ENDPOINT));
s3Info.setRegion(properties.get(S3Properties.REGION));
s3Info.setAk(properties.get(S3Properties.ACCESS_KEY));
s3Info.setSk(properties.get(S3Properties.SECRET_KEY));
s3Info.setToken(properties.get(S3Properties.SESSION_TOKEN));
s3Info.setRootPath(properties.get(S3Properties.ROOT_PATH));
s3Info.setBucket(properties.get(S3Properties.BUCKET));
String maxConnections = properties.get(S3Properties.MAX_CONNECTIONS);
s3Info.setMaxConn(Integer.parseInt(maxConnections == null
? S3Properties.Env.DEFAULT_MAX_CONNECTIONS : maxConnections));
String requestTimeoutMs = properties.get(S3Properties.REQUEST_TIMEOUT_MS);
s3Info.setRequestTimeoutMs(Integer.parseInt(requestTimeoutMs == null
? S3Properties.Env.DEFAULT_REQUEST_TIMEOUT_MS : requestTimeoutMs));
String connTimeoutMs = properties.get(S3Properties.CONNECTION_TIMEOUT_MS);
s3Info.setConnTimeoutMs(Integer.parseInt(connTimeoutMs == null
? S3Properties.Env.DEFAULT_CONNECTION_TIMEOUT_MS : connTimeoutMs));
String usePathStyle = properties.getOrDefault(S3Properties.USE_PATH_STYLE, "false");
s3Info.setUsePathStyle(Boolean.parseBoolean(usePathStyle));
return s3Info;
}
}