From 7f74a9f9a2d9bc4f1f913ab732c602613a4ee610 Mon Sep 17 00:00:00 2001 From: Eleni Dimitropoulou <12170229+eldimi@users.noreply.github.com> Date: Fri, 21 Jul 2023 16:36:40 +0300 Subject: [PATCH 1/5] chore: add powertools user-agent-suffix to the AWS SDK v2 clients --- pom.xml | 1 + powertools-core/pom.xml | 9 ++ .../core/internal/UserAgentConfigurer.java | 90 ++++++++++++++++ .../src/main/resources/version.properties | 1 + .../internal/UserAgentConfigurerTest.java | 102 ++++++++++++++++++ .../src/test/resources/test.properties | 1 + .../src/test/resources/unreadable.properties | 1 + .../persistence/DynamoDBPersistenceStore.java | 7 +- .../parameters/AppConfigProvider.java | 9 +- .../powertools/parameters/BaseProvider.java | 1 + .../parameters/DynamoDbProvider.java | 6 +- .../powertools/parameters/SSMProvider.java | 7 +- .../parameters/SecretsProvider.java | 6 +- .../lambda/powertools/sqs/SqsUtils.java | 30 +++--- 14 files changed, 252 insertions(+), 19 deletions(-) create mode 100644 powertools-core/src/main/java/software/amazon/lambda/powertools/core/internal/UserAgentConfigurer.java create mode 100644 powertools-core/src/main/resources/version.properties create mode 100644 powertools-core/src/test/java/software/amazon/lambda/powertools/core/internal/UserAgentConfigurerTest.java create mode 100644 powertools-core/src/test/resources/test.properties create mode 100644 powertools-core/src/test/resources/unreadable.properties diff --git a/pom.xml b/pom.xml index 2e68a99ec..f092e8617 100644 --- a/pom.xml +++ b/pom.xml @@ -519,6 +519,7 @@ @{argLine} --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED + --add-exports=java.xml.crypto/com.sun.org.slf4j.internal=ALL-UNNAMED diff --git a/powertools-core/pom.xml b/powertools-core/pom.xml index cf9ad45d1..2bf788edc 100644 --- a/powertools-core/pom.xml +++ b/powertools-core/pom.xml @@ -89,4 +89,13 @@ + + + + src/main/resources + true + + + + \ No newline at end of file diff --git a/powertools-core/src/main/java/software/amazon/lambda/powertools/core/internal/UserAgentConfigurer.java b/powertools-core/src/main/java/software/amazon/lambda/powertools/core/internal/UserAgentConfigurer.java new file mode 100644 index 000000000..2b93e9d5d --- /dev/null +++ b/powertools-core/src/main/java/software/amazon/lambda/powertools/core/internal/UserAgentConfigurer.java @@ -0,0 +1,90 @@ +package software.amazon.lambda.powertools.core.internal; + +import com.sun.org.slf4j.internal.Logger; +import com.sun.org.slf4j.internal.LoggerFactory; + +import java.io.FileInputStream; +import java.io.IOException; +import java.net.URL; +import java.util.Properties; + +import static software.amazon.lambda.powertools.core.internal.SystemWrapper.getenv; + +public class UserAgentConfigurer { + + public static final String NA = "NA"; + public static final String VERSION_KEY = "powertools.version"; + public static final String PT_FEATURE_VARIABLE = "${PT_FEATURE}"; + public static final String PT_EXEC_ENV_VARIABLE = "${PT_EXEC_ENV}"; + public static final String VERSION_PROPERTIES_FILENAME = "version.properties"; + public static final String AWS_EXECUTION_ENV = "AWS_EXECUTION_ENV"; + private static final Logger LOG = LoggerFactory.getLogger(UserAgentConfigurer.class); + private static final String NO_OP = "no-op"; + private static String PT_VERSION = getProjectVersion(); + private static String USER_AGENT_PATTERN = "PT/" + PT_FEATURE_VARIABLE + "/" + PT_VERSION + " PTEnv/" + PT_EXEC_ENV_VARIABLE; + + /** + * Retrieves the project version from the version.properties file + * + * @return the project version + */ + static String getProjectVersion() { + return getVersionFromProperties(VERSION_PROPERTIES_FILENAME, VERSION_KEY); + } + + + /** + * Retrieves the project version from a properties file. + * The file should be in the resources folder. + * The version is retrieved from the property with the given key. + * + * @param propertyFileName the name of the properties file + * @param versionKey the key of the property that contains the version + * @return the version of the project as configured in the given properties file + */ + static String getVersionFromProperties(String propertyFileName, String versionKey) { + + URL propertiesFileURI = Thread.currentThread().getContextClassLoader().getResource(propertyFileName); + if (propertiesFileURI != null) { + try (FileInputStream fis = new FileInputStream(propertiesFileURI.getPath())) { + Properties properties = new Properties(); + properties.load(fis); + String version = properties.getProperty(versionKey); + if (version != null && !version.isEmpty()) { + return version; + } + } catch (IOException e) { + LOG.warn("Unable to read {} file. Using default version.", propertyFileName); + LOG.debug("Exception:", e); + } + } + return NA; + } + + /** + * Retrieves the user agent string for the Powertools for AWS Lambda. + * It follows the pattern PT/{PT_FEATURE}/{PT_VERSION} PTEnv/{PT_EXEC_ENV} + * The version of the project is automatically retrieved. + * The PT_EXEC_ENV is automatically retrieved from the AWS_EXECUTION_ENV environment variable. + * If it AWS_EXECUTION_ENV is not set, PT_EXEC_ENV defaults to "NA" + * + * @param ptFeature a custom feature to be added to the user agent string (e.g. idempotency). + * If null or empty, the default PT_FEATURE is used. + * The default PT_FEATURE is "no-op". + * @return the user agent string + */ + public static String getUserAgent(String ptFeature) { + + String awsExecutionEnv = getenv(AWS_EXECUTION_ENV); + String ptExecEnv = awsExecutionEnv != null ? awsExecutionEnv : NA; + String userAgent = USER_AGENT_PATTERN.replace(PT_EXEC_ENV_VARIABLE, ptExecEnv); + + if (ptFeature == null || ptFeature.isEmpty()) { + ptFeature = NO_OP; + } + return userAgent + .replace(PT_FEATURE_VARIABLE, ptFeature) + .replace(PT_EXEC_ENV_VARIABLE, ptExecEnv); + } + +} diff --git a/powertools-core/src/main/resources/version.properties b/powertools-core/src/main/resources/version.properties new file mode 100644 index 000000000..3063b3a71 --- /dev/null +++ b/powertools-core/src/main/resources/version.properties @@ -0,0 +1 @@ +powertools.version=${project.version} \ No newline at end of file diff --git a/powertools-core/src/test/java/software/amazon/lambda/powertools/core/internal/UserAgentConfigurerTest.java b/powertools-core/src/test/java/software/amazon/lambda/powertools/core/internal/UserAgentConfigurerTest.java new file mode 100644 index 000000000..82988870c --- /dev/null +++ b/powertools-core/src/test/java/software/amazon/lambda/powertools/core/internal/UserAgentConfigurerTest.java @@ -0,0 +1,102 @@ +package software.amazon.lambda.powertools.core.internal; + +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; + +import java.io.File; +import java.util.regex.Pattern; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mockStatic; +import static software.amazon.lambda.powertools.core.internal.SystemWrapper.getenv; +import static software.amazon.lambda.powertools.core.internal.UserAgentConfigurer.VERSION_KEY; +import static software.amazon.lambda.powertools.core.internal.UserAgentConfigurer.getVersionFromProperties; +import static software.amazon.lambda.powertools.core.internal.UserAgentConfigurer.VERSION_PROPERTIES_FILENAME; +import static software.amazon.lambda.powertools.core.internal.UserAgentConfigurer.AWS_EXECUTION_ENV; + + + +public class UserAgentConfigurerTest { + + private static final String SEM_VER_PATTERN = "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$"; + private static final String VERSION = UserAgentConfigurer.getProjectVersion(); + + + @Test + public void testGetVersion() { + + assertThat(VERSION).isNotNull(); + assertThat(VERSION).isNotEmpty(); + assertThat(Pattern.matches(SEM_VER_PATTERN, VERSION)).isTrue(); + } + + @Test + public void testGetVersionFromProperties_WrongKey() { + String version = getVersionFromProperties(VERSION_PROPERTIES_FILENAME, "some invalid key"); + + assertThat(version).isNotNull(); + assertThat(version).isEqualTo("NA"); + } + + @Test + public void testGetVersionFromProperties_FileNotExist() { + String version = getVersionFromProperties("some file", VERSION_KEY); + + assertThat(version).isNotNull(); + assertThat(version).isEqualTo("NA"); + } + + @Test + public void testGetVersionFromProperties_InvalidFile() { + File f = new File(Thread.currentThread().getContextClassLoader().getResource("unreadable.properties").getPath()); + f.setReadable(false); + + String version = getVersionFromProperties("unreadable.properties", VERSION_KEY); + + assertThat(version).isEqualTo("NA"); + } + + @Test + public void testGetVersionFromProperties_EmptyVersion() { + String version = getVersionFromProperties("test.properties", VERSION_KEY); + + assertThat(version).isEqualTo("NA"); + } + + @Test + public void testGetUserAgent() { + String userAgent = UserAgentConfigurer.getUserAgent("test-feature"); + + assertThat(userAgent).isNotNull(); + assertThat(userAgent).isEqualTo("PT/test-feature/" + VERSION + " PTEnv/NA"); + + } + + @Test + public void testGetUserAgent_NoFeature() { + String userAgent = UserAgentConfigurer.getUserAgent(""); + + assertThat(userAgent).isNotNull(); + assertThat(userAgent).isEqualTo("PT/no-op/" + VERSION + " PTEnv/NA"); + } + + @Test + public void testGetUserAgent_NullFeature() { + String userAgent = UserAgentConfigurer.getUserAgent(null); + + assertThat(userAgent).isNotNull(); + assertThat(userAgent).isEqualTo("PT/no-op/" + VERSION + " PTEnv/NA"); + } + + @Test + public void testGetUserAgent_SetAWSExecutionEnv() { + try (MockedStatic mockedSystemWrapper = mockStatic(SystemWrapper.class)) { + mockedSystemWrapper.when(() -> getenv(AWS_EXECUTION_ENV)).thenReturn("AWS_Lambda_java8"); + String userAgent = UserAgentConfigurer.getUserAgent("test-feature"); + + assertThat(userAgent).isNotNull(); + assertThat(userAgent).isEqualTo("PT/test-feature/" + VERSION + " PTEnv/AWS_Lambda_java8"); + } + } + +} diff --git a/powertools-core/src/test/resources/test.properties b/powertools-core/src/test/resources/test.properties new file mode 100644 index 000000000..65756b8dd --- /dev/null +++ b/powertools-core/src/test/resources/test.properties @@ -0,0 +1 @@ +powertools.version= \ No newline at end of file diff --git a/powertools-core/src/test/resources/unreadable.properties b/powertools-core/src/test/resources/unreadable.properties new file mode 100644 index 000000000..3063b3a71 --- /dev/null +++ b/powertools-core/src/test/resources/unreadable.properties @@ -0,0 +1 @@ +powertools.version=${project.version} \ No newline at end of file diff --git a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/persistence/DynamoDBPersistenceStore.java b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/persistence/DynamoDBPersistenceStore.java index 47ddf4c5c..1f1542a3f 100644 --- a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/persistence/DynamoDBPersistenceStore.java +++ b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/persistence/DynamoDBPersistenceStore.java @@ -16,12 +16,15 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider; +import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; +import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption; import software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; import software.amazon.awssdk.services.dynamodb.DynamoDbClientBuilder; import software.amazon.awssdk.services.dynamodb.model.*; import software.amazon.awssdk.utils.StringUtils; +import software.amazon.lambda.powertools.core.internal.UserAgentConfigurer; import software.amazon.lambda.powertools.idempotency.Constants; import software.amazon.lambda.powertools.idempotency.exceptions.IdempotencyItemAlreadyExistsException; import software.amazon.lambda.powertools.idempotency.exceptions.IdempotencyItemNotFoundException; @@ -47,6 +50,7 @@ public class DynamoDBPersistenceStore extends BasePersistenceStore implements PersistenceStore { private static final Logger LOG = LoggerFactory.getLogger(DynamoDBPersistenceStore.class); + public static final String IDEMPOTENCY = "idempotency"; private final String tableName; private final String keyAttr; @@ -90,13 +94,14 @@ private DynamoDBPersistenceStore(String tableName, if (idempotencyDisabledEnv == null || idempotencyDisabledEnv.equalsIgnoreCase("false")) { DynamoDbClientBuilder ddbBuilder = DynamoDbClient.builder() .httpClient(UrlConnectionHttpClient.builder().build()) + .overrideConfiguration(ClientOverrideConfiguration.builder().putAdvancedOption(SdkAdvancedClientOption.USER_AGENT_SUFFIX, UserAgentConfigurer.getUserAgent(IDEMPOTENCY)).build()) .region(Region.of(System.getenv(AWS_REGION_ENV))); // AWS_LAMBDA_INITIALIZATION_TYPE has two values on-demand and snap-start // when using snap-start mode, the env var creds provider isn't used and causes a fatal error if set // fall back to the default provider chain if the mode is anything other than on-demand. String initializationType = System.getenv().get(AWS_LAMBDA_INITIALIZATION_TYPE); - if (initializationType != null && initializationType.equals(ON_DEMAND)) { + if (initializationType != null && initializationType.equals(ON_DEMAND)) { ddbBuilder.credentialsProvider(EnvironmentVariableCredentialsProvider.create()); } diff --git a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/AppConfigProvider.java b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/AppConfigProvider.java index e0255125d..29302123c 100644 --- a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/AppConfigProvider.java +++ b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/AppConfigProvider.java @@ -2,6 +2,8 @@ import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider; import software.amazon.awssdk.core.SdkSystemSetting; +import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; +import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption; import software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.appconfigdata.AppConfigDataClient; @@ -10,6 +12,7 @@ import software.amazon.awssdk.services.appconfigdata.model.GetLatestConfigurationResponse; import software.amazon.awssdk.services.appconfigdata.model.StartConfigurationSessionRequest; import software.amazon.lambda.powertools.core.internal.LambdaConstants; +import software.amazon.lambda.powertools.core.internal.UserAgentConfigurer; import software.amazon.lambda.powertools.parameters.cache.CacheManager; import software.amazon.lambda.powertools.parameters.transform.TransformationManager; @@ -146,13 +149,15 @@ public AppConfigProvider build() { if (client == null) { AppConfigDataClientBuilder appConfigDataClientBuilder = AppConfigDataClient.builder() .httpClientBuilder(UrlConnectionHttpClient.builder()) - .region(Region.of(System.getenv(SdkSystemSetting.AWS_REGION.environmentVariable()))); + .region(Region.of(System.getenv(SdkSystemSetting.AWS_REGION.environmentVariable()))) + .overrideConfiguration(ClientOverrideConfiguration.builder() + .putAdvancedOption(SdkAdvancedClientOption.USER_AGENT_SUFFIX, UserAgentConfigurer.getUserAgent(PARAMETERS)).build()); // AWS_LAMBDA_INITIALIZATION_TYPE has two values on-demand and snap-start // when using snap-start mode, the env var creds provider isn't used and causes a fatal error if set // fall back to the default provider chain if the mode is anything other than on-demand. String initializationType = System.getenv().get(AWS_LAMBDA_INITIALIZATION_TYPE); - if (initializationType != null && initializationType.equals(LambdaConstants.ON_DEMAND)) { + if (initializationType != null && initializationType.equals(LambdaConstants.ON_DEMAND)) { appConfigDataClientBuilder.credentialsProvider(EnvironmentVariableCredentialsProvider.create()); } diff --git a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/BaseProvider.java b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/BaseProvider.java index fb539f850..200c0184a 100644 --- a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/BaseProvider.java +++ b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/BaseProvider.java @@ -31,6 +31,7 @@ */ @NotThreadSafe public abstract class BaseProvider implements ParamProvider { + public static final String PARAMETERS = "parameters"; protected final CacheManager cacheManager; private TransformationManager transformationManager; diff --git a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/DynamoDbProvider.java b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/DynamoDbProvider.java index 1b77aed88..da4c5b18f 100644 --- a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/DynamoDbProvider.java +++ b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/DynamoDbProvider.java @@ -2,6 +2,8 @@ import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider; import software.amazon.awssdk.core.SdkSystemSetting; +import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; +import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption; import software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; @@ -12,6 +14,7 @@ import software.amazon.awssdk.services.dynamodb.model.QueryRequest; import software.amazon.awssdk.services.dynamodb.model.QueryResponse; import software.amazon.lambda.powertools.core.internal.LambdaConstants; +import software.amazon.lambda.powertools.core.internal.UserAgentConfigurer; import software.amazon.lambda.powertools.parameters.cache.CacheManager; import software.amazon.lambda.powertools.parameters.exception.DynamoDbProviderSchemaException; import software.amazon.lambda.powertools.parameters.transform.TransformationManager; @@ -192,7 +195,8 @@ public DynamoDbProvider.Builder withTransformationManager(TransformationManager private static DynamoDbClient createClient() { DynamoDbClientBuilder dynamoDbClientBuilder = DynamoDbClient.builder() .httpClientBuilder(UrlConnectionHttpClient.builder()) - .region(Region.of(System.getenv(SdkSystemSetting.AWS_REGION.environmentVariable()))); + .region(Region.of(System.getenv(SdkSystemSetting.AWS_REGION.environmentVariable()))) + .overrideConfiguration(ClientOverrideConfiguration.builder().putAdvancedOption(SdkAdvancedClientOption.USER_AGENT_SUFFIX, UserAgentConfigurer.getUserAgent(PARAMETERS)).build()); // AWS_LAMBDA_INITIALIZATION_TYPE has two values on-demand and snap-start // when using snap-start mode, the env var creds provider isn't used and causes a fatal error if set diff --git a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/SSMProvider.java b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/SSMProvider.java index 2eb2d4199..56dd592a1 100644 --- a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/SSMProvider.java +++ b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/SSMProvider.java @@ -15,6 +15,8 @@ import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider; import software.amazon.awssdk.core.SdkSystemSetting; +import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; +import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption; import software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.ssm.SsmClient; @@ -24,6 +26,7 @@ import software.amazon.awssdk.services.ssm.model.GetParametersByPathResponse; import software.amazon.awssdk.utils.StringUtils; import software.amazon.lambda.powertools.core.internal.LambdaConstants; +import software.amazon.lambda.powertools.core.internal.UserAgentConfigurer; import software.amazon.lambda.powertools.parameters.cache.CacheManager; import software.amazon.lambda.powertools.parameters.transform.TransformationManager; import software.amazon.lambda.powertools.parameters.transform.Transformer; @@ -285,7 +288,9 @@ public SSMProvider.Builder withClient(SsmClient client) { private static SsmClient createClient() { SsmClientBuilder ssmClientBuilder = SsmClient.builder() .httpClientBuilder(UrlConnectionHttpClient.builder()) - .region(Region.of(System.getenv(SdkSystemSetting.AWS_REGION.environmentVariable()))); + .region(Region.of(System.getenv(SdkSystemSetting.AWS_REGION.environmentVariable()))) + .overrideConfiguration(ClientOverrideConfiguration.builder().putAdvancedOption(SdkAdvancedClientOption.USER_AGENT_SUFFIX, UserAgentConfigurer.getUserAgent(PARAMETERS)).build()); + ; // AWS_LAMBDA_INITIALIZATION_TYPE has two values on-demand and snap-start // when using snap-start mode, the env var creds provider isn't used and causes a fatal error if set diff --git a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/SecretsProvider.java b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/SecretsProvider.java index ea8b5a9d0..b6e4f475f 100644 --- a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/SecretsProvider.java +++ b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/SecretsProvider.java @@ -15,12 +15,15 @@ import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider; import software.amazon.awssdk.core.SdkSystemSetting; +import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; +import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption; import software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient; import software.amazon.awssdk.services.secretsmanager.SecretsManagerClientBuilder; import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueRequest; import software.amazon.lambda.powertools.core.internal.LambdaConstants; +import software.amazon.lambda.powertools.core.internal.UserAgentConfigurer; import software.amazon.lambda.powertools.parameters.cache.CacheManager; import software.amazon.lambda.powertools.parameters.transform.TransformationManager; import software.amazon.lambda.powertools.parameters.transform.Transformer; @@ -193,7 +196,8 @@ public Builder withClient(SecretsManagerClient client) { private static SecretsManagerClient createClient() { SecretsManagerClientBuilder secretsManagerClientBuilder = SecretsManagerClient.builder() .httpClientBuilder(UrlConnectionHttpClient.builder()) - .region(Region.of(System.getenv(SdkSystemSetting.AWS_REGION.environmentVariable()))); + .region(Region.of(System.getenv(SdkSystemSetting.AWS_REGION.environmentVariable()))) + .overrideConfiguration(ClientOverrideConfiguration.builder().putAdvancedOption(SdkAdvancedClientOption.USER_AGENT_SUFFIX, UserAgentConfigurer.getUserAgent(PARAMETERS)).build()); // AWS_LAMBDA_INITIALIZATION_TYPE has two values on-demand and snap-start // when using snap-start mode, the env var creds provider isn't used and causes a fatal error if set diff --git a/powertools-sqs/src/main/java/software/amazon/lambda/powertools/sqs/SqsUtils.java b/powertools-sqs/src/main/java/software/amazon/lambda/powertools/sqs/SqsUtils.java index 9fff4dc6f..bf79c6602 100644 --- a/powertools-sqs/src/main/java/software/amazon/lambda/powertools/sqs/SqsUtils.java +++ b/powertools-sqs/src/main/java/software/amazon/lambda/powertools/sqs/SqsUtils.java @@ -13,25 +13,26 @@ */ package software.amazon.lambda.powertools.sqs; -import java.lang.reflect.Constructor; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.Queue; -import java.util.function.Function; -import java.util.stream.Collectors; - import com.amazonaws.services.lambda.runtime.events.SQSEvent; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; +import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.sqs.SqsClient; +import software.amazon.lambda.powertools.core.internal.UserAgentConfigurer; import software.amazon.lambda.powertools.sqs.exception.SkippedMessageDueToFailedBatchException; import software.amazon.lambda.powertools.sqs.internal.BatchContext; -import software.amazon.payloadoffloading.PayloadS3Pointer; import software.amazon.lambda.powertools.sqs.internal.SqsLargeMessageAspect; +import software.amazon.payloadoffloading.PayloadS3Pointer; + +import java.lang.reflect.Constructor; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; import static com.amazonaws.services.lambda.runtime.events.SQSEvent.SQSMessage; import static software.amazon.lambda.powertools.sqs.internal.SqsLargeMessageAspect.processMessages; @@ -43,6 +44,7 @@ public final class SqsUtils { private static final Logger LOG = LoggerFactory.getLogger(SqsUtils.class); private static final ObjectMapper objectMapper = new ObjectMapper(); + public static final String SQS = "sqs"; private static SqsClient client; private static S3Client s3Client; @@ -491,8 +493,9 @@ public static List batchProcessor(final SQSEvent event, final Class... nonRetryableExceptions) { final List handlerReturn = new ArrayList<>(); - if(client == null) { - client = SqsClient.create(); + if (client == null) { + client = (SqsClient) SqsClient.builder() + .overrideConfiguration(ClientOverrideConfiguration.builder().putAdvancedOption(SdkAdvancedClientOption.USER_AGENT_SUFFIX, UserAgentConfigurer.getUserAgent(SQS)).build()); } BatchContext batchContext = new BatchContext(client); @@ -576,8 +579,9 @@ public static ObjectMapper objectMapper() { } public static S3Client s3Client() { - if(null == s3Client) { - SqsUtils.s3Client = S3Client.create(); + if (null == s3Client) { + s3Client = (S3Client) S3Client.builder(). + overrideConfiguration(ClientOverrideConfiguration.builder().putAdvancedOption(SdkAdvancedClientOption.USER_AGENT_SUFFIX, UserAgentConfigurer.getUserAgent(SQS)).build()); } return s3Client; From b1809ccbd7d9dea551fcbbc9226abe85a85ba585 Mon Sep 17 00:00:00 2001 From: Eleni Dimitropoulou <12170229+eldimi@users.noreply.github.com> Date: Fri, 21 Jul 2023 17:31:57 +0300 Subject: [PATCH 2/5] fix wrong import for logger --- pom.xml | 1 - powertools-core/pom.xml | 5 +++++ .../lambda/powertools/core/internal/UserAgentConfigurer.java | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 7b84bc8b6..197e84a91 100644 --- a/pom.xml +++ b/pom.xml @@ -519,7 +519,6 @@ @{argLine} --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED - --add-exports=java.xml.crypto/com.sun.org.slf4j.internal=ALL-UNNAMED diff --git a/powertools-core/pom.xml b/powertools-core/pom.xml index 2bf788edc..3e31e0557 100644 --- a/powertools-core/pom.xml +++ b/powertools-core/pom.xml @@ -50,6 +50,11 @@ org.aspectj aspectjrt + + org.apache.logging.log4j + log4j-slf4j2-impl + ${log4j.version} + diff --git a/powertools-core/src/main/java/software/amazon/lambda/powertools/core/internal/UserAgentConfigurer.java b/powertools-core/src/main/java/software/amazon/lambda/powertools/core/internal/UserAgentConfigurer.java index 2b93e9d5d..87af89087 100644 --- a/powertools-core/src/main/java/software/amazon/lambda/powertools/core/internal/UserAgentConfigurer.java +++ b/powertools-core/src/main/java/software/amazon/lambda/powertools/core/internal/UserAgentConfigurer.java @@ -1,7 +1,7 @@ package software.amazon.lambda.powertools.core.internal; -import com.sun.org.slf4j.internal.Logger; -import com.sun.org.slf4j.internal.LoggerFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.FileInputStream; import java.io.IOException; From 3bf973ca23373cda3eb02d2f9b180dbab34a5003 Mon Sep 17 00:00:00 2001 From: Eleni Dimitropoulou <12170229+eldimi@users.noreply.github.com> Date: Mon, 24 Jul 2023 18:23:05 +0300 Subject: [PATCH 3/5] fix review comments: Add comments and javadoc for readability, rename class --- powertools-core/pom.xml | 2 +- ...igurer.java => UserAgentConfigurator.java} | 8 +++++--- .../resources-filtered/version.properties | 9 +++++++++ .../src/main/resources/version.properties | 1 - ...st.java => UserAgentConfiguratorTest.java} | 20 +++++++++---------- .../src/test/resources/unreadable.properties | 3 ++- .../persistence/DynamoDBPersistenceStore.java | 4 ++-- .../parameters/AppConfigProvider.java | 3 ++- .../parameters/DynamoDbProvider.java | 4 ++-- .../powertools/parameters/SSMProvider.java | 4 ++-- .../parameters/SecretsProvider.java | 4 ++-- .../lambda/powertools/sqs/SqsUtils.java | 6 +++--- 12 files changed, 40 insertions(+), 28 deletions(-) rename powertools-core/src/main/java/software/amazon/lambda/powertools/core/internal/{UserAgentConfigurer.java => UserAgentConfigurator.java} (95%) create mode 100644 powertools-core/src/main/resources-filtered/version.properties delete mode 100644 powertools-core/src/main/resources/version.properties rename powertools-core/src/test/java/software/amazon/lambda/powertools/core/internal/{UserAgentConfigurerTest.java => UserAgentConfiguratorTest.java} (84%) diff --git a/powertools-core/pom.xml b/powertools-core/pom.xml index 3e31e0557..da3922381 100644 --- a/powertools-core/pom.xml +++ b/powertools-core/pom.xml @@ -97,7 +97,7 @@ - src/main/resources + src/main/resources-filtered true diff --git a/powertools-core/src/main/java/software/amazon/lambda/powertools/core/internal/UserAgentConfigurer.java b/powertools-core/src/main/java/software/amazon/lambda/powertools/core/internal/UserAgentConfigurator.java similarity index 95% rename from powertools-core/src/main/java/software/amazon/lambda/powertools/core/internal/UserAgentConfigurer.java rename to powertools-core/src/main/java/software/amazon/lambda/powertools/core/internal/UserAgentConfigurator.java index 87af89087..a1c21afa4 100644 --- a/powertools-core/src/main/java/software/amazon/lambda/powertools/core/internal/UserAgentConfigurer.java +++ b/powertools-core/src/main/java/software/amazon/lambda/powertools/core/internal/UserAgentConfigurator.java @@ -10,7 +10,10 @@ import static software.amazon.lambda.powertools.core.internal.SystemWrapper.getenv; -public class UserAgentConfigurer { +/** + * Can be used to create a string that can server as a User-Agent suffix in requests made with the AWS SDK clients + */ +public class UserAgentConfigurator { public static final String NA = "NA"; public static final String VERSION_KEY = "powertools.version"; @@ -18,7 +21,7 @@ public class UserAgentConfigurer { public static final String PT_EXEC_ENV_VARIABLE = "${PT_EXEC_ENV}"; public static final String VERSION_PROPERTIES_FILENAME = "version.properties"; public static final String AWS_EXECUTION_ENV = "AWS_EXECUTION_ENV"; - private static final Logger LOG = LoggerFactory.getLogger(UserAgentConfigurer.class); + private static final Logger LOG = LoggerFactory.getLogger(UserAgentConfigurator.class); private static final String NO_OP = "no-op"; private static String PT_VERSION = getProjectVersion(); private static String USER_AGENT_PATTERN = "PT/" + PT_FEATURE_VARIABLE + "/" + PT_VERSION + " PTEnv/" + PT_EXEC_ENV_VARIABLE; @@ -86,5 +89,4 @@ public static String getUserAgent(String ptFeature) { .replace(PT_FEATURE_VARIABLE, ptFeature) .replace(PT_EXEC_ENV_VARIABLE, ptExecEnv); } - } diff --git a/powertools-core/src/main/resources-filtered/version.properties b/powertools-core/src/main/resources-filtered/version.properties new file mode 100644 index 000000000..1d835a456 --- /dev/null +++ b/powertools-core/src/main/resources-filtered/version.properties @@ -0,0 +1,9 @@ +# The filtered properties can have variables that are filled in y system properties or project properties. +# See https://maven.apache.org/plugins/maven-resources-plugin/examples/filter.html +# +# The values are replaced before copying the resources to the main output directory. Therefore, ass soon as the build phase is completed, +# the values should have been replaced if the properties are available and if 'filtering' is set to true in the pom.xml +# +# +# The ${project.version} is retrieved from the respective pom.xml property +powertools.version=${project.version} \ No newline at end of file diff --git a/powertools-core/src/main/resources/version.properties b/powertools-core/src/main/resources/version.properties deleted file mode 100644 index 3063b3a71..000000000 --- a/powertools-core/src/main/resources/version.properties +++ /dev/null @@ -1 +0,0 @@ -powertools.version=${project.version} \ No newline at end of file diff --git a/powertools-core/src/test/java/software/amazon/lambda/powertools/core/internal/UserAgentConfigurerTest.java b/powertools-core/src/test/java/software/amazon/lambda/powertools/core/internal/UserAgentConfiguratorTest.java similarity index 84% rename from powertools-core/src/test/java/software/amazon/lambda/powertools/core/internal/UserAgentConfigurerTest.java rename to powertools-core/src/test/java/software/amazon/lambda/powertools/core/internal/UserAgentConfiguratorTest.java index 82988870c..a0ae6ad53 100644 --- a/powertools-core/src/test/java/software/amazon/lambda/powertools/core/internal/UserAgentConfigurerTest.java +++ b/powertools-core/src/test/java/software/amazon/lambda/powertools/core/internal/UserAgentConfiguratorTest.java @@ -9,17 +9,17 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mockStatic; import static software.amazon.lambda.powertools.core.internal.SystemWrapper.getenv; -import static software.amazon.lambda.powertools.core.internal.UserAgentConfigurer.VERSION_KEY; -import static software.amazon.lambda.powertools.core.internal.UserAgentConfigurer.getVersionFromProperties; -import static software.amazon.lambda.powertools.core.internal.UserAgentConfigurer.VERSION_PROPERTIES_FILENAME; -import static software.amazon.lambda.powertools.core.internal.UserAgentConfigurer.AWS_EXECUTION_ENV; +import static software.amazon.lambda.powertools.core.internal.UserAgentConfigurator.VERSION_KEY; +import static software.amazon.lambda.powertools.core.internal.UserAgentConfigurator.getVersionFromProperties; +import static software.amazon.lambda.powertools.core.internal.UserAgentConfigurator.VERSION_PROPERTIES_FILENAME; +import static software.amazon.lambda.powertools.core.internal.UserAgentConfigurator.AWS_EXECUTION_ENV; -public class UserAgentConfigurerTest { +public class UserAgentConfiguratorTest { private static final String SEM_VER_PATTERN = "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$"; - private static final String VERSION = UserAgentConfigurer.getProjectVersion(); + private static final String VERSION = UserAgentConfigurator.getProjectVersion(); @Test @@ -65,7 +65,7 @@ public void testGetVersionFromProperties_EmptyVersion() { @Test public void testGetUserAgent() { - String userAgent = UserAgentConfigurer.getUserAgent("test-feature"); + String userAgent = UserAgentConfigurator.getUserAgent("test-feature"); assertThat(userAgent).isNotNull(); assertThat(userAgent).isEqualTo("PT/test-feature/" + VERSION + " PTEnv/NA"); @@ -74,7 +74,7 @@ public void testGetUserAgent() { @Test public void testGetUserAgent_NoFeature() { - String userAgent = UserAgentConfigurer.getUserAgent(""); + String userAgent = UserAgentConfigurator.getUserAgent(""); assertThat(userAgent).isNotNull(); assertThat(userAgent).isEqualTo("PT/no-op/" + VERSION + " PTEnv/NA"); @@ -82,7 +82,7 @@ public void testGetUserAgent_NoFeature() { @Test public void testGetUserAgent_NullFeature() { - String userAgent = UserAgentConfigurer.getUserAgent(null); + String userAgent = UserAgentConfigurator.getUserAgent(null); assertThat(userAgent).isNotNull(); assertThat(userAgent).isEqualTo("PT/no-op/" + VERSION + " PTEnv/NA"); @@ -92,7 +92,7 @@ public void testGetUserAgent_NullFeature() { public void testGetUserAgent_SetAWSExecutionEnv() { try (MockedStatic mockedSystemWrapper = mockStatic(SystemWrapper.class)) { mockedSystemWrapper.when(() -> getenv(AWS_EXECUTION_ENV)).thenReturn("AWS_Lambda_java8"); - String userAgent = UserAgentConfigurer.getUserAgent("test-feature"); + String userAgent = UserAgentConfigurator.getUserAgent("test-feature"); assertThat(userAgent).isNotNull(); assertThat(userAgent).isEqualTo("PT/test-feature/" + VERSION + " PTEnv/AWS_Lambda_java8"); diff --git a/powertools-core/src/test/resources/unreadable.properties b/powertools-core/src/test/resources/unreadable.properties index 3063b3a71..42ff4693f 100644 --- a/powertools-core/src/test/resources/unreadable.properties +++ b/powertools-core/src/test/resources/unreadable.properties @@ -1 +1,2 @@ -powertools.version=${project.version} \ No newline at end of file +# This is intentionally left empty +# It used during testing and is set to un-readable to fulfil the test purposes. \ No newline at end of file diff --git a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/persistence/DynamoDBPersistenceStore.java b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/persistence/DynamoDBPersistenceStore.java index 787dd9645..457ad0233 100644 --- a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/persistence/DynamoDBPersistenceStore.java +++ b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/persistence/DynamoDBPersistenceStore.java @@ -24,7 +24,7 @@ import software.amazon.awssdk.services.dynamodb.DynamoDbClientBuilder; import software.amazon.awssdk.services.dynamodb.model.*; import software.amazon.awssdk.utils.StringUtils; -import software.amazon.lambda.powertools.core.internal.UserAgentConfigurer; +import software.amazon.lambda.powertools.core.internal.UserAgentConfigurator; import software.amazon.lambda.powertools.idempotency.Constants; import software.amazon.lambda.powertools.idempotency.exceptions.IdempotencyItemAlreadyExistsException; import software.amazon.lambda.powertools.idempotency.exceptions.IdempotencyItemNotFoundException; @@ -94,7 +94,7 @@ private DynamoDBPersistenceStore(String tableName, if (idempotencyDisabledEnv == null || idempotencyDisabledEnv.equalsIgnoreCase("false")) { DynamoDbClientBuilder ddbBuilder = DynamoDbClient.builder() .httpClient(UrlConnectionHttpClient.builder().build()) - .overrideConfiguration(ClientOverrideConfiguration.builder().putAdvancedOption(SdkAdvancedClientOption.USER_AGENT_SUFFIX, UserAgentConfigurer.getUserAgent(IDEMPOTENCY)).build()) + .overrideConfiguration(ClientOverrideConfiguration.builder().putAdvancedOption(SdkAdvancedClientOption.USER_AGENT_SUFFIX, UserAgentConfigurator.getUserAgent(IDEMPOTENCY)).build()) .region(Region.of(System.getenv(AWS_REGION_ENV))); // AWS_LAMBDA_INITIALIZATION_TYPE has two values on-demand and snap-start diff --git a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/AppConfigProvider.java b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/AppConfigProvider.java index 29302123c..08270a229 100644 --- a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/AppConfigProvider.java +++ b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/AppConfigProvider.java @@ -12,6 +12,7 @@ import software.amazon.awssdk.services.appconfigdata.model.GetLatestConfigurationResponse; import software.amazon.awssdk.services.appconfigdata.model.StartConfigurationSessionRequest; import software.amazon.lambda.powertools.core.internal.LambdaConstants; +import software.amazon.lambda.powertools.core.internal.UserAgentConfigurator; import software.amazon.lambda.powertools.core.internal.UserAgentConfigurer; import software.amazon.lambda.powertools.parameters.cache.CacheManager; import software.amazon.lambda.powertools.parameters.transform.TransformationManager; @@ -151,7 +152,7 @@ public AppConfigProvider build() { .httpClientBuilder(UrlConnectionHttpClient.builder()) .region(Region.of(System.getenv(SdkSystemSetting.AWS_REGION.environmentVariable()))) .overrideConfiguration(ClientOverrideConfiguration.builder() - .putAdvancedOption(SdkAdvancedClientOption.USER_AGENT_SUFFIX, UserAgentConfigurer.getUserAgent(PARAMETERS)).build()); + .putAdvancedOption(SdkAdvancedClientOption.USER_AGENT_SUFFIX, UserAgentConfigurator.getUserAgent(PARAMETERS)).build()); // AWS_LAMBDA_INITIALIZATION_TYPE has two values on-demand and snap-start // when using snap-start mode, the env var creds provider isn't used and causes a fatal error if set diff --git a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/DynamoDbProvider.java b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/DynamoDbProvider.java index da4c5b18f..914dd84a4 100644 --- a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/DynamoDbProvider.java +++ b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/DynamoDbProvider.java @@ -14,7 +14,7 @@ import software.amazon.awssdk.services.dynamodb.model.QueryRequest; import software.amazon.awssdk.services.dynamodb.model.QueryResponse; import software.amazon.lambda.powertools.core.internal.LambdaConstants; -import software.amazon.lambda.powertools.core.internal.UserAgentConfigurer; +import software.amazon.lambda.powertools.core.internal.UserAgentConfigurator; import software.amazon.lambda.powertools.parameters.cache.CacheManager; import software.amazon.lambda.powertools.parameters.exception.DynamoDbProviderSchemaException; import software.amazon.lambda.powertools.parameters.transform.TransformationManager; @@ -196,7 +196,7 @@ private static DynamoDbClient createClient() { DynamoDbClientBuilder dynamoDbClientBuilder = DynamoDbClient.builder() .httpClientBuilder(UrlConnectionHttpClient.builder()) .region(Region.of(System.getenv(SdkSystemSetting.AWS_REGION.environmentVariable()))) - .overrideConfiguration(ClientOverrideConfiguration.builder().putAdvancedOption(SdkAdvancedClientOption.USER_AGENT_SUFFIX, UserAgentConfigurer.getUserAgent(PARAMETERS)).build()); + .overrideConfiguration(ClientOverrideConfiguration.builder().putAdvancedOption(SdkAdvancedClientOption.USER_AGENT_SUFFIX, UserAgentConfigurator.getUserAgent(PARAMETERS)).build()); // AWS_LAMBDA_INITIALIZATION_TYPE has two values on-demand and snap-start // when using snap-start mode, the env var creds provider isn't used and causes a fatal error if set diff --git a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/SSMProvider.java b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/SSMProvider.java index 56dd592a1..c19534646 100644 --- a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/SSMProvider.java +++ b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/SSMProvider.java @@ -26,7 +26,7 @@ import software.amazon.awssdk.services.ssm.model.GetParametersByPathResponse; import software.amazon.awssdk.utils.StringUtils; import software.amazon.lambda.powertools.core.internal.LambdaConstants; -import software.amazon.lambda.powertools.core.internal.UserAgentConfigurer; +import software.amazon.lambda.powertools.core.internal.UserAgentConfigurator; import software.amazon.lambda.powertools.parameters.cache.CacheManager; import software.amazon.lambda.powertools.parameters.transform.TransformationManager; import software.amazon.lambda.powertools.parameters.transform.Transformer; @@ -289,7 +289,7 @@ private static SsmClient createClient() { SsmClientBuilder ssmClientBuilder = SsmClient.builder() .httpClientBuilder(UrlConnectionHttpClient.builder()) .region(Region.of(System.getenv(SdkSystemSetting.AWS_REGION.environmentVariable()))) - .overrideConfiguration(ClientOverrideConfiguration.builder().putAdvancedOption(SdkAdvancedClientOption.USER_AGENT_SUFFIX, UserAgentConfigurer.getUserAgent(PARAMETERS)).build()); + .overrideConfiguration(ClientOverrideConfiguration.builder().putAdvancedOption(SdkAdvancedClientOption.USER_AGENT_SUFFIX, UserAgentConfigurator.getUserAgent(PARAMETERS)).build()); ; // AWS_LAMBDA_INITIALIZATION_TYPE has two values on-demand and snap-start diff --git a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/SecretsProvider.java b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/SecretsProvider.java index b6e4f475f..0dfbc0b0b 100644 --- a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/SecretsProvider.java +++ b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/SecretsProvider.java @@ -23,7 +23,7 @@ import software.amazon.awssdk.services.secretsmanager.SecretsManagerClientBuilder; import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueRequest; import software.amazon.lambda.powertools.core.internal.LambdaConstants; -import software.amazon.lambda.powertools.core.internal.UserAgentConfigurer; +import software.amazon.lambda.powertools.core.internal.UserAgentConfigurator; import software.amazon.lambda.powertools.parameters.cache.CacheManager; import software.amazon.lambda.powertools.parameters.transform.TransformationManager; import software.amazon.lambda.powertools.parameters.transform.Transformer; @@ -197,7 +197,7 @@ private static SecretsManagerClient createClient() { SecretsManagerClientBuilder secretsManagerClientBuilder = SecretsManagerClient.builder() .httpClientBuilder(UrlConnectionHttpClient.builder()) .region(Region.of(System.getenv(SdkSystemSetting.AWS_REGION.environmentVariable()))) - .overrideConfiguration(ClientOverrideConfiguration.builder().putAdvancedOption(SdkAdvancedClientOption.USER_AGENT_SUFFIX, UserAgentConfigurer.getUserAgent(PARAMETERS)).build()); + .overrideConfiguration(ClientOverrideConfiguration.builder().putAdvancedOption(SdkAdvancedClientOption.USER_AGENT_SUFFIX, UserAgentConfigurator.getUserAgent(PARAMETERS)).build()); // AWS_LAMBDA_INITIALIZATION_TYPE has two values on-demand and snap-start // when using snap-start mode, the env var creds provider isn't used and causes a fatal error if set diff --git a/powertools-sqs/src/main/java/software/amazon/lambda/powertools/sqs/SqsUtils.java b/powertools-sqs/src/main/java/software/amazon/lambda/powertools/sqs/SqsUtils.java index bf79c6602..b2b904bcf 100644 --- a/powertools-sqs/src/main/java/software/amazon/lambda/powertools/sqs/SqsUtils.java +++ b/powertools-sqs/src/main/java/software/amazon/lambda/powertools/sqs/SqsUtils.java @@ -22,7 +22,7 @@ import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.sqs.SqsClient; -import software.amazon.lambda.powertools.core.internal.UserAgentConfigurer; +import software.amazon.lambda.powertools.core.internal.UserAgentConfigurator; import software.amazon.lambda.powertools.sqs.exception.SkippedMessageDueToFailedBatchException; import software.amazon.lambda.powertools.sqs.internal.BatchContext; import software.amazon.lambda.powertools.sqs.internal.SqsLargeMessageAspect; @@ -495,7 +495,7 @@ public static List batchProcessor(final SQSEvent event, if (client == null) { client = (SqsClient) SqsClient.builder() - .overrideConfiguration(ClientOverrideConfiguration.builder().putAdvancedOption(SdkAdvancedClientOption.USER_AGENT_SUFFIX, UserAgentConfigurer.getUserAgent(SQS)).build()); + .overrideConfiguration(ClientOverrideConfiguration.builder().putAdvancedOption(SdkAdvancedClientOption.USER_AGENT_SUFFIX, UserAgentConfigurator.getUserAgent(SQS)).build()); } BatchContext batchContext = new BatchContext(client); @@ -581,7 +581,7 @@ public static ObjectMapper objectMapper() { public static S3Client s3Client() { if (null == s3Client) { s3Client = (S3Client) S3Client.builder(). - overrideConfiguration(ClientOverrideConfiguration.builder().putAdvancedOption(SdkAdvancedClientOption.USER_AGENT_SUFFIX, UserAgentConfigurer.getUserAgent(SQS)).build()); + overrideConfiguration(ClientOverrideConfiguration.builder().putAdvancedOption(SdkAdvancedClientOption.USER_AGENT_SUFFIX, UserAgentConfigurator.getUserAgent(SQS)).build()); } return s3Client; From 825b41cff8af3d57a2f8f348f554623b6aa80787 Mon Sep 17 00:00:00 2001 From: Eleni Dimitropoulou <12170229+eldimi@users.noreply.github.com> Date: Wed, 26 Jul 2023 17:39:28 +0300 Subject: [PATCH 4/5] fix typo --- .../src/main/resources-filtered/version.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/powertools-core/src/main/resources-filtered/version.properties b/powertools-core/src/main/resources-filtered/version.properties index 1d835a456..5e95fb588 100644 --- a/powertools-core/src/main/resources-filtered/version.properties +++ b/powertools-core/src/main/resources-filtered/version.properties @@ -1,7 +1,7 @@ -# The filtered properties can have variables that are filled in y system properties or project properties. +# The filtered properties can have variables that are filled in by system properties or project properties. # See https://maven.apache.org/plugins/maven-resources-plugin/examples/filter.html # -# The values are replaced before copying the resources to the main output directory. Therefore, ass soon as the build phase is completed, +# The values are replaced before copying the resources to the main output directory. Therefore, as soon as the build phase is completed, # the values should have been replaced if the properties are available and if 'filtering' is set to true in the pom.xml # # From ecaa919fc2927d438754600eed9a58f7a60d2277 Mon Sep 17 00:00:00 2001 From: Eleni Dimitropoulou <12170229+eldimi@users.noreply.github.com> Date: Thu, 27 Jul 2023 16:03:51 +0300 Subject: [PATCH 5/5] fix code smells and formatting issues --- .../core/internal/UserAgentConfigurator.java | 31 +++++-- .../internal/UserAgentConfiguratorTest.java | 88 ++++++++++++------- .../parameters/DynamoDbProvider.java | 6 +- .../lambda/powertools/sqs/SqsUtils.java | 21 +++-- 4 files changed, 96 insertions(+), 50 deletions(-) diff --git a/powertools-core/src/main/java/software/amazon/lambda/powertools/core/internal/UserAgentConfigurator.java b/powertools-core/src/main/java/software/amazon/lambda/powertools/core/internal/UserAgentConfigurator.java index a1c21afa4..354305d33 100644 --- a/powertools-core/src/main/java/software/amazon/lambda/powertools/core/internal/UserAgentConfigurator.java +++ b/powertools-core/src/main/java/software/amazon/lambda/powertools/core/internal/UserAgentConfigurator.java @@ -1,14 +1,28 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed 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 software.amazon.lambda.powertools.core.internal; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static software.amazon.lambda.powertools.core.internal.SystemWrapper.getenv; import java.io.FileInputStream; import java.io.IOException; import java.net.URL; import java.util.Properties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import static software.amazon.lambda.powertools.core.internal.SystemWrapper.getenv; /** * Can be used to create a string that can server as a User-Agent suffix in requests made with the AWS SDK clients @@ -23,8 +37,13 @@ public class UserAgentConfigurator { public static final String AWS_EXECUTION_ENV = "AWS_EXECUTION_ENV"; private static final Logger LOG = LoggerFactory.getLogger(UserAgentConfigurator.class); private static final String NO_OP = "no-op"; - private static String PT_VERSION = getProjectVersion(); - private static String USER_AGENT_PATTERN = "PT/" + PT_FEATURE_VARIABLE + "/" + PT_VERSION + " PTEnv/" + PT_EXEC_ENV_VARIABLE; + private static String ptVersion = getProjectVersion(); + private static String userAgentPattern = "PT/" + PT_FEATURE_VARIABLE + "/" + ptVersion + " PTEnv/" + + PT_EXEC_ENV_VARIABLE; + + private UserAgentConfigurator() { + throw new IllegalStateException("Utility class. Not meant to be instantiated"); + } /** * Retrieves the project version from the version.properties file @@ -80,7 +99,7 @@ public static String getUserAgent(String ptFeature) { String awsExecutionEnv = getenv(AWS_EXECUTION_ENV); String ptExecEnv = awsExecutionEnv != null ? awsExecutionEnv : NA; - String userAgent = USER_AGENT_PATTERN.replace(PT_EXEC_ENV_VARIABLE, ptExecEnv); + String userAgent = userAgentPattern.replace(PT_EXEC_ENV_VARIABLE, ptExecEnv); if (ptFeature == null || ptFeature.isEmpty()) { ptFeature = NO_OP; diff --git a/powertools-core/src/test/java/software/amazon/lambda/powertools/core/internal/UserAgentConfiguratorTest.java b/powertools-core/src/test/java/software/amazon/lambda/powertools/core/internal/UserAgentConfiguratorTest.java index a0ae6ad53..00110077f 100644 --- a/powertools-core/src/test/java/software/amazon/lambda/powertools/core/internal/UserAgentConfiguratorTest.java +++ b/powertools-core/src/test/java/software/amazon/lambda/powertools/core/internal/UserAgentConfiguratorTest.java @@ -1,54 +1,70 @@ -package software.amazon.lambda.powertools.core.internal; +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. + * Licensed 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 org.junit.jupiter.api.Test; -import org.mockito.MockedStatic; - -import java.io.File; -import java.util.regex.Pattern; +package software.amazon.lambda.powertools.core.internal; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mockStatic; import static software.amazon.lambda.powertools.core.internal.SystemWrapper.getenv; +import static software.amazon.lambda.powertools.core.internal.UserAgentConfigurator.AWS_EXECUTION_ENV; import static software.amazon.lambda.powertools.core.internal.UserAgentConfigurator.VERSION_KEY; -import static software.amazon.lambda.powertools.core.internal.UserAgentConfigurator.getVersionFromProperties; import static software.amazon.lambda.powertools.core.internal.UserAgentConfigurator.VERSION_PROPERTIES_FILENAME; -import static software.amazon.lambda.powertools.core.internal.UserAgentConfigurator.AWS_EXECUTION_ENV; - +import static software.amazon.lambda.powertools.core.internal.UserAgentConfigurator.getVersionFromProperties; +import java.io.File; +import java.util.Objects; +import java.util.regex.Pattern; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; -public class UserAgentConfiguratorTest { +class UserAgentConfiguratorTest { private static final String SEM_VER_PATTERN = "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$"; private static final String VERSION = UserAgentConfigurator.getProjectVersion(); @Test - public void testGetVersion() { + void testGetVersion() { - assertThat(VERSION).isNotNull(); - assertThat(VERSION).isNotEmpty(); + assertThat(VERSION) + .isNotNull() + .isNotEmpty(); assertThat(Pattern.matches(SEM_VER_PATTERN, VERSION)).isTrue(); } @Test - public void testGetVersionFromProperties_WrongKey() { + void testGetVersionFromProperties_WrongKey() { String version = getVersionFromProperties(VERSION_PROPERTIES_FILENAME, "some invalid key"); - assertThat(version).isNotNull(); - assertThat(version).isEqualTo("NA"); + assertThat(version) + .isNotNull() + .isEqualTo("NA"); } @Test - public void testGetVersionFromProperties_FileNotExist() { + void testGetVersionFromProperties_FileNotExist() { String version = getVersionFromProperties("some file", VERSION_KEY); - assertThat(version).isNotNull(); - assertThat(version).isEqualTo("NA"); + assertThat(version) + .isNotNull() + .isEqualTo("NA"); } @Test - public void testGetVersionFromProperties_InvalidFile() { - File f = new File(Thread.currentThread().getContextClassLoader().getResource("unreadable.properties").getPath()); + void testGetVersionFromProperties_InvalidFile() { + File f = new File(Objects.requireNonNull(Thread.currentThread().getContextClassLoader() + .getResource("unreadable.properties")).getPath()); f.setReadable(false); String version = getVersionFromProperties("unreadable.properties", VERSION_KEY); @@ -57,45 +73,49 @@ public void testGetVersionFromProperties_InvalidFile() { } @Test - public void testGetVersionFromProperties_EmptyVersion() { + void testGetVersionFromProperties_EmptyVersion() { String version = getVersionFromProperties("test.properties", VERSION_KEY); assertThat(version).isEqualTo("NA"); } @Test - public void testGetUserAgent() { + void testGetUserAgent() { String userAgent = UserAgentConfigurator.getUserAgent("test-feature"); - assertThat(userAgent).isNotNull(); - assertThat(userAgent).isEqualTo("PT/test-feature/" + VERSION + " PTEnv/NA"); + assertThat(userAgent) + .isNotNull() + .isEqualTo("PT/test-feature/" + VERSION + " PTEnv/NA"); } @Test - public void testGetUserAgent_NoFeature() { + void testGetUserAgent_NoFeature() { String userAgent = UserAgentConfigurator.getUserAgent(""); - assertThat(userAgent).isNotNull(); - assertThat(userAgent).isEqualTo("PT/no-op/" + VERSION + " PTEnv/NA"); + assertThat(userAgent) + .isNotNull() + .isEqualTo("PT/no-op/" + VERSION + " PTEnv/NA"); } @Test - public void testGetUserAgent_NullFeature() { + void testGetUserAgent_NullFeature() { String userAgent = UserAgentConfigurator.getUserAgent(null); - assertThat(userAgent).isNotNull(); - assertThat(userAgent).isEqualTo("PT/no-op/" + VERSION + " PTEnv/NA"); + assertThat(userAgent) + .isNotNull() + .isEqualTo("PT/no-op/" + VERSION + " PTEnv/NA"); } @Test - public void testGetUserAgent_SetAWSExecutionEnv() { + void testGetUserAgent_SetAWSExecutionEnv() { try (MockedStatic mockedSystemWrapper = mockStatic(SystemWrapper.class)) { mockedSystemWrapper.when(() -> getenv(AWS_EXECUTION_ENV)).thenReturn("AWS_Lambda_java8"); String userAgent = UserAgentConfigurator.getUserAgent("test-feature"); - assertThat(userAgent).isNotNull(); - assertThat(userAgent).isEqualTo("PT/test-feature/" + VERSION + " PTEnv/AWS_Lambda_java8"); + assertThat(userAgent) + .isNotNull() + .isEqualTo("PT/test-feature/" + VERSION + " PTEnv/AWS_Lambda_java8"); } } diff --git a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/DynamoDbProvider.java b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/DynamoDbProvider.java index 654cbfd33..499241927 100644 --- a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/DynamoDbProvider.java +++ b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/DynamoDbProvider.java @@ -23,7 +23,11 @@ import software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.dynamodb.DynamoDbClient; -import software.amazon.awssdk.services.dynamodb.model.*; +import software.amazon.awssdk.services.dynamodb.model.AttributeValue; +import software.amazon.awssdk.services.dynamodb.model.GetItemRequest; +import software.amazon.awssdk.services.dynamodb.model.GetItemResponse; +import software.amazon.awssdk.services.dynamodb.model.QueryRequest; +import software.amazon.awssdk.services.dynamodb.model.QueryResponse; import software.amazon.lambda.powertools.core.internal.UserAgentConfigurator; import software.amazon.lambda.powertools.parameters.cache.CacheManager; import software.amazon.lambda.powertools.parameters.exception.DynamoDbProviderSchemaException; diff --git a/powertools-sqs/src/main/java/software/amazon/lambda/powertools/sqs/SqsUtils.java b/powertools-sqs/src/main/java/software/amazon/lambda/powertools/sqs/SqsUtils.java index c8d83bd68..29050d6c8 100644 --- a/powertools-sqs/src/main/java/software/amazon/lambda/powertools/sqs/SqsUtils.java +++ b/powertools-sqs/src/main/java/software/amazon/lambda/powertools/sqs/SqsUtils.java @@ -41,17 +41,14 @@ * A class of helper functions to add additional functionality to {@link SQSEvent} processing. */ public final class SqsUtils { - private static final Logger LOG = LoggerFactory.getLogger(SqsUtils.class); - - private static final ObjectMapper objectMapper = new ObjectMapper(); public static final String SQS = "sqs"; + private static final Logger LOG = LoggerFactory.getLogger(SqsUtils.class); + private static final ObjectMapper objectMapper = new ObjectMapper(); + private static final String MESSAGE_GROUP_ID = "MessageGroupId"; private static SqsClient client; private static S3Client s3Client; - // The attribute on an SQS-FIFO message used to record the message group ID - private static final String MESSAGE_GROUP_ID = "MessageGroupId"; - private SqsUtils() { } @@ -500,7 +497,10 @@ public static List batchProcessor(final SQSEvent event, if (client == null) { client = (SqsClient) SqsClient.builder() - .overrideConfiguration(ClientOverrideConfiguration.builder().putAdvancedOption(SdkAdvancedClientOption.USER_AGENT_SUFFIX, UserAgentConfigurator.getUserAgent(SQS)).build()); + .overrideConfiguration(ClientOverrideConfiguration.builder() + .putAdvancedOption(SdkAdvancedClientOption.USER_AGENT_SUFFIX, + UserAgentConfigurator.getUserAgent(SQS)) + .build()); } BatchContext batchContext = new BatchContext(client); @@ -589,8 +589,11 @@ public static ObjectMapper objectMapper() { public static S3Client s3Client() { if (null == s3Client) { - s3Client = (S3Client) S3Client.builder(). - overrideConfiguration(ClientOverrideConfiguration.builder().putAdvancedOption(SdkAdvancedClientOption.USER_AGENT_SUFFIX, UserAgentConfigurator.getUserAgent(SQS)).build()); + s3Client = (S3Client) S3Client.builder() + .overrideConfiguration(ClientOverrideConfiguration.builder() + .putAdvancedOption(SdkAdvancedClientOption.USER_AGENT_SUFFIX, + UserAgentConfigurator.getUserAgent(SQS)) + .build()); SqsUtils.s3Client = S3Client.create(); }