* curl -X POST https://[REST-API-ID].execute-api.[REGION].amazonaws.com/Prod/helloidem/ -H "Content-Type: application/json" -d '{"address": "https://checkip.amazonaws.com"}' *@@ -52,7 +56,7 @@ public App(DynamoDbClient client) { *
* You can test the endpoint like this: * *
@@ -89,13 +103,12 @@ public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEv /** * Helper to retrieve the contents of the given URL and return them as a string. - * + ** We could also put the @Idempotent annotation here if we only wanted this sub-operation to be idempotent. Putting * it on the handler, however, reduces total execution time and saves us time! * * @param address The URL to fetch * @return The contents of the given URL - * * @throws IOException */ private String getPageContents(String address) throws IOException { diff --git a/examples/powertools-examples-idempotency/src/test/java/helloworld/AppTest.java b/examples/powertools-examples-idempotency/src/test/java/helloworld/AppTest.java index 7a5304e36..7f097906a 100644 --- a/examples/powertools-examples-idempotency/src/test/java/helloworld/AppTest.java +++ b/examples/powertools-examples-idempotency/src/test/java/helloworld/AppTest.java @@ -1,3 +1,17 @@ +/* + * 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 helloworld; import com.amazonaws.services.dynamodbv2.local.main.ServerRunner; @@ -5,6 +19,9 @@ import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent; import com.amazonaws.services.lambda.runtime.tests.EventLoader; +import java.io.IOException; +import java.net.ServerSocket; +import java.net.URI; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; @@ -16,23 +33,24 @@ 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 java.io.IOException; -import java.net.ServerSocket; -import java.net.URI; +import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition; +import software.amazon.awssdk.services.dynamodb.model.BillingMode; +import software.amazon.awssdk.services.dynamodb.model.CreateTableRequest; +import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement; +import software.amazon.awssdk.services.dynamodb.model.KeyType; +import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType; public class AppTest { + private static DynamoDbClient client; @Mock private Context context; private App app; - private static DynamoDbClient client; @BeforeAll public static void setupDynamoLocal() { int port = getFreePort(); try { - DynamoDBProxyServer dynamoProxy = ServerRunner.createServerFromCommandLineArgs(new String[]{ + DynamoDBProxyServer dynamoProxy = ServerRunner.createServerFromCommandLineArgs(new String[] { "-inMemory", "-port", Integer.toString(port) @@ -79,7 +97,8 @@ void setUp() { @Test public void testApp() { - APIGatewayProxyResponseEvent response = app.handleRequest(EventLoader.loadApiGatewayRestEvent("event.json"), context); + APIGatewayProxyResponseEvent response = + app.handleRequest(EventLoader.loadApiGatewayRestEvent("event.json"), context); Assertions.assertNotNull(response); Assertions.assertTrue(response.getBody().contains("hello world")); } diff --git a/examples/powertools-examples-parameters/src/main/java/org/demo/parameters/MyObject.java b/examples/powertools-examples-parameters/src/main/java/org/demo/parameters/MyObject.java index 2cf145284..d406ae3df 100644 --- a/examples/powertools-examples-parameters/src/main/java/org/demo/parameters/MyObject.java +++ b/examples/powertools-examples-parameters/src/main/java/org/demo/parameters/MyObject.java @@ -1,3 +1,17 @@ +/* + * 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 org.demo.parameters; public class MyObject { diff --git a/examples/powertools-examples-parameters/src/main/java/org/demo/parameters/ParametersFunction.java b/examples/powertools-examples-parameters/src/main/java/org/demo/parameters/ParametersFunction.java index f96352e86..5b691cfd9 100644 --- a/examples/powertools-examples-parameters/src/main/java/org/demo/parameters/ParametersFunction.java +++ b/examples/powertools-examples-parameters/src/main/java/org/demo/parameters/ParametersFunction.java @@ -1,15 +1,27 @@ +/* + * 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 org.demo.parameters; +import static java.time.temporal.ChronoUnit.SECONDS; +import static software.amazon.lambda.powertools.parameters.transform.Transformer.base64; +import static software.amazon.lambda.powertools.parameters.transform.Transformer.json; + import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent; import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import software.amazon.lambda.powertools.parameters.ParamManager; -import software.amazon.lambda.powertools.parameters.SSMProvider; -import software.amazon.lambda.powertools.parameters.SecretsProvider; - import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; @@ -17,10 +29,11 @@ import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; - -import static java.time.temporal.ChronoUnit.SECONDS; -import static software.amazon.lambda.powertools.parameters.transform.Transformer.base64; -import static software.amazon.lambda.powertools.parameters.transform.Transformer.json; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import software.amazon.lambda.powertools.parameters.ParamManager; +import software.amazon.lambda.powertools.parameters.SSMProvider; +import software.amazon.lambda.powertools.parameters.SecretsProvider; public class ParametersFunction implements RequestHandler
{ private final static Logger log = LogManager.getLogger(ParametersFunction.class); @@ -34,8 +47,10 @@ public class ParametersFunction implements RequestHandler allValues = ssmProvider.getMultiple("/powertools-java/sample"); String b64value = ssmProvider.withTransformation(base64).get("/powertools-java/sample/keybase64"); - Map secretJson = secretsProvider.withTransformation(json).get("/powertools-java/userpwd", Map.class); - MyObject secretJsonObj = secretsProvider.withMaxAge(42, SECONDS).withTransformation(json).get("/powertools-java/secretcode", MyObject.class); + Map secretJson = + secretsProvider.withTransformation(json).get("/powertools-java/userpwd", Map.class); + MyObject secretJsonObj = secretsProvider.withMaxAge(42, SECONDS).withTransformation(json) + .get("/powertools-java/secretcode", MyObject.class); @Override public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent input, Context context) { @@ -72,9 +87,9 @@ public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent in } } - private String getPageContents(String address) throws IOException{ + private String getPageContents(String address) throws IOException { URL url = new URL(address); - try(BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8"))) { + try (BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8"))) { return br.lines().collect(Collectors.joining(System.lineSeparator())); } } diff --git a/examples/powertools-examples-serialization/src/main/java/org/demo/serialization/APIGatewayRequestDeserializationFunction.java b/examples/powertools-examples-serialization/src/main/java/org/demo/serialization/APIGatewayRequestDeserializationFunction.java index 8c33baed9..e70b37959 100644 --- a/examples/powertools-examples-serialization/src/main/java/org/demo/serialization/APIGatewayRequestDeserializationFunction.java +++ b/examples/powertools-examples-serialization/src/main/java/org/demo/serialization/APIGatewayRequestDeserializationFunction.java @@ -1,19 +1,33 @@ +/* + * 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 org.demo.serialization; +import static software.amazon.lambda.powertools.utilities.EventDeserializer.extractDataFrom; + import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent; import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - import java.util.HashMap; import java.util.Map; - -import static software.amazon.lambda.powertools.utilities.EventDeserializer.extractDataFrom; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; -public class APIGatewayRequestDeserializationFunction implements RequestHandler { +public class APIGatewayRequestDeserializationFunction + implements RequestHandler { private final static Logger LOGGER = LogManager.getLogger(APIGatewayRequestDeserializationFunction.class); private static final Map HEADERS = new HashMap () {{ @@ -28,9 +42,9 @@ public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent ev LOGGER.info("product={}\n", product); return new APIGatewayProxyResponseEvent() - .withHeaders(HEADERS) - .withStatusCode(200) - .withBody("Received request for productId: " + product.getId()); + .withHeaders(HEADERS) + .withStatusCode(200) + .withBody("Received request for productId: " + product.getId()); } } diff --git a/examples/powertools-examples-serialization/src/main/java/org/demo/serialization/Product.java b/examples/powertools-examples-serialization/src/main/java/org/demo/serialization/Product.java index fb94a99f8..25bae34f6 100644 --- a/examples/powertools-examples-serialization/src/main/java/org/demo/serialization/Product.java +++ b/examples/powertools-examples-serialization/src/main/java/org/demo/serialization/Product.java @@ -1,3 +1,17 @@ +/* + * 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 org.demo.serialization; public class Product { diff --git a/examples/powertools-examples-serialization/src/main/java/org/demo/serialization/SQSEventDeserializationFunction.java b/examples/powertools-examples-serialization/src/main/java/org/demo/serialization/SQSEventDeserializationFunction.java index 129fe0243..36dbed074 100644 --- a/examples/powertools-examples-serialization/src/main/java/org/demo/serialization/SQSEventDeserializationFunction.java +++ b/examples/powertools-examples-serialization/src/main/java/org/demo/serialization/SQSEventDeserializationFunction.java @@ -1,15 +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 org.demo.serialization; +import static software.amazon.lambda.powertools.utilities.EventDeserializer.extractDataFrom; + import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.amazonaws.services.lambda.runtime.events.SQSEvent; +import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import java.util.List; - -import static software.amazon.lambda.powertools.utilities.EventDeserializer.extractDataFrom; - public class SQSEventDeserializationFunction implements RequestHandler { diff --git a/examples/powertools-examples-serialization/src/test/java/org/demo/serialization/APIGatewayRequestDeserializationFunctionTest.java b/examples/powertools-examples-serialization/src/test/java/org/demo/serialization/APIGatewayRequestDeserializationFunctionTest.java index 5d5da7ecc..ec8cdbd33 100644 --- a/examples/powertools-examples-serialization/src/test/java/org/demo/serialization/APIGatewayRequestDeserializationFunctionTest.java +++ b/examples/powertools-examples-serialization/src/test/java/org/demo/serialization/APIGatewayRequestDeserializationFunctionTest.java @@ -1,5 +1,21 @@ +/* + * 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 org.demo.serialization; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent; import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent; @@ -8,8 +24,6 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import static org.junit.jupiter.api.Assertions.assertEquals; - class APIGatewayRequestDeserializationFunctionTest { @Mock diff --git a/examples/powertools-examples-serialization/src/test/java/org/demo/serialization/SQSEventDeserializationFunctionTest.java b/examples/powertools-examples-serialization/src/test/java/org/demo/serialization/SQSEventDeserializationFunctionTest.java index 6979a6868..b46af3052 100644 --- a/examples/powertools-examples-serialization/src/test/java/org/demo/serialization/SQSEventDeserializationFunctionTest.java +++ b/examples/powertools-examples-serialization/src/test/java/org/demo/serialization/SQSEventDeserializationFunctionTest.java @@ -1,17 +1,29 @@ +/* + * 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 org.demo.serialization; +import static org.junit.jupiter.api.Assertions.assertEquals; + import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.events.SQSEvent; +import java.util.ArrayList; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import java.util.List; -import java.util.ArrayList; - -import static org.junit.jupiter.api.Assertions.assertEquals; - class SQSEventDeserializationFunctionTest { @Mock @@ -29,7 +41,7 @@ public void shouldReturnNumberOfReceivedMessages() { SQSEvent.SQSMessage message1 = messageWithBody("{ \"id\": 1234, \"name\": \"product\", \"price\": 42}"); SQSEvent.SQSMessage message2 = messageWithBody("{ \"id\": 12345, \"name\": \"product5\", \"price\": 45}"); SQSEvent event = new SQSEvent(); - event.setRecords(new ArrayList (){{ + event.setRecords(new ArrayList () {{ add(message1); add(message2); }}); diff --git a/examples/powertools-examples-sqs/src/main/java/org/demo/sqs/SqsMessageSender.java b/examples/powertools-examples-sqs/src/main/java/org/demo/sqs/SqsMessageSender.java index b90c50654..45856d198 100644 --- a/examples/powertools-examples-sqs/src/main/java/org/demo/sqs/SqsMessageSender.java +++ b/examples/powertools-examples-sqs/src/main/java/org/demo/sqs/SqsMessageSender.java @@ -1,11 +1,32 @@ +/* + * 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 org.demo.sqs; +import static java.util.stream.Collectors.toList; + import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.amazonaws.services.lambda.runtime.events.ScheduledEvent; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.joda.JodaModule; +import java.security.SecureRandom; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.stream.IntStream; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient; @@ -17,15 +38,6 @@ import software.amazon.lambda.powertools.logging.Logging; import software.amazon.lambda.powertools.logging.LoggingUtils; -import java.security.SecureRandom; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.stream.IntStream; - -import static java.util.stream.Collectors.toList; - public class SqsMessageSender implements RequestHandler { private static final Logger log = LogManager.getLogger(SqsMessageSender.class); @@ -50,22 +62,23 @@ public String handleRequest(final ScheduledEvent input, final Context context) { // Push 5 messages on each invoke. List batchRequestEntries = IntStream.range(0, 5) - .mapToObj(value -> { - Map attributeValueHashMap = new HashMap<>(); - attributeValueHashMap.put("Key" + value, MessageAttributeValue.builder() - .dataType("String") - .stringValue("Value" + value) - .build()); - - byte[] array = new byte[7]; - random.nextBytes(array); - - return SendMessageBatchRequestEntry.builder() - .messageAttributes(attributeValueHashMap) - .id(input.getId() + value) - .messageBody("Sample Message " + value) - .build(); - }).collect(toList()); + .mapToObj(value -> + { + Map attributeValueHashMap = new HashMap<>(); + attributeValueHashMap.put("Key" + value, MessageAttributeValue.builder() + .dataType("String") + .stringValue("Value" + value) + .build()); + + byte[] array = new byte[7]; + random.nextBytes(array); + + return SendMessageBatchRequestEntry.builder() + .messageAttributes(attributeValueHashMap) + .id(input.getId() + value) + .messageBody("Sample Message " + value) + .build(); + }).collect(toList()); SendMessageBatchResponse sendMessageBatchResponse = sqsClient.sendMessageBatch(SendMessageBatchRequest.builder() .queueUrl(queueUrl) diff --git a/examples/powertools-examples-sqs/src/main/java/org/demo/sqs/SqsPoller.java b/examples/powertools-examples-sqs/src/main/java/org/demo/sqs/SqsPoller.java index bf2b7bdfe..9ad5c7868 100644 --- a/examples/powertools-examples-sqs/src/main/java/org/demo/sqs/SqsPoller.java +++ b/examples/powertools-examples-sqs/src/main/java/org/demo/sqs/SqsPoller.java @@ -1,10 +1,26 @@ +/* + * 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 org.demo.sqs; -import java.util.Random; +import static com.amazonaws.services.lambda.runtime.events.SQSEvent.SQSMessage; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.amazonaws.services.lambda.runtime.events.SQSEvent; +import java.security.SecureRandom; +import java.util.Random; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient; @@ -13,18 +29,12 @@ import software.amazon.lambda.powertools.sqs.SqsBatch; import software.amazon.lambda.powertools.sqs.SqsMessageHandler; import software.amazon.lambda.powertools.sqs.SqsUtils; -import java.security.SecureRandom; - -import static com.amazonaws.services.lambda.runtime.events.SQSEvent.SQSMessage; /** * Handler for requests to Lambda function. */ public class SqsPoller implements RequestHandler { - Logger log = LogManager.getLogger(SqsPoller.class); - Random random = new SecureRandom(); - static { // https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/lambda-optimize-starttime.html SqsUtils.overrideSqsClient(SqsClient.builder() @@ -32,6 +42,9 @@ public class SqsPoller implements RequestHandler { .build()); } + Logger log = LogManager.getLogger(SqsPoller.class); + Random random = new SecureRandom(); + @SqsBatch(value = BatchProcessor.class, nonRetryableExceptions = {IllegalArgumentException.class}) @Logging(logEvent = true) public String handleRequest(final SQSEvent input, final Context context) { @@ -45,14 +58,16 @@ public String process(SQSMessage message) { int nextInt = random.nextInt(100); - if(nextInt <= 10) { + if (nextInt <= 10) { log.info("Randomly picked message with id {} as business validation failure.", message.getMessageId()); - throw new IllegalArgumentException("Failed business validation. No point of retrying. Move me to DLQ." + message.getMessageId()); + throw new IllegalArgumentException( + "Failed business validation. No point of retrying. Move me to DLQ." + message.getMessageId()); } - if(nextInt > 90) { + if (nextInt > 90) { log.info("Randomly picked message with id {} as intermittent failure.", message.getMessageId()); - throw new RuntimeException("Failed due to intermittent issue. Will be sent back for retry." + message.getMessageId()); + throw new RuntimeException( + "Failed due to intermittent issue. Will be sent back for retry." + message.getMessageId()); } return "Success"; diff --git a/examples/powertools-examples-validation/pom.xml b/examples/powertools-examples-validation/pom.xml index 455fd66b8..1c7e33de0 100644 --- a/examples/powertools-examples-validation/pom.xml +++ b/examples/powertools-examples-validation/pom.xml @@ -1,3 +1,17 @@ + + 4.0.0 diff --git a/examples/powertools-examples-validation/src/main/java/org/demo/validation/InboundValidation.java b/examples/powertools-examples-validation/src/main/java/org/demo/validation/InboundValidation.java index 89ec538c9..d3b8e51e4 100644 --- a/examples/powertools-examples-validation/src/main/java/org/demo/validation/InboundValidation.java +++ b/examples/powertools-examples-validation/src/main/java/org/demo/validation/InboundValidation.java @@ -1,11 +1,23 @@ +/* + * 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 org.demo.validation; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent; import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent; -import software.amazon.lambda.powertools.validation.Validation; - import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; @@ -13,6 +25,7 @@ import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; +import software.amazon.lambda.powertools.validation.Validation; /** * Request handler for Lambda function which demonstrates validation of request message. @@ -20,7 +33,8 @@ public class InboundValidation implements RequestHandler{ @Validation(inboundSchema = "classpath:/schema.json") - public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent apiGatewayProxyRequestEvent, Context context) { + public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent apiGatewayProxyRequestEvent, + Context context) { Map headers = new HashMap<>(); headers.put("Content-Type", "application/json"); diff --git a/examples/powertools-examples-validation/src/test/java/org/demo/validation/InboundValidationTest.java b/examples/powertools-examples-validation/src/test/java/org/demo/validation/InboundValidationTest.java index af47d3d87..d5e6de313 100644 --- a/examples/powertools-examples-validation/src/test/java/org/demo/validation/InboundValidationTest.java +++ b/examples/powertools-examples-validation/src/test/java/org/demo/validation/InboundValidationTest.java @@ -1,5 +1,22 @@ +/* + * 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 org.demo.validation; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent; import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent; @@ -9,9 +26,6 @@ import org.mockito.MockitoAnnotations; import software.amazon.lambda.powertools.validation.ValidationException; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - public class InboundValidationTest { @Mock diff --git a/license-header b/license-header new file mode 100644 index 000000000..5669f143f --- /dev/null +++ b/license-header @@ -0,0 +1,13 @@ +/* + * 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. + * + */ diff --git a/pom.xml b/pom.xml index ccc27b64c..7744913fd 100644 --- a/pom.xml +++ b/pom.xml @@ -1,4 +1,18 @@ + + @@ -525,6 +539,45 @@ + diff --git a/powertools-cloudformation/pom.xml b/powertools-cloudformation/pom.xml index 3a846c378..a122e7ac8 100644 --- a/powertools-cloudformation/pom.xml +++ b/powertools-cloudformation/pom.xml @@ -1,4 +1,18 @@ + ++ jdk11 ++ +11 ++ ++ ++ + +org.apache.maven.plugins +maven-checkstyle-plugin +3.3.0 ++ + + +checkstyle.xml +UTF-8 +true +true +false ++ ++ +com.puppycrawl.tools +checkstyle +10.9.1 ++ ++ ++ +check +@@ -100,4 +114,12 @@
* If PhysicalResourceId is null at this point it will be replaced with the Lambda LogStreamName. * * @throws CustomResourceResponseException if unable to generate the response stream @@ -223,7 +140,8 @@ StringInputStream responseBodyStream(CloudFormationCustomResourceEvent event, try { String reason = "See the details in CloudWatch Log Stream: " + context.getLogStreamName(); if (resp == null) { - String physicalResourceId = event.getPhysicalResourceId() != null? event.getPhysicalResourceId() : context.getLogStreamName(); + String physicalResourceId = event.getPhysicalResourceId() != null ? event.getPhysicalResourceId() : + context.getLogStreamName(); ResponseBody body = new ResponseBody(event, Response.Status.SUCCESS, physicalResourceId, false, reason); LOG.debug("ResponseBody: {}", body); @@ -232,9 +150,11 @@ StringInputStream responseBodyStream(CloudFormationCustomResourceEvent event, } else { String physicalResourceId = resp.getPhysicalResourceId() != null ? resp.getPhysicalResourceId() : - event.getPhysicalResourceId() != null? event.getPhysicalResourceId() : context.getLogStreamName(); + event.getPhysicalResourceId() != null ? event.getPhysicalResourceId() : + context.getLogStreamName(); - ResponseBody body = new ResponseBody(event, resp.getStatus(), physicalResourceId, resp.isNoEcho(), reason); + ResponseBody body = + new ResponseBody(event, resp.getStatus(), physicalResourceId, resp.isNoEcho(), reason); LOG.debug("ResponseBody: {}", body); ObjectNode node = body.toObjectNode(resp.getJsonNode()); return new StringInputStream(node.toString()); @@ -244,4 +164,99 @@ StringInputStream responseBodyStream(CloudFormationCustomResourceEvent event, throw new CustomResourceResponseException("Unable to generate response body.", e); } } + + /** + * Internal representation of the payload to be sent to the event target URL. Retains all properties of the payload + * except for "Data". This is done so that the serialization of the non-"Data" properties and the serialization of + * the value of "Data" can be handled by separate ObjectMappers, if need be. The former properties are dictated by + * the custom resource but the latter is dictated by the implementor of the custom resource handler. + */ + @SuppressWarnings("unused") + static class ResponseBody { + static final ObjectMapper MAPPER = new ObjectMapper() + .setPropertyNamingStrategy(PropertyNamingStrategies.UPPER_CAMEL_CASE); + private static final String DATA_PROPERTY_NAME = "Data"; + + private final String status; + private final String reason; + private final String physicalResourceId; + private final String stackId; + private final String requestId; + private final String logicalResourceId; + private final boolean noEcho; + + ResponseBody(CloudFormationCustomResourceEvent event, + Response.Status responseStatus, + String physicalResourceId, + boolean noEcho, + String reason) { + Objects.requireNonNull(event, "CloudFormationCustomResourceEvent cannot be null"); + + this.physicalResourceId = physicalResourceId; + this.reason = reason; + this.status = responseStatus == null ? Response.Status.SUCCESS.name() : responseStatus.name(); + this.stackId = event.getStackId(); + this.requestId = event.getRequestId(); + this.logicalResourceId = event.getLogicalResourceId(); + this.noEcho = noEcho; + } + + public String getStatus() { + return status; + } + + public String getReason() { + return reason; + } + + public String getPhysicalResourceId() { + return physicalResourceId; + } + + public String getStackId() { + return stackId; + } + + public String getRequestId() { + return requestId; + } + + public String getLogicalResourceId() { + return logicalResourceId; + } + + public boolean isNoEcho() { + return noEcho; + } + + /** + * Returns this ResponseBody as an ObjectNode with the provided JsonNode as the value of its "Data" property. + * + * @param dataNode the value of the "Data" property for the returned node; may be null + * @return an ObjectNode representation of this ResponseBody and the provided dataNode + */ + ObjectNode toObjectNode(JsonNode dataNode) { + ObjectNode node = MAPPER.valueToTree(this); + if (dataNode == null) { + node.putNull(DATA_PROPERTY_NAME); + } else { + node.set(DATA_PROPERTY_NAME, dataNode); + } + return node; + } + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer("ResponseBody{"); + sb.append("status='").append(status).append('\''); + sb.append(", reason='").append(reason).append('\''); + sb.append(", physicalResourceId='").append(physicalResourceId).append('\''); + sb.append(", stackId='").append(stackId).append('\''); + sb.append(", requestId='").append(requestId).append('\''); + sb.append(", logicalResourceId='").append(logicalResourceId).append('\''); + sb.append(", noEcho=").append(noEcho); + sb.append('}'); + return sb.toString(); + } + } } diff --git a/powertools-cloudformation/src/main/java/software/amazon/lambda/powertools/cloudformation/CustomResourceResponseException.java b/powertools-cloudformation/src/main/java/software/amazon/lambda/powertools/cloudformation/CustomResourceResponseException.java index ead912392..904ae9c3f 100644 --- a/powertools-cloudformation/src/main/java/software/amazon/lambda/powertools/cloudformation/CustomResourceResponseException.java +++ b/powertools-cloudformation/src/main/java/software/amazon/lambda/powertools/cloudformation/CustomResourceResponseException.java @@ -1,3 +1,17 @@ +/* + * 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.cloudformation; /** diff --git a/powertools-cloudformation/src/main/java/software/amazon/lambda/powertools/cloudformation/Response.java b/powertools-cloudformation/src/main/java/software/amazon/lambda/powertools/cloudformation/Response.java index f388f6384..fe18000d4 100644 --- a/powertools-cloudformation/src/main/java/software/amazon/lambda/powertools/cloudformation/Response.java +++ b/powertools-cloudformation/src/main/java/software/amazon/lambda/powertools/cloudformation/Response.java @@ -1,8 +1,21 @@ +/* + * 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.cloudformation; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; - import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; @@ -13,119 +26,16 @@ */ public class Response { - /** - * Indicates whether a response is a success or failure. - */ - public enum Status { - SUCCESS, FAILED - } - - /** - * For building Response instances. - */ - public static class Builder { - private Object value; - private ObjectMapper objectMapper; - private Status status; - private String physicalResourceId; - private boolean noEcho; - - private Builder() { - } - - /** - * Configures the value of this Response, typically a Map of name/value pairs. - * - * @param value if null, the Response will be empty - * @return a reference to this builder - */ - public Builder value(Object value) { - this.value = value; - return this; - } - - /** - * Configures a custom ObjectMapper for serializing the value object. Creates a copy of the mapper provided; - * future mutations of the ObjectMapper made using the provided reference will not affect Response - * serialization. - * - * @param objectMapper if null, a default mapper will be used - * @return a reference to this builder - */ - public Builder objectMapper(ObjectMapper objectMapper) { - this.objectMapper = objectMapper == null ? null : objectMapper.copy(); - return this; - } - - /** - * Configures the status of this response. - * - * @param status if null, SUCCESS will be assumed - * @return a reference to this builder - */ - public Builder status(Status status) { - this.status = status; - return this; - } - - /** - * A unique identifier for the custom resource being responded to. By default, the identifier is the name of the - * Amazon CloudWatch Logs log stream associated with the Lambda function. - * - * @param physicalResourceId if null, the default resource ID will be used - * @return a reference to this builder - */ - public Builder physicalResourceId(String physicalResourceId) { - this.physicalResourceId = physicalResourceId; - return this; - } - - /** - * Indicates whether to mask the output of the custom resource when it's retrieved by using the Fn::GetAtt - * function. If set to true, values will be masked with asterisks (*****), except for information stored in the - * these locations: - *
- * We strongly recommend not using these mechanisms to include sensitive information, such as passwords or - * secrets. - *
- * For more information about using noEcho to mask sensitive information, see - * https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/best-practices.html#creds - *
- * By default, this value is false. - * - * @param noEcho when true, masks certain output - * @return a reference to this builder - */ - public Builder noEcho(boolean noEcho) { - this.noEcho = noEcho; - return this; - } + private final JsonNode jsonNode; + private final Status status; + private final String physicalResourceId; + private final boolean noEcho; - /** - * Builds a Response object for the value. - * - * @return a Response object wrapping the initially provided value. - */ - public Response build() { - JsonNode node; - if (value == null) { - node = null; - } else { - ObjectMapper mapper = objectMapper != null ? objectMapper : CloudFormationResponse.ResponseBody.MAPPER; - node = mapper.valueToTree(value); - } - Status responseStatus = this.status != null ? this.status : Status.SUCCESS; - return new Response(node, responseStatus, physicalResourceId, noEcho); - } + private Response(JsonNode jsonNode, Status status, String physicalResourceId, boolean noEcho) { + this.jsonNode = jsonNode; + this.status = status; + this.physicalResourceId = physicalResourceId; + this.noEcho = noEcho; } /** @@ -140,14 +50,14 @@ public static Builder builder() { /** * Creates a failed Response with no physicalResourceId set. Powertools for AWS Lambda (Java) will set the physicalResourceId to the * Lambda LogStreamName - * + *
* The value returned for a PhysicalResourceId can change custom resource update operations. If the value returned * is the same, it is considered a normal update. If the value returned is different, AWS CloudFormation recognizes * the update as a replacement and sends a delete request to the old resource. For more information, * see AWS::CloudFormation::CustomResource. * - * @deprecated this method is not safe. Provide a physicalResourceId. * @return a failed Response with no value. + * @deprecated this method is not safe. Provide a physicalResourceId. */ @Deprecated public static Response failed() { @@ -173,14 +83,14 @@ public static Response failed(String physicalResourceId) { /** * Creates a successful Response with no physicalResourceId set. Powertools for AWS Lambda (Java) will set the physicalResourceId to the * Lambda LogStreamName - * + *
* The value returned for a PhysicalResourceId can change custom resource update operations. If the value returned * is the same, it is considered a normal update. If the value returned is different, AWS CloudFormation recognizes * the update as a replacement and sends a delete request to the old resource. For more information, * see AWS::CloudFormation::CustomResource. * - * @deprecated this method is not safe. Provide a physicalResourceId. * @return a success Response with no physicalResourceId value. + * @deprecated this method is not safe. Provide a physicalResourceId. */ @Deprecated public static Response success() { @@ -203,18 +113,6 @@ public static Response success(String physicalResourceId) { return new Response(null, Status.SUCCESS, physicalResourceId, false); } - private final JsonNode jsonNode; - private final Status status; - private final String physicalResourceId; - private final boolean noEcho; - - private Response(JsonNode jsonNode, Status status, String physicalResourceId, boolean noEcho) { - this.jsonNode = jsonNode; - this.status = status; - this.physicalResourceId = physicalResourceId; - this.noEcho = noEcho; - } - /** * Returns a JsonNode representation of the Response. * @@ -267,4 +165,119 @@ public String toString() { .map(entry -> entry.getKey() + " = " + entry.getValue()) .collect(Collectors.joining(",", "[", "]")); } + + /** + * Indicates whether a response is a success or failure. + */ + public enum Status { + SUCCESS, FAILED + } + + /** + * For building Response instances. + */ + public static class Builder { + private Object value; + private ObjectMapper objectMapper; + private Status status; + private String physicalResourceId; + private boolean noEcho; + + private Builder() { + } + + /** + * Configures the value of this Response, typically a Map of name/value pairs. + * + * @param value if null, the Response will be empty + * @return a reference to this builder + */ + public Builder value(Object value) { + this.value = value; + return this; + } + + /** + * Configures a custom ObjectMapper for serializing the value object. Creates a copy of the mapper provided; + * future mutations of the ObjectMapper made using the provided reference will not affect Response + * serialization. + * + * @param objectMapper if null, a default mapper will be used + * @return a reference to this builder + */ + public Builder objectMapper(ObjectMapper objectMapper) { + this.objectMapper = objectMapper == null ? null : objectMapper.copy(); + return this; + } + + /** + * Configures the status of this response. + * + * @param status if null, SUCCESS will be assumed + * @return a reference to this builder + */ + public Builder status(Status status) { + this.status = status; + return this; + } + + /** + * A unique identifier for the custom resource being responded to. By default, the identifier is the name of the + * Amazon CloudWatch Logs log stream associated with the Lambda function. + * + * @param physicalResourceId if null, the default resource ID will be used + * @return a reference to this builder + */ + public Builder physicalResourceId(String physicalResourceId) { + this.physicalResourceId = physicalResourceId; + return this; + } + + /** + * Indicates whether to mask the output of the custom resource when it's retrieved by using the Fn::GetAtt + * function. If set to true, values will be masked with asterisks (*****), except for information stored in the + * these locations: + *
+ * We strongly recommend not using these mechanisms to include sensitive information, such as passwords or + * secrets. + *
+ * For more information about using noEcho to mask sensitive information, see + * https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/best-practices.html#creds + *
+ * By default, this value is false.
+ *
+ * @param noEcho when true, masks certain output
+ * @return a reference to this builder
+ */
+ public Builder noEcho(boolean noEcho) {
+ this.noEcho = noEcho;
+ return this;
+ }
+
+ /**
+ * Builds a Response object for the value.
+ *
+ * @return a Response object wrapping the initially provided value.
+ */
+ public Response build() {
+ JsonNode node;
+ if (value == null) {
+ node = null;
+ } else {
+ ObjectMapper mapper = objectMapper != null ? objectMapper : CloudFormationResponse.ResponseBody.MAPPER;
+ node = mapper.valueToTree(value);
+ }
+ Status responseStatus = this.status != null ? this.status : Status.SUCCESS;
+ return new Response(node, responseStatus, physicalResourceId, noEcho);
+ }
+ }
}
diff --git a/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/AbstractCustomResourceHandlerTest.java b/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/AbstractCustomResourceHandlerTest.java
index d68b434d6..1e399ef6f 100644
--- a/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/AbstractCustomResourceHandlerTest.java
+++ b/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/AbstractCustomResourceHandlerTest.java
@@ -1,14 +1,18 @@
-package software.amazon.lambda.powertools.cloudformation;
+/*
+ * 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 com.amazonaws.services.lambda.runtime.Context;
-import com.amazonaws.services.lambda.runtime.events.CloudFormationCustomResourceEvent;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.CsvSource;
-import software.amazon.awssdk.http.SdkHttpClient;
-import software.amazon.lambda.powertools.cloudformation.Response.Status;
-
-import java.io.IOException;
+package software.amazon.lambda.powertools.cloudformation;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -21,95 +25,16 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-public class AbstractCustomResourceHandlerTest {
-
- /**
- * Bare-bones implementation that returns null for abstract methods.
- */
- static class NullCustomResourceHandler extends AbstractCustomResourceHandler {
- NullCustomResourceHandler() {
- }
-
- NullCustomResourceHandler(SdkHttpClient client) {
- super(client);
- }
-
- @Override
- protected Response create(CloudFormationCustomResourceEvent event, Context context) {
- return null;
- }
-
- @Override
- protected Response update(CloudFormationCustomResourceEvent event, Context context) {
- return null;
- }
-
- @Override
- protected Response delete(CloudFormationCustomResourceEvent event, Context context) {
- return null;
- }
- }
-
- /**
- * Uses a mocked CloudFormationResponse to avoid sending actual HTTP requests.
- */
- static class NoOpCustomResourceHandler extends NullCustomResourceHandler {
-
- NoOpCustomResourceHandler() {
- super(mock(SdkHttpClient.class));
- }
-
- @Override
- protected CloudFormationResponse buildResponseClient() {
- return mock(CloudFormationResponse.class);
- }
- }
-
- /**
- * Creates a handler that will expect the Response to be sent with an expected status. Will throw an AssertionError
- * if the method is sent with an unexpected status.
- */
- static class ExpectedStatusResourceHandler extends NoOpCustomResourceHandler {
- private final Status expectedStatus;
-
- ExpectedStatusResourceHandler(Status expectedStatus) {
- this.expectedStatus = expectedStatus;
- }
-
- @Override
- protected CloudFormationResponse buildResponseClient() {
- // create a CloudFormationResponse that fails if invoked with unexpected status
- CloudFormationResponse cfnResponse = mock(CloudFormationResponse.class);
- try {
- when(cfnResponse.send(any(), any(), argThat(resp -> resp.getStatus() != expectedStatus)))
- .thenThrow(new AssertionError("Expected response's status to be " + expectedStatus));
- } catch (IOException | CustomResourceResponseException e) {
- // this should never happen
- throw new RuntimeException("Unexpected mocking exception", e);
- }
- return cfnResponse;
- }
- }
+import com.amazonaws.services.lambda.runtime.Context;
+import com.amazonaws.services.lambda.runtime.events.CloudFormationCustomResourceEvent;
+import java.io.IOException;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+import software.amazon.awssdk.http.SdkHttpClient;
+import software.amazon.lambda.powertools.cloudformation.Response.Status;
- /**
- * Always fails to send the response
- */
- static class FailToSendResponseHandler extends NoOpCustomResourceHandler {
- @Override
- protected CloudFormationResponse buildResponseClient() {
- CloudFormationResponse cfnResponse = mock(CloudFormationResponse.class);
- try {
- when(cfnResponse.send(any(), any()))
- .thenThrow(new IOException("Intentional send failure"));
- when(cfnResponse.send(any(), any(), any()))
- .thenThrow(new IOException("Intentional send failure"));
- } catch (IOException | CustomResourceResponseException e) {
- // this should never happen
- throw new RuntimeException("Unexpected mocking exception", e);
- }
- return cfnResponse;
- }
- }
+public class AbstractCustomResourceHandlerTest {
/**
* Builds a valid Event with the provide request type.
@@ -288,4 +213,92 @@ protected Response create(CloudFormationCustomResourceEvent event, Context conte
verify(handler, times(1))
.onSendFailure(eq(event), eq(context), isNull(), any(IOException.class));
}
+
+ /**
+ * Bare-bones implementation that returns null for abstract methods.
+ */
+ static class NullCustomResourceHandler extends AbstractCustomResourceHandler {
+ NullCustomResourceHandler() {
+ }
+
+ NullCustomResourceHandler(SdkHttpClient client) {
+ super(client);
+ }
+
+ @Override
+ protected Response create(CloudFormationCustomResourceEvent event, Context context) {
+ return null;
+ }
+
+ @Override
+ protected Response update(CloudFormationCustomResourceEvent event, Context context) {
+ return null;
+ }
+
+ @Override
+ protected Response delete(CloudFormationCustomResourceEvent event, Context context) {
+ return null;
+ }
+ }
+
+ /**
+ * Uses a mocked CloudFormationResponse to avoid sending actual HTTP requests.
+ */
+ static class NoOpCustomResourceHandler extends NullCustomResourceHandler {
+
+ NoOpCustomResourceHandler() {
+ super(mock(SdkHttpClient.class));
+ }
+
+ @Override
+ protected CloudFormationResponse buildResponseClient() {
+ return mock(CloudFormationResponse.class);
+ }
+ }
+
+ /**
+ * Creates a handler that will expect the Response to be sent with an expected status. Will throw an AssertionError
+ * if the method is sent with an unexpected status.
+ */
+ static class ExpectedStatusResourceHandler extends NoOpCustomResourceHandler {
+ private final Status expectedStatus;
+
+ ExpectedStatusResourceHandler(Status expectedStatus) {
+ this.expectedStatus = expectedStatus;
+ }
+
+ @Override
+ protected CloudFormationResponse buildResponseClient() {
+ // create a CloudFormationResponse that fails if invoked with unexpected status
+ CloudFormationResponse cfnResponse = mock(CloudFormationResponse.class);
+ try {
+ when(cfnResponse.send(any(), any(), argThat(resp -> resp.getStatus() != expectedStatus)))
+ .thenThrow(new AssertionError("Expected response's status to be " + expectedStatus));
+ } catch (IOException | CustomResourceResponseException e) {
+ // this should never happen
+ throw new RuntimeException("Unexpected mocking exception", e);
+ }
+ return cfnResponse;
+ }
+ }
+
+ /**
+ * Always fails to send the response
+ */
+ static class FailToSendResponseHandler extends NoOpCustomResourceHandler {
+ @Override
+ protected CloudFormationResponse buildResponseClient() {
+ CloudFormationResponse cfnResponse = mock(CloudFormationResponse.class);
+ try {
+ when(cfnResponse.send(any(), any()))
+ .thenThrow(new IOException("Intentional send failure"));
+ when(cfnResponse.send(any(), any(), any()))
+ .thenThrow(new IOException("Intentional send failure"));
+ } catch (IOException | CustomResourceResponseException e) {
+ // this should never happen
+ throw new RuntimeException("Unexpected mocking exception", e);
+ }
+ return cfnResponse;
+ }
+ }
}
diff --git a/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/CloudFormationIntegrationTest.java b/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/CloudFormationIntegrationTest.java
index 06463308c..ce45d3afc 100644
--- a/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/CloudFormationIntegrationTest.java
+++ b/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/CloudFormationIntegrationTest.java
@@ -1,5 +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.cloudformation;
+import static com.github.tomakehurst.wiremock.client.WireMock.matchingJsonPath;
+import static com.github.tomakehurst.wiremock.client.WireMock.ok;
+import static com.github.tomakehurst.wiremock.client.WireMock.put;
+import static com.github.tomakehurst.wiremock.client.WireMock.putRequestedFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlPathMatching;
+import static com.github.tomakehurst.wiremock.client.WireMock.verify;
+import static org.assertj.core.api.Assertions.assertThat;
+
import com.amazonaws.services.lambda.runtime.ClientContext;
import com.amazonaws.services.lambda.runtime.CognitoIdentity;
import com.amazonaws.services.lambda.runtime.Context;
@@ -7,6 +30,7 @@
import com.amazonaws.services.lambda.runtime.events.CloudFormationCustomResourceEvent;
import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
import com.github.tomakehurst.wiremock.junit5.WireMockTest;
+import java.util.UUID;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
@@ -14,20 +38,47 @@
import software.amazon.lambda.powertools.cloudformation.handlers.PhysicalResourceIdSetHandler;
import software.amazon.lambda.powertools.cloudformation.handlers.RuntimeExceptionThrownHandler;
-import java.util.UUID;
-
-import static com.github.tomakehurst.wiremock.client.WireMock.*;
-import static org.assertj.core.api.Assertions.assertThat;
-
@WireMockTest
public class CloudFormationIntegrationTest {
public static final String PHYSICAL_RESOURCE_ID = UUID.randomUUID().toString();
public static final String LOG_STREAM_NAME = "FakeLogStreamName";
+ private static CloudFormationCustomResourceEvent updateEventWithPhysicalResourceId(int httpPort,
+ String physicalResourceId) {
+ CloudFormationCustomResourceEvent.CloudFormationCustomResourceEventBuilder builder = baseEvent(httpPort);
+
+ builder.withPhysicalResourceId(physicalResourceId);
+ builder.withRequestType("Update");
+
+ return builder.build();
+ }
+
+ private static CloudFormationCustomResourceEvent deleteEventWithPhysicalResourceId(int httpPort,
+ String physicalResourceId) {
+ CloudFormationCustomResourceEvent.CloudFormationCustomResourceEventBuilder builder = baseEvent(httpPort);
+
+ builder.withPhysicalResourceId(physicalResourceId);
+ builder.withRequestType("Delete");
+
+ return builder.build();
+ }
+
+ private static CloudFormationCustomResourceEvent.CloudFormationCustomResourceEventBuilder baseEvent(int httpPort) {
+ CloudFormationCustomResourceEvent.CloudFormationCustomResourceEventBuilder builder =
+ CloudFormationCustomResourceEvent.builder()
+ .withResponseUrl("http://localhost:" + httpPort + "/")
+ .withStackId("123")
+ .withRequestId("234")
+ .withLogicalResourceId("345");
+
+ return builder;
+ }
+
@ParameterizedTest
@ValueSource(strings = {"Update", "Delete"})
- void physicalResourceIdTakenFromRequestForUpdateOrDeleteWhenUserSpecifiesNull(String requestType, WireMockRuntimeInfo wmRuntimeInfo) {
+ void physicalResourceIdTakenFromRequestForUpdateOrDeleteWhenUserSpecifiesNull(String requestType,
+ WireMockRuntimeInfo wmRuntimeInfo) {
stubFor(put("/").willReturn(ok()));
NoPhysicalResourceIdSetHandler handler = new NoPhysicalResourceIdSetHandler();
@@ -48,7 +99,8 @@ void physicalResourceIdTakenFromRequestForUpdateOrDeleteWhenUserSpecifiesNull(St
@ParameterizedTest
@ValueSource(strings = {"Update", "Delete"})
- void physicalResourceIdDoesNotChangeWhenRuntimeExceptionThrownWhenUpdatingOrDeleting(String requestType, WireMockRuntimeInfo wmRuntimeInfo) {
+ void physicalResourceIdDoesNotChangeWhenRuntimeExceptionThrownWhenUpdatingOrDeleting(String requestType,
+ WireMockRuntimeInfo wmRuntimeInfo) {
stubFor(put("/").willReturn(ok()));
RuntimeExceptionThrownHandler handler = new RuntimeExceptionThrownHandler();
@@ -68,7 +120,7 @@ void physicalResourceIdDoesNotChangeWhenRuntimeExceptionThrownWhenUpdatingOrDele
}
@Test
- void runtimeExceptionThrownOnCreateSendsLogStreamNameAsPhysicalResourceId(WireMockRuntimeInfo wmRuntimeInfo) {
+ void runtimeExceptionThrownOnCreateSendsLogStreamNameAsPhysicalResourceId(WireMockRuntimeInfo wmRuntimeInfo) {
stubFor(put("/").willReturn(ok()));
RuntimeExceptionThrownHandler handler = new RuntimeExceptionThrownHandler();
@@ -85,7 +137,8 @@ void runtimeExceptionThrownOnCreateSendsLogStreamNameAsPhysicalResourceId(WireMo
@ParameterizedTest
@ValueSource(strings = {"Update", "Delete"})
- void physicalResourceIdSetFromRequestOnUpdateOrDeleteWhenCustomerDoesntProvideAPhysicalResourceId(String requestType, WireMockRuntimeInfo wmRuntimeInfo) {
+ void physicalResourceIdSetFromRequestOnUpdateOrDeleteWhenCustomerDoesntProvideAPhysicalResourceId(
+ String requestType, WireMockRuntimeInfo wmRuntimeInfo) {
stubFor(put("/").willReturn(ok()));
NoPhysicalResourceIdSetHandler handler = new NoPhysicalResourceIdSetHandler();
@@ -160,34 +213,6 @@ void physicalResourceIdReturnedFromFailedToCloudformation(String requestType, Wi
);
}
- private static CloudFormationCustomResourceEvent updateEventWithPhysicalResourceId(int httpPort, String physicalResourceId) {
- CloudFormationCustomResourceEvent.CloudFormationCustomResourceEventBuilder builder = baseEvent(httpPort);
-
- builder.withPhysicalResourceId(physicalResourceId);
- builder.withRequestType("Update");
-
- return builder.build();
- }
-
- private static CloudFormationCustomResourceEvent deleteEventWithPhysicalResourceId(int httpPort, String physicalResourceId) {
- CloudFormationCustomResourceEvent.CloudFormationCustomResourceEventBuilder builder = baseEvent(httpPort);
-
- builder.withPhysicalResourceId(physicalResourceId);
- builder.withRequestType("Delete");
-
- return builder.build();
- }
-
- private static CloudFormationCustomResourceEvent.CloudFormationCustomResourceEventBuilder baseEvent(int httpPort) {
- CloudFormationCustomResourceEvent.CloudFormationCustomResourceEventBuilder builder = CloudFormationCustomResourceEvent.builder()
- .withResponseUrl("http://localhost:" + httpPort + "/")
- .withStackId("123")
- .withRequestId("234")
- .withLogicalResourceId("345");
-
- return builder;
- }
-
private static class FakeContext implements Context {
@Override
public String getAwsRequestId() {
diff --git a/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/CloudFormationResponseTest.java b/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/CloudFormationResponseTest.java
index 64c313695..2e7fbcc0c 100644
--- a/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/CloudFormationResponseTest.java
+++ b/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/CloudFormationResponseTest.java
@@ -1,8 +1,33 @@
+/*
+ * 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.cloudformation;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.events.CloudFormationCustomResourceEvent;
import com.fasterxml.jackson.databind.node.ObjectNode;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Optional;
import org.junit.jupiter.api.Test;
import software.amazon.awssdk.http.AbortableInputStream;
import software.amazon.awssdk.http.ExecutableHttpRequest;
@@ -13,18 +38,6 @@
import software.amazon.awssdk.utils.StringInputStream;
import software.amazon.lambda.powertools.cloudformation.CloudFormationResponse.ResponseBody;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Optional;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
public class CloudFormationResponseTest {
/**
@@ -44,16 +57,17 @@ static CloudFormationResponse testableCloudFormationResponse() {
SdkHttpClient client = mock(SdkHttpClient.class);
ExecutableHttpRequest executableRequest = mock(ExecutableHttpRequest.class);
- when(client.prepareRequest(any(HttpExecuteRequest.class))).thenAnswer(args -> {
- HttpExecuteRequest request = args.getArgument(0, HttpExecuteRequest.class);
- assertThat(request.contentStreamProvider()).isPresent();
+ when(client.prepareRequest(any(HttpExecuteRequest.class))).thenAnswer(args ->
+ {
+ HttpExecuteRequest request = args.getArgument(0, HttpExecuteRequest.class);
+ assertThat(request.contentStreamProvider()).isPresent();
- InputStream inputStream = request.contentStreamProvider().get().newStream();
- HttpExecuteResponse response = mock(HttpExecuteResponse.class);
- when(response.responseBody()).thenReturn(Optional.of(AbortableInputStream.create(inputStream)));
- when(executableRequest.call()).thenReturn(response);
- return executableRequest;
- });
+ InputStream inputStream = request.contentStreamProvider().get().newStream();
+ HttpExecuteResponse response = mock(HttpExecuteResponse.class);
+ when(response.responseBody()).thenReturn(Optional.of(AbortableInputStream.create(inputStream)));
+ when(executableRequest.call()).thenReturn(response);
+ return executableRequest;
+ });
return new CloudFormationResponse(client);
}
@@ -113,7 +127,8 @@ void customPhysicalResponseId() {
String customPhysicalResourceId = "Custom-Physical-Resource-ID";
ResponseBody body = new ResponseBody(
- event, Response.Status.SUCCESS, customPhysicalResourceId, false, "See the details in CloudWatch Log Stream: " + context.getLogStreamName());
+ event, Response.Status.SUCCESS, customPhysicalResourceId, false,
+ "See the details in CloudWatch Log Stream: " + context.getLogStreamName());
assertThat(body.getPhysicalResourceId()).isEqualTo(customPhysicalResourceId);
}
@@ -122,7 +137,8 @@ void responseBodyWithNullDataNode() {
CloudFormationCustomResourceEvent event = mockCloudFormationCustomResourceEvent();
Context context = mock(Context.class);
- ResponseBody responseBody = new ResponseBody(event, Response.Status.FAILED, null, true, "See the details in CloudWatch Log Stream: " + context.getLogStreamName());
+ ResponseBody responseBody = new ResponseBody(event, Response.Status.FAILED, null, true,
+ "See the details in CloudWatch Log Stream: " + context.getLogStreamName());
String actualJson = responseBody.toObjectNode(null).toString();
String expectedJson = "{" +
@@ -146,7 +162,8 @@ void responseBodyWithNonNullDataNode() {
dataNode.put("foo", "bar");
dataNode.put("baz", 10);
- ResponseBody responseBody = new ResponseBody(event, Response.Status.FAILED, null, true, "See the details in CloudWatch Log Stream: " + context.getLogStreamName());
+ ResponseBody responseBody = new ResponseBody(event, Response.Status.FAILED, null, true,
+ "See the details in CloudWatch Log Stream: " + context.getLogStreamName());
String actualJson = responseBody.toObjectNode(dataNode).toString();
String expectedJson = "{" +
@@ -178,7 +195,8 @@ void customStatus() {
Context context = mock(Context.class);
ResponseBody body = new ResponseBody(
- event, Response.Status.FAILED, null, false, "See the details in CloudWatch Log Stream: " + context.getLogStreamName());
+ event, Response.Status.FAILED, null, false,
+ "See the details in CloudWatch Log Stream: " + context.getLogStreamName());
assertThat(body.getStatus()).isEqualTo("FAILED");
}
@@ -191,7 +209,8 @@ void reasonIncludesLogStreamName() {
when(context.getLogStreamName()).thenReturn(logStreamName);
ResponseBody body = new ResponseBody(
- event, Response.Status.SUCCESS, null, false, "See the details in CloudWatch Log Stream: " + context.getLogStreamName());
+ event, Response.Status.SUCCESS, null, false,
+ "See the details in CloudWatch Log Stream: " + context.getLogStreamName());
assertThat(body.getReason()).contains(logStreamName);
}
diff --git a/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/ResponseTest.java b/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/ResponseTest.java
index e97a1a5ba..37fe73d0f 100644
--- a/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/ResponseTest.java
+++ b/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/ResponseTest.java
@@ -1,29 +1,29 @@
+/*
+ * 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.cloudformation;
+import static org.assertj.core.api.Assertions.assertThat;
+
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
-import org.junit.jupiter.api.Test;
-
import java.util.HashMap;
import java.util.Map;
-
-import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.jupiter.api.Test;
public class ResponseTest {
- static class DummyBean {
- private final Object propertyWithLongName;
-
- DummyBean(Object propertyWithLongName) {
- this.propertyWithLongName = propertyWithLongName;
- }
-
- @SuppressWarnings("unused")
- public Object getPropertyWithLongName() {
- return propertyWithLongName;
- }
- }
-
@Test
void defaultValues() {
Response response = Response.builder().build();
@@ -173,4 +173,17 @@ void failedFactoryMethod() {
assertThat(response).isNotNull();
assertThat(response.getStatus()).isEqualTo(Response.Status.FAILED);
}
+
+ static class DummyBean {
+ private final Object propertyWithLongName;
+
+ DummyBean(Object propertyWithLongName) {
+ this.propertyWithLongName = propertyWithLongName;
+ }
+
+ @SuppressWarnings("unused")
+ public Object getPropertyWithLongName() {
+ return propertyWithLongName;
+ }
+ }
}
diff --git a/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/handlers/NoPhysicalResourceIdSetHandler.java b/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/handlers/NoPhysicalResourceIdSetHandler.java
index 68d057b54..2bbda309f 100644
--- a/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/handlers/NoPhysicalResourceIdSetHandler.java
+++ b/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/handlers/NoPhysicalResourceIdSetHandler.java
@@ -1,3 +1,17 @@
+/*
+ * 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.cloudformation.handlers;
import com.amazonaws.services.lambda.runtime.Context;
diff --git a/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/handlers/PhysicalResourceIdSetHandler.java b/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/handlers/PhysicalResourceIdSetHandler.java
index 51f520a3d..c6bd56b76 100644
--- a/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/handlers/PhysicalResourceIdSetHandler.java
+++ b/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/handlers/PhysicalResourceIdSetHandler.java
@@ -1,3 +1,17 @@
+/*
+ * 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.cloudformation.handlers;
import com.amazonaws.services.lambda.runtime.Context;
@@ -17,16 +31,16 @@ public PhysicalResourceIdSetHandler(String physicalResourceId, boolean callsSucc
@Override
protected Response create(CloudFormationCustomResourceEvent event, Context context) {
- return callsSucceed? Response.success(physicalResourceId) : Response.failed(physicalResourceId);
+ return callsSucceed ? Response.success(physicalResourceId) : Response.failed(physicalResourceId);
}
@Override
protected Response update(CloudFormationCustomResourceEvent event, Context context) {
- return callsSucceed? Response.success(physicalResourceId) : Response.failed(physicalResourceId);
+ return callsSucceed ? Response.success(physicalResourceId) : Response.failed(physicalResourceId);
}
@Override
protected Response delete(CloudFormationCustomResourceEvent event, Context context) {
- return callsSucceed? Response.success(physicalResourceId) : Response.failed(physicalResourceId);
+ return callsSucceed ? Response.success(physicalResourceId) : Response.failed(physicalResourceId);
}
}
diff --git a/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/handlers/RuntimeExceptionThrownHandler.java b/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/handlers/RuntimeExceptionThrownHandler.java
index ee5be77b8..d5a11e895 100644
--- a/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/handlers/RuntimeExceptionThrownHandler.java
+++ b/powertools-cloudformation/src/test/java/software/amazon/lambda/powertools/cloudformation/handlers/RuntimeExceptionThrownHandler.java
@@ -1,3 +1,17 @@
+/*
+ * 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.cloudformation.handlers;
import com.amazonaws.services.lambda.runtime.Context;
diff --git a/powertools-core/pom.xml b/powertools-core/pom.xml
index cf9ad45d1..1adb64af8 100644
--- a/powertools-core/pom.xml
+++ b/powertools-core/pom.xml
@@ -1,4 +1,18 @@
+
+
* All fields are non-nullable.
*/
public class AppConfig {
diff --git a/powertools-e2e-tests/src/test/java/software/amazon/lambda/powertools/testutils/Infrastructure.java b/powertools-e2e-tests/src/test/java/software/amazon/lambda/powertools/testutils/Infrastructure.java
index 59035af7c..62bb018f4 100644
--- a/powertools-e2e-tests/src/test/java/software/amazon/lambda/powertools/testutils/Infrastructure.java
+++ b/powertools-e2e-tests/src/test/java/software/amazon/lambda/powertools/testutils/Infrastructure.java
@@ -1,23 +1,56 @@
+/*
+ * 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.testutils;
+import static java.util.Collections.singletonList;
+
import com.fasterxml.jackson.databind.JsonNode;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.UUID;
+import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yaml.snakeyaml.Yaml;
+import software.amazon.awscdk.App;
+import software.amazon.awscdk.BundlingOptions;
+import software.amazon.awscdk.BundlingOutput;
+import software.amazon.awscdk.DockerVolume;
+import software.amazon.awscdk.Duration;
+import software.amazon.awscdk.RemovalPolicy;
import software.amazon.awscdk.Stack;
-import software.amazon.awscdk.*;
import software.amazon.awscdk.cxapi.CloudAssembly;
-import software.amazon.awscdk.services.appconfig.*;
+import software.amazon.awscdk.services.appconfig.CfnApplication;
+import software.amazon.awscdk.services.appconfig.CfnConfigurationProfile;
+import software.amazon.awscdk.services.appconfig.CfnDeployment;
+import software.amazon.awscdk.services.appconfig.CfnDeploymentStrategy;
+import software.amazon.awscdk.services.appconfig.CfnEnvironment;
+import software.amazon.awscdk.services.appconfig.CfnHostedConfigurationVersion;
import software.amazon.awscdk.services.dynamodb.Attribute;
import software.amazon.awscdk.services.dynamodb.AttributeType;
import software.amazon.awscdk.services.dynamodb.BillingMode;
import software.amazon.awscdk.services.dynamodb.Table;
-import software.amazon.awscdk.services.groundstation.CfnConfig;
import software.amazon.awscdk.services.iam.PolicyStatement;
-import software.amazon.awscdk.services.iam.ServicePrincipal;
import software.amazon.awscdk.services.lambda.Code;
import software.amazon.awscdk.services.lambda.Function;
-import software.amazon.awscdk.services.lambda.Permission;
import software.amazon.awscdk.services.lambda.Tracing;
import software.amazon.awscdk.services.logs.LogGroup;
import software.amazon.awscdk.services.logs.RetentionDays;
@@ -27,7 +60,12 @@
import software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.cloudformation.CloudFormationClient;
-import software.amazon.awssdk.services.cloudformation.model.*;
+import software.amazon.awssdk.services.cloudformation.model.Capability;
+import software.amazon.awssdk.services.cloudformation.model.CreateStackRequest;
+import software.amazon.awssdk.services.cloudformation.model.DeleteStackRequest;
+import software.amazon.awssdk.services.cloudformation.model.DescribeStacksRequest;
+import software.amazon.awssdk.services.cloudformation.model.DescribeStacksResponse;
+import software.amazon.awssdk.services.cloudformation.model.OnFailure;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.ListObjectsV2Request;
import software.amazon.awssdk.services.s3.model.ListObjectsV2Response;
@@ -36,14 +74,6 @@
import software.amazon.awssdk.utils.StringUtils;
import software.amazon.lambda.powertools.utilities.JsonConfig;
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Paths;
-import java.util.*;
-import java.util.stream.Collectors;
-
-import static java.util.Collections.singletonList;
-
/**
* This class is in charge of bootstrapping the infrastructure for the tests.
*
* DynamoDB's TTL mechanism is used to remove the record once the
* expiry has been reached, and subsequent execution of the request
* will be permitted. The user must configure this on their table.
@@ -43,16 +42,17 @@ public class DataRecord {
* The in-progress field is set to the remaining lambda execution time
* when the record is created.
* This field is stored in _milliseconds since epoch_.
- *
+ *
* This ensures that:
- *
+ *
* 1/ other concurrently executing requests are blocked from starting
* 2/ if a lambda times out, subsequent requests will be allowed again, despite
- * the fact that the idempotency record is already in the table
+ * the fact that the idempotency record is already in the table
*/
private final OptionalLong inProgressExpiryTimestamp;
- public DataRecord(String idempotencyKey, Status status, long expiryTimestamp, String responseData, String payloadHash) {
+ public DataRecord(String idempotencyKey, Status status, long expiryTimestamp, String responseData,
+ String payloadHash) {
this.idempotencyKey = idempotencyKey;
this.status = status.toString();
this.expiryTimestamp = expiryTimestamp;
@@ -61,7 +61,8 @@ public DataRecord(String idempotencyKey, Status status, long expiryTimestamp, St
this.inProgressExpiryTimestamp = OptionalLong.empty();
}
- public DataRecord(String idempotencyKey, Status status, long expiryTimestamp, String responseData, String payloadHash, OptionalLong inProgressExpiryTimestamp) {
+ public DataRecord(String idempotencyKey, Status status, long expiryTimestamp, String responseData,
+ String payloadHash, OptionalLong inProgressExpiryTimestamp) {
this.idempotencyKey = idempotencyKey;
this.status = status.toString();
this.expiryTimestamp = expiryTimestamp;
@@ -110,8 +111,12 @@ public String getPayloadHash() {
@Override
public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
DataRecord record = (DataRecord) o;
return expiryTimestamp == record.expiryTimestamp
&& idempotencyKey.equals(record.idempotencyKey)
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 783b029bb..7a023b4de 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
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Amazon.com, Inc. or its affiliates.
+ * 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
@@ -11,31 +11,37 @@
* limitations under the License.
*
*/
+
package software.amazon.lambda.powertools.idempotency.persistence;
+import static software.amazon.lambda.powertools.core.internal.LambdaConstants.AWS_REGION_ENV;
+import static software.amazon.lambda.powertools.core.internal.LambdaConstants.LAMBDA_FUNCTION_NAME_ENV;
+import static software.amazon.lambda.powertools.idempotency.persistence.DataRecord.Status.INPROGRESS;
+
+import java.time.Instant;
+import java.util.AbstractMap;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.OptionalLong;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.ConditionalCheckFailedException;
+import software.amazon.awssdk.services.dynamodb.model.DeleteItemRequest;
+import software.amazon.awssdk.services.dynamodb.model.GetItemRequest;
+import software.amazon.awssdk.services.dynamodb.model.GetItemResponse;
+import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;
+import software.amazon.awssdk.services.dynamodb.model.UpdateItemRequest;
import software.amazon.awssdk.utils.StringUtils;
import software.amazon.lambda.powertools.idempotency.Constants;
import software.amazon.lambda.powertools.idempotency.exceptions.IdempotencyItemAlreadyExistsException;
import software.amazon.lambda.powertools.idempotency.exceptions.IdempotencyItemNotFoundException;
-import java.time.Instant;
-import java.util.AbstractMap;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.OptionalLong;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import static software.amazon.lambda.powertools.core.internal.LambdaConstants.AWS_REGION_ENV;
-import static software.amazon.lambda.powertools.core.internal.LambdaConstants.LAMBDA_FUNCTION_NAME_ENV;
-import static software.amazon.lambda.powertools.idempotency.persistence.DataRecord.Status.INPROGRESS;
-
/**
* DynamoDB version of the {@link PersistenceStore}. Will store idempotency data in DynamoDB.
* {@see Logging}
*/
public final class LoggingUtils {
@@ -35,7 +35,7 @@ private LoggingUtils() {
* Appends an additional key and value to each log entry made. Duplicate values
* for the same key will be replaced with the latest.
*
- * @param key The name of the key to be logged
+ * @param key The name of the key to be logged
* @param value The value to be logged
*/
public static void appendKey(String key, String value) {
@@ -43,7 +43,6 @@ public static void appendKey(String key, String value) {
}
-
/**
* Appends additional key and value to each log entry made. Duplicate values
* for the same key will be replaced with the latest.
@@ -93,8 +92,8 @@ public static void defaultObjectMapper(ObjectMapper objectMapper) {
}
public static ObjectMapper objectMapper() {
- if(null == objectMapper) {
- objectMapper = new ObjectMapper();
+ if (null == objectMapper) {
+ objectMapper = new ObjectMapper();
}
return objectMapper;
diff --git a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/AbstractJacksonLayoutCopy.java b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/AbstractJacksonLayoutCopy.java
index c96d1383e..f98e2ee46 100644
--- a/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/AbstractJacksonLayoutCopy.java
+++ b/powertools-logging/src/main/java/software/amazon/lambda/powertools/logging/internal/AbstractJacksonLayoutCopy.java
@@ -1,3 +1,17 @@
+/*
+ * 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.logging.internal;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
@@ -7,6 +21,11 @@
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.util.LinkedHashMap;
+import java.util.Map;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.ThreadContext;
@@ -26,17 +45,145 @@
import org.apache.logging.log4j.util.ReadOnlyStringMap;
import org.apache.logging.log4j.util.Strings;
-import java.io.IOException;
-import java.io.Writer;
-import java.nio.charset.Charset;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
@Deprecated
abstract class AbstractJacksonLayoutCopy extends AbstractStringLayout {
protected static final String DEFAULT_EOL = "\r\n";
protected static final String COMPACT_EOL = Strings.EMPTY;
+ protected final String eol;
+ protected final ObjectWriter objectWriter;
+ protected final boolean compact;
+ protected final boolean complete;
+ protected final boolean includeNullDelimiter;
+ protected final ResolvableKeyValuePair[] additionalFields;
+ @Deprecated
+ protected AbstractJacksonLayoutCopy(final Configuration config, final ObjectWriter objectWriter,
+ final Charset charset,
+ final boolean compact, final boolean complete, final boolean eventEol,
+ final Serializer headerSerializer,
+ final Serializer footerSerializer) {
+ this(config, objectWriter, charset, compact, complete, eventEol, headerSerializer, footerSerializer, false);
+ }
+
+ @Deprecated
+ protected AbstractJacksonLayoutCopy(final Configuration config, final ObjectWriter objectWriter,
+ final Charset charset,
+ final boolean compact, final boolean complete, final boolean eventEol,
+ final Serializer headerSerializer,
+ final Serializer footerSerializer, final boolean includeNullDelimiter) {
+ this(config, objectWriter, charset, compact, complete, eventEol, null, headerSerializer, footerSerializer,
+ includeNullDelimiter, null);
+ }
+
+ protected AbstractJacksonLayoutCopy(final Configuration config, final ObjectWriter objectWriter,
+ final Charset charset,
+ final boolean compact, final boolean complete, final boolean eventEol,
+ final String endOfLine, final Serializer headerSerializer,
+ final Serializer footerSerializer, final boolean includeNullDelimiter,
+ final KeyValuePair[] additionalFields) {
+ super(config, charset, headerSerializer, footerSerializer);
+ this.objectWriter = objectWriter;
+ this.compact = compact;
+ this.complete = complete;
+ this.eol = endOfLine != null ? endOfLine : compact && !eventEol ? COMPACT_EOL : DEFAULT_EOL;
+ this.includeNullDelimiter = includeNullDelimiter;
+ this.additionalFields = prepareAdditionalFields(config, additionalFields);
+ }
+
+ protected static boolean valueNeedsLookup(final String value) {
+ return value != null && value.contains("${");
+ }
+
+ private static ResolvableKeyValuePair[] prepareAdditionalFields(final Configuration config,
+ final KeyValuePair[] additionalFields) {
+ if (additionalFields == null || additionalFields.length == 0) {
+ // No fields set
+ return ResolvableKeyValuePair.EMPTY_ARRAY;
+ }
+
+ // Convert to specific class which already determines whether values needs lookup during serialization
+ final ResolvableKeyValuePair[] resolvableFields = new ResolvableKeyValuePair[additionalFields.length];
+
+ for (int i = 0; i < additionalFields.length; i++) {
+ final ResolvableKeyValuePair resolvable =
+ resolvableFields[i] = new ResolvableKeyValuePair(additionalFields[i]);
+
+ // Validate
+ if (config == null && resolvable.valueNeedsLookup) {
+ throw new IllegalArgumentException(
+ "configuration needs to be set when there are additional fields with variables");
+ }
+ }
+
+ return resolvableFields;
+ }
+
+ private static LogEvent convertMutableToLog4jEvent(final LogEvent event) {
+ return event instanceof Log4jLogEvent ? event : Log4jLogEvent.createMemento(event);
+ }
+
+ /**
+ * Formats a {@link org.apache.logging.log4j.core.LogEvent}.
+ *
+ * @param event The LogEvent.
+ * @return The XML representation of the LogEvent.
+ */
+ @Override
+ public String toSerializable(final LogEvent event) {
+ final StringBuilderWriter writer = new StringBuilderWriter();
+ try {
+ toSerializable(event, writer);
+ return writer.toString();
+ } catch (final IOException e) {
+ // Should this be an ISE or IAE?
+ LOGGER.error(e);
+ return Strings.EMPTY;
+ }
+ }
+
+ protected Object wrapLogEvent(final LogEvent event) {
+ if (additionalFields.length > 0) {
+ // Construct map for serialization - note that we are intentionally using original LogEvent
+ final Map
* {@see Metrics}
*/
public final class MetricsUtils {
@@ -43,6 +56,7 @@ public static MetricsLogger metricsLogger() {
/**
* Configure default dimension to be used by logger.
* By default, @{@link Metrics} annotation captures configured service as a dimension Service
+ *
* @param dimensionSets Default value of dimensions set for logger
*/
public static void defaultDimensions(final DimensionSet... dimensionSets) {
@@ -52,15 +66,15 @@ public static void defaultDimensions(final DimensionSet... dimensionSets) {
/**
* Configure default dimension to be used by logger.
* By default, @{@link Metrics} annotation captures configured service as a dimension Service
+ *
* @param dimensionSet Default value of dimension set for logger
* @deprecated use {@link #defaultDimensions(DimensionSet...)} instead
- *
*/
@Deprecated
public static void defaultDimensionSet(final DimensionSet dimensionSet) {
requireNonNull(dimensionSet, "Null dimension set not allowed");
- if(dimensionSet.getDimensionKeys().size() > 0) {
+ if (dimensionSet.getDimensionKeys().size() > 0) {
defaultDimensions(dimensionSet);
}
}
@@ -81,10 +95,11 @@ public static void withSingleMetric(final String name,
final double value,
final Unit unit,
final Consumer
* Because AppConfig is designed to handle rollouts of configuration over time, we must first
* establish a session for each key we wish to retrieve, and then poll the session for the latest
* value when the user re-requests it. This means we must hold a keyed set of session tokens
@@ -27,24 +40,11 @@
* @see Parameters provider documentation
* @see AppConfig documentation
*/
-public class AppConfigProvider extends BaseProvider{
-
- private static class EstablishedSession {
- private final String nextSessionToken;
- private final String lastConfigurationValue;
-
- private EstablishedSession(String nextSessionToken, String value) {
- this.nextSessionToken = nextSessionToken;
- this.lastConfigurationValue = value;
- }
- }
+public class AppConfigProvider extends BaseProvider {
private final AppConfigDataClient client;
-
private final String application;
-
private final String environment;
-
private final HashMap
* Used in {@link ParamManager#createProvider(Class)}
+ *
* @param cacheManager handles the parameter caching
*/
SSMProvider(CacheManager cacheManager) {
this(cacheManager, Builder.createClient());
}
+ /**
+ * Create a builder that can be used to configure and create a {@link SSMProvider}.
+ *
+ * @return a new instance of {@link SSMProvider.Builder}
+ */
+ public static SSMProvider.Builder builder() {
+ return new SSMProvider.Builder();
+ }
+
/**
* Retrieve the parameter value from the AWS System Manager Parameter Store.
*
@@ -194,19 +204,20 @@ private Map
* Use the {@link Builder} to create an instance of it.
*
* @param client custom client you would like to use.
@@ -71,14 +71,24 @@ public class SecretsProvider extends BaseProvider {
/**
* Constructor with only a CacheManager
* Used in {@link ParamManager#createProvider(Class)}
+ *
* @param cacheManager handles the parameter caching
*/
SecretsProvider(CacheManager cacheManager) {
this(cacheManager, Builder.createClient());
}
+ /**
+ * Create a builder that can be used to configure and create a {@link SecretsProvider}.
+ *
+ * @return a new instance of {@link SecretsProvider.Builder}
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
/**
* Retrieve the parameter value from the AWS Secrets Manager.
*
@@ -91,13 +101,14 @@ protected String getValue(String key) {
String secretValue = client.getSecretValue(request).secretString();
if (secretValue == null) {
- secretValue = new String(Base64.getDecoder().decode(client.getSecretValue(request).secretBinary().asByteArray()), UTF_8);
+ secretValue =
+ new String(Base64.getDecoder().decode(client.getSecretValue(request).secretBinary().asByteArray()),
+ UTF_8);
}
return secretValue;
}
/**
- *
* @throws UnsupportedOperationException as it is not possible to get multiple values simultaneously from Secrets Manager
*/
@Override
@@ -137,21 +148,19 @@ SecretsManagerClient getClient() {
return client;
}
- /**
- * Create a builder that can be used to configure and create a {@link SecretsProvider}.
- *
- * @return a new instance of {@link SecretsProvider.Builder}
- */
- public static Builder builder() {
- return new Builder();
- }
-
static class Builder {
private SecretsManagerClient client;
private CacheManager cacheManager;
private TransformationManager transformationManager;
+ private static SecretsManagerClient createClient() {
+ return SecretsManagerClient.builder()
+ .httpClientBuilder(UrlConnectionHttpClient.builder())
+ .region(Region.of(System.getenv(SdkSystemSetting.AWS_REGION.environmentVariable())))
+ .build();
+ }
+
/**
* Create a {@link SecretsProvider} instance.
*
@@ -186,13 +195,6 @@ public Builder withClient(SecretsManagerClient client) {
return this;
}
- private static SecretsManagerClient createClient() {
- return SecretsManagerClient.builder()
- .httpClientBuilder(UrlConnectionHttpClient.builder())
- .region(Region.of(System.getenv(SdkSystemSetting.AWS_REGION.environmentVariable())))
- .build();
- }
-
/**
* Mandatory. Provide a CacheManager to the {@link SecretsProvider}
*
diff --git a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/cache/CacheManager.java b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/cache/CacheManager.java
index 687337a96..b868cb642 100644
--- a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/cache/CacheManager.java
+++ b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/cache/CacheManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Amazon.com, Inc. or its affiliates.
+ * 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
@@ -11,15 +11,16 @@
* limitations under the License.
*
*/
+
package software.amazon.lambda.powertools.parameters.cache;
+import static java.time.temporal.ChronoUnit.SECONDS;
+
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.util.Optional;
-import static java.time.temporal.ChronoUnit.SECONDS;
-
public class CacheManager {
static final Duration DEFAULT_MAX_AGE_SECS = Duration.of(5, SECONDS);
diff --git a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/cache/DataStore.java b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/cache/DataStore.java
index 9ad8df12c..737faa353 100644
--- a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/cache/DataStore.java
+++ b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/cache/DataStore.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Amazon.com, Inc. or its affiliates.
+ * 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
@@ -11,6 +11,7 @@
* limitations under the License.
*
*/
+
package software.amazon.lambda.powertools.parameters.cache;
import java.time.Instant;
@@ -27,21 +28,11 @@ public DataStore() {
this.store = new ConcurrentHashMap<>();
}
- static class ValueNode {
- public final Object value;
- public final Instant time;
-
- public ValueNode(Object value, Instant time){
- this.value = value;
- this.time = time;
- }
- }
-
- public void put(String key, Object value, Instant time){
+ public void put(String key, Object value, Instant time) {
store.put(key, new ValueNode(value, time));
}
- public void remove(String Key){
+ public void remove(String Key) {
store.remove(Key);
}
@@ -51,11 +42,21 @@ public Object get(String key) {
}
public boolean hasExpired(String key, Instant now) {
- boolean hasExpired = !store.containsKey(key) || now.isAfter(store.get(key).time);
+ boolean hasExpired = !store.containsKey(key) || now.isAfter(store.get(key).time);
// Auto-clean if the parameter has expired
if (hasExpired) {
remove(key);
}
return hasExpired;
}
+
+ static class ValueNode {
+ public final Object value;
+ public final Instant time;
+
+ public ValueNode(Object value, Instant time) {
+ this.value = value;
+ this.time = time;
+ }
+ }
}
diff --git a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/exception/DynamoDbProviderSchemaException.java b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/exception/DynamoDbProviderSchemaException.java
index b7574e81d..77df6e3d3 100644
--- a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/exception/DynamoDbProviderSchemaException.java
+++ b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/exception/DynamoDbProviderSchemaException.java
@@ -1,3 +1,17 @@
+/*
+ * 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.parameters.exception;
/**
diff --git a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/exception/TransformationException.java b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/exception/TransformationException.java
index 7d28d12d1..f071c8a6b 100644
--- a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/exception/TransformationException.java
+++ b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/exception/TransformationException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Amazon.com, Inc. or its affiliates.
+ * 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
@@ -11,6 +11,7 @@
* limitations under the License.
*
*/
+
package software.amazon.lambda.powertools.parameters.exception;
public class TransformationException extends RuntimeException {
@@ -19,6 +20,7 @@ public TransformationException(Exception e) {
super(e);
}
- public TransformationException(String message) { super(message);
+ public TransformationException(String message) {
+ super(message);
}
}
diff --git a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/internal/LambdaParametersAspect.java b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/internal/LambdaParametersAspect.java
index 8de2f3f57..081af108d 100644
--- a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/internal/LambdaParametersAspect.java
+++ b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/internal/LambdaParametersAspect.java
@@ -1,3 +1,17 @@
+/*
+ * 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.parameters.internal;
import org.aspectj.lang.ProceedingJoinPoint;
@@ -20,12 +34,12 @@ public void getParam(Param paramAnnotation) {
public Object injectParam(final ProceedingJoinPoint joinPoint, final Param paramAnnotation) {
BaseProvider provider = ParamManager.getProvider(paramAnnotation.provider());
- if(paramAnnotation.transformer().isInterface()) {
+ if (paramAnnotation.transformer().isInterface()) {
// No transformation
return provider.get(paramAnnotation.key());
} else {
FieldSignature s = (FieldSignature) joinPoint.getSignature();
- if(String.class.isAssignableFrom(s.getFieldType())) {
+ if (String.class.isAssignableFrom(s.getFieldType())) {
// Basic transformation
return provider
.withTransformation(paramAnnotation.transformer())
diff --git a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/transform/Base64Transformer.java b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/transform/Base64Transformer.java
index c666edce7..e8557ebfd 100644
--- a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/transform/Base64Transformer.java
+++ b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/transform/Base64Transformer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Amazon.com, Inc. or its affiliates.
+ * 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
@@ -11,13 +11,13 @@
* limitations under the License.
*
*/
+
package software.amazon.lambda.powertools.parameters.transform;
-import software.amazon.lambda.powertools.parameters.exception.TransformationException;
+import static java.nio.charset.StandardCharsets.UTF_8;
import java.util.Base64;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
+import software.amazon.lambda.powertools.parameters.exception.TransformationException;
/**
* Transformer that take a base64 encoded string and return a decoded string.
diff --git a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/transform/BasicTransformer.java b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/transform/BasicTransformer.java
index 5251d9f16..92e73d9b0 100644
--- a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/transform/BasicTransformer.java
+++ b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/transform/BasicTransformer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Amazon.com, Inc. or its affiliates.
+ * 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
@@ -11,6 +11,7 @@
* limitations under the License.
*
*/
+
package software.amazon.lambda.powertools.parameters.transform;
import software.amazon.lambda.powertools.parameters.exception.TransformationException;
diff --git a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/transform/JsonTransformer.java b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/transform/JsonTransformer.java
index d84a1ab3a..0eff58ea8 100644
--- a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/transform/JsonTransformer.java
+++ b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/transform/JsonTransformer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Amazon.com, Inc. or its affiliates.
+ * 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
@@ -11,6 +11,7 @@
* limitations under the License.
*
*/
+
package software.amazon.lambda.powertools.parameters.transform;
import com.fasterxml.jackson.core.JsonProcessingException;
diff --git a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/transform/TransformationManager.java b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/transform/TransformationManager.java
index 00e6f84a9..d3fbce14f 100644
--- a/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/transform/TransformationManager.java
+++ b/powertools-parameters/src/main/java/software/amazon/lambda/powertools/parameters/transform/TransformationManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020 Amazon.com, Inc. or its affiliates.
+ * 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
@@ -11,11 +11,11 @@
* limitations under the License.
*
*/
-package software.amazon.lambda.powertools.parameters.transform;
-import software.amazon.lambda.powertools.parameters.exception.TransformationException;
+package software.amazon.lambda.powertools.parameters.transform;
import java.lang.reflect.InvocationTargetException;
+import software.amazon.lambda.powertools.parameters.exception.TransformationException;
/**
* Manager in charge of transforming parameter values in another format.
* The test is kept here for 1/ local development and 2/ in preparation for future
* E2E tests running in the cloud CI. Once the E2E test structure is merged we
* will move this across.
@@ -46,8 +59,8 @@ public void TestGetValue() {
testItem.put("id", AttributeValue.fromS("test_param"));
testItem.put("value", AttributeValue.fromS("the_value_is_hello!"));
ddbClient.putItem(PutItemRequest.builder()
- .tableName(ParamsTestTable)
- .item(testItem)
+ .tableName(ParamsTestTable)
+ .item(testItem)
.build());
// Act
diff --git a/powertools-parameters/src/test/java/software/amazon/lambda/powertools/parameters/DynamoDbProviderTest.java b/powertools-parameters/src/test/java/software/amazon/lambda/powertools/parameters/DynamoDbProviderTest.java
index d6818a64f..abfc9ab8a 100644
--- a/powertools-parameters/src/test/java/software/amazon/lambda/powertools/parameters/DynamoDbProviderTest.java
+++ b/powertools-parameters/src/test/java/software/amazon/lambda/powertools/parameters/DynamoDbProviderTest.java
@@ -1,5 +1,26 @@
+/*
+ * 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.parameters;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
+import static org.mockito.MockitoAnnotations.openMocks;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -17,31 +38,18 @@
import software.amazon.lambda.powertools.parameters.exception.DynamoDbProviderSchemaException;
import software.amazon.lambda.powertools.parameters.transform.TransformationManager;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.UUID;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
-import static org.mockito.MockitoAnnotations.openMocks;
-
public class DynamoDbProviderTest {
+ private final String tableName = "ddb-test-table";
@Mock
DynamoDbClient client;
-
@Mock
TransformationManager transformationManager;
-
@Captor
ArgumentCaptor
@@ -71,12 +101,10 @@ public class Infrastructure {
private final String account;
private final String idempotencyTable;
private final AppConfig appConfig;
-
-
+ private final SdkHttpClient httpClient;
private String functionName;
private Object cfnTemplate;
private String cfnAssetDirectory;
- private final SdkHttpClient httpClient;
private Infrastructure(Builder builder) {
this.stackName = builder.stackName;
@@ -110,8 +138,13 @@ private Infrastructure(Builder builder) {
.build();
}
+ public static Builder builder() {
+ return new Builder();
+ }
+
/**
* Use the CloudFormation SDK to create the stack
+ *
* @return the name of the function deployed part of the stack
*/
public String deploy() {
@@ -124,9 +157,11 @@ public String deploy() {
.onFailure(OnFailure.ROLLBACK)
.capabilities(Capability.CAPABILITY_IAM)
.build());
- WaiterResponse> callable = () -> {
- LOG.debug("Get Metrics for namespace {}, start {}, end {}, metric {}, dimensions {}", namespace, start, end, metricName, dimensionsList);
- GetMetricDataResponse metricData = cloudwatch.getMetricData(GetMetricDataRequest.builder()
- .startTime(start)
- .endTime(end)
- .metricDataQueries(MetricDataQuery.builder()
- .id(metricName.toLowerCase())
- .metricStat(MetricStat.builder()
- .unit(StandardUnit.COUNT)
- .metric(Metric.builder()
- .namespace(namespace)
- .metricName(metricName)
- .dimensions(dimensionsList)
- .build())
- .period(period)
- .stat("Sum")
- .build())
- .returnData(true)
- .build())
- .build());
- List
> callable = () ->
+ {
+ LOG.debug("Get Metrics for namespace {}, start {}, end {}, metric {}, dimensions {}", namespace, start,
+ end, metricName, dimensionsList);
+ GetMetricDataResponse metricData = cloudwatch.getMetricData(GetMetricDataRequest.builder()
+ .startTime(start)
+ .endTime(end)
+ .metricDataQueries(MetricDataQuery.builder()
+ .id(metricName.toLowerCase())
+ .metricStat(MetricStat.builder()
+ .unit(StandardUnit.COUNT)
+ .metric(Metric.builder()
+ .namespace(namespace)
+ .metricName(metricName)
+ .dimensions(dimensionsList)
+ .build())
+ .period(period)
+ .stat("Sum")
+ .build())
+ .returnData(true)
+ .build())
+ .build());
+ List
> callExecutor = new CallExecutorBuilder
>()
.config(retryConfig)
- .afterFailedTryListener(s -> {
- LOG.warn(s.getLastExceptionThatCausedRetry().getMessage() + ", attempts: " + s.getTotalTries());
- })
+ .afterFailedTryListener(s ->
+ {
+ LOG.warn(s.getLastExceptionThatCausedRetry().getMessage() + ", attempts: " + s.getTotalTries());
+ })
.build();
Status
> status = callExecutor.execute(callable);
return status.getResult();
diff --git a/powertools-e2e-tests/src/test/java/software/amazon/lambda/powertools/testutils/tracing/SegmentDocument.java b/powertools-e2e-tests/src/test/java/software/amazon/lambda/powertools/testutils/tracing/SegmentDocument.java
index 08f4bf7d8..5654b9876 100644
--- a/powertools-e2e-tests/src/test/java/software/amazon/lambda/powertools/testutils/tracing/SegmentDocument.java
+++ b/powertools-e2e-tests/src/test/java/software/amazon/lambda/powertools/testutils/tracing/SegmentDocument.java
@@ -1,7 +1,20 @@
+/*
+ * 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.testutils.tracing;
import com.fasterxml.jackson.annotation.JsonSetter;
-
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
@@ -92,7 +105,7 @@ public boolean hasSubsegments() {
return !subsegments.isEmpty();
}
- public static class SubSegment{
+ public static class SubSegment {
private String id;
private String name;
diff --git a/powertools-e2e-tests/src/test/java/software/amazon/lambda/powertools/testutils/tracing/Trace.java b/powertools-e2e-tests/src/test/java/software/amazon/lambda/powertools/testutils/tracing/Trace.java
index 15026a9d1..7298957aa 100644
--- a/powertools-e2e-tests/src/test/java/software/amazon/lambda/powertools/testutils/tracing/Trace.java
+++ b/powertools-e2e-tests/src/test/java/software/amazon/lambda/powertools/testutils/tracing/Trace.java
@@ -1,9 +1,22 @@
-package software.amazon.lambda.powertools.testutils.tracing;
+/*
+ * 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 software.amazon.lambda.powertools.testutils.tracing.SegmentDocument.SubSegment;
+package software.amazon.lambda.powertools.testutils.tracing;
import java.util.ArrayList;
import java.util.List;
+import software.amazon.lambda.powertools.testutils.tracing.SegmentDocument.SubSegment;
public class Trace {
private final List
* Idempotency.config().withConfig(config).configure();
*
+ *
* @return an instance of {@link IdempotencyConfig}.
*/
public IdempotencyConfig build() {
@@ -124,16 +126,15 @@ public IdempotencyConfig build() {
* A JMESPath expression to extract the idempotency key from the event record.
* See https://jmespath.org/ for more details.
* Common paths are:
- *
*
- *
* @param eventKeyJMESPath path of the key in the Lambda event
* @return the instance of the builder (to chain operations)
*/
diff --git a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/IdempotencyKey.java b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/IdempotencyKey.java
index 92a0a3d49..4f63b10f5 100644
--- a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/IdempotencyKey.java
+++ b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/IdempotencyKey.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Amazon.com, Inc. or its affiliates.
+ * 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
@@ -11,6 +11,7 @@
* limitations under the License.
*
*/
+
package software.amazon.lambda.powertools.idempotency;
import java.lang.annotation.ElementType;
diff --git a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/Idempotent.java b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/Idempotent.java
index e7cace1fb..6ca40a0e1 100644
--- a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/Idempotent.java
+++ b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/Idempotent.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Amazon.com, Inc. or its affiliates.
+ * 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
@@ -11,10 +11,10 @@
* limitations under the License.
*
*/
+
package software.amazon.lambda.powertools.idempotency;
import com.amazonaws.services.lambda.runtime.Context;
-
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyAlreadyInProgressException.java b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyAlreadyInProgressException.java
index 3d5ee93c5..dc87f422b 100644
--- a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyAlreadyInProgressException.java
+++ b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyAlreadyInProgressException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Amazon.com, Inc. or its affiliates.
+ * 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
@@ -11,6 +11,7 @@
* limitations under the License.
*
*/
+
package software.amazon.lambda.powertools.idempotency.exceptions;
/**
diff --git a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyConfigurationException.java b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyConfigurationException.java
index 0d3844641..9e85f4b5f 100644
--- a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyConfigurationException.java
+++ b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyConfigurationException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Amazon.com, Inc. or its affiliates.
+ * 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
@@ -11,6 +11,7 @@
* limitations under the License.
*
*/
+
package software.amazon.lambda.powertools.idempotency.exceptions;
/**
diff --git a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyInconsistentStateException.java b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyInconsistentStateException.java
index 40c90dcab..e41e30e84 100644
--- a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyInconsistentStateException.java
+++ b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyInconsistentStateException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Amazon.com, Inc. or its affiliates.
+ * 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
@@ -11,6 +11,7 @@
* limitations under the License.
*
*/
+
package software.amazon.lambda.powertools.idempotency.exceptions;
/**
diff --git a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyItemAlreadyExistsException.java b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyItemAlreadyExistsException.java
index 088db59c0..ba7da69bf 100644
--- a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyItemAlreadyExistsException.java
+++ b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyItemAlreadyExistsException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Amazon.com, Inc. or its affiliates.
+ * 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
@@ -11,6 +11,7 @@
* limitations under the License.
*
*/
+
package software.amazon.lambda.powertools.idempotency.exceptions;
/**
diff --git a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyItemNotFoundException.java b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyItemNotFoundException.java
index afae2554e..420829363 100644
--- a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyItemNotFoundException.java
+++ b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyItemNotFoundException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Amazon.com, Inc. or its affiliates.
+ * 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
@@ -11,15 +11,16 @@
* limitations under the License.
*
*/
+
package software.amazon.lambda.powertools.idempotency.exceptions;
/**
* Exception thrown when the item was not found in the persistence store.
*/
-public class IdempotencyItemNotFoundException extends RuntimeException{
+public class IdempotencyItemNotFoundException extends RuntimeException {
private static final long serialVersionUID = 4818288566747993032L;
public IdempotencyItemNotFoundException(String idempotencyKey) {
- super("Item with idempotency key "+ idempotencyKey + " not found");
+ super("Item with idempotency key " + idempotencyKey + " not found");
}
}
diff --git a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyKeyException.java b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyKeyException.java
index 7259dff0f..29b8bd2ec 100644
--- a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyKeyException.java
+++ b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyKeyException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Amazon.com, Inc. or its affiliates.
+ * 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
@@ -11,6 +11,7 @@
* limitations under the License.
*
*/
+
package software.amazon.lambda.powertools.idempotency.exceptions;
/**
diff --git a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyPersistenceLayerException.java b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyPersistenceLayerException.java
index fa49b746c..bfdd2d792 100644
--- a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyPersistenceLayerException.java
+++ b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyPersistenceLayerException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Amazon.com, Inc. or its affiliates.
+ * 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
@@ -11,6 +11,7 @@
* limitations under the License.
*
*/
+
package software.amazon.lambda.powertools.idempotency.exceptions;
/**
diff --git a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyValidationException.java b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyValidationException.java
index 5aee228eb..cdb2bb6a7 100644
--- a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyValidationException.java
+++ b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/exceptions/IdempotencyValidationException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Amazon.com, Inc. or its affiliates.
+ * 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
@@ -11,6 +11,7 @@
* limitations under the License.
*
*/
+
package software.amazon.lambda.powertools.idempotency.exceptions;
import software.amazon.lambda.powertools.idempotency.IdempotencyConfig;
diff --git a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/internal/IdempotencyHandler.java b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/internal/IdempotencyHandler.java
index 5ce723f04..2875ab3d1 100644
--- a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/internal/IdempotencyHandler.java
+++ b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/internal/IdempotencyHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Amazon.com, Inc. or its affiliates.
+ * 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
@@ -11,26 +11,32 @@
* limitations under the License.
*
*/
+
package software.amazon.lambda.powertools.idempotency.internal;
+import static software.amazon.lambda.powertools.idempotency.persistence.DataRecord.Status.EXPIRED;
+import static software.amazon.lambda.powertools.idempotency.persistence.DataRecord.Status.INPROGRESS;
+
import com.amazonaws.services.lambda.runtime.Context;
import com.fasterxml.jackson.databind.JsonNode;
+import java.time.Instant;
+import java.util.OptionalInt;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.amazon.lambda.powertools.idempotency.Idempotency;
-import software.amazon.lambda.powertools.idempotency.exceptions.*;
+import software.amazon.lambda.powertools.idempotency.exceptions.IdempotencyAlreadyInProgressException;
+import software.amazon.lambda.powertools.idempotency.exceptions.IdempotencyInconsistentStateException;
+import software.amazon.lambda.powertools.idempotency.exceptions.IdempotencyItemAlreadyExistsException;
+import software.amazon.lambda.powertools.idempotency.exceptions.IdempotencyItemNotFoundException;
+import software.amazon.lambda.powertools.idempotency.exceptions.IdempotencyKeyException;
+import software.amazon.lambda.powertools.idempotency.exceptions.IdempotencyPersistenceLayerException;
+import software.amazon.lambda.powertools.idempotency.exceptions.IdempotencyValidationException;
import software.amazon.lambda.powertools.idempotency.persistence.BasePersistenceStore;
import software.amazon.lambda.powertools.idempotency.persistence.DataRecord;
import software.amazon.lambda.powertools.utilities.JsonConfig;
-import java.time.Instant;
-import java.util.OptionalInt;
-
-import static software.amazon.lambda.powertools.idempotency.persistence.DataRecord.Status.EXPIRED;
-import static software.amazon.lambda.powertools.idempotency.persistence.DataRecord.Status.INPROGRESS;
-
/**
* Internal class that will handle the Idempotency, and use the {@link software.amazon.lambda.powertools.idempotency.persistence.PersistenceStore}
* to store the result of previous calls.
@@ -90,7 +96,9 @@ private Object processIdempotency() throws Throwable {
} catch (IdempotencyKeyException ike) {
throw ike;
} catch (Exception e) {
- throw new IdempotencyPersistenceLayerException("Failed to save in progress record to idempotency store. If you believe this is a Powertools for AWS Lambda (Java) bug, please open an issue.", e);
+ throw new IdempotencyPersistenceLayerException(
+ "Failed to save in progress record to idempotency store. If you believe this is a Powertools for AWS Lambda (Java) bug, please open an issue.",
+ e);
}
return getFunctionResponse();
}
@@ -121,11 +129,14 @@ private DataRecord getIdempotencyRecord() {
} catch (IdempotencyItemNotFoundException e) {
// This code path will only be triggered if the record is removed between saveInProgress and getRecord
LOG.debug("An existing idempotency record was deleted before we could fetch it");
- throw new IdempotencyInconsistentStateException("saveInProgress and getRecord return inconsistent results", e);
+ throw new IdempotencyInconsistentStateException("saveInProgress and getRecord return inconsistent results",
+ e);
} catch (IdempotencyValidationException | IdempotencyKeyException vke) {
throw vke;
} catch (Exception e) {
- throw new IdempotencyPersistenceLayerException("Failed to get record from idempotency store. If you believe this is a Powertools for AWS Lambda (Java) bug, please open an issue.", e);
+ throw new IdempotencyPersistenceLayerException(
+ "Failed to get record from idempotency store. If you believe this is a Powertools for AWS Lambda (Java) bug, please open an issue.",
+ e);
}
}
@@ -144,19 +155,24 @@ private Object handleForStatus(DataRecord record) {
if (INPROGRESS.equals(record.getStatus())) {
if (record.getInProgressExpiryTimestamp().isPresent()
&& record.getInProgressExpiryTimestamp().getAsLong() < Instant.now().toEpochMilli()) {
- throw new IdempotencyInconsistentStateException("Item should have been expired in-progress because it already time-outed.");
+ throw new IdempotencyInconsistentStateException(
+ "Item should have been expired in-progress because it already time-outed.");
}
- throw new IdempotencyAlreadyInProgressException("Execution already in progress with idempotency key: " + record.getIdempotencyKey());
+ throw new IdempotencyAlreadyInProgressException(
+ "Execution already in progress with idempotency key: " + record.getIdempotencyKey());
}
Class> returnType = ((MethodSignature) pjp.getSignature()).getReturnType();
try {
- LOG.debug("Response for key '{}' retrieved from idempotency store, skipping the function", record.getIdempotencyKey());
- if (returnType.equals(String.class))
+ LOG.debug("Response for key '{}' retrieved from idempotency store, skipping the function",
+ record.getIdempotencyKey());
+ if (returnType.equals(String.class)) {
return record.getResponseData();
+ }
return JsonConfig.get().getObjectMapper().reader().readValue(record.getResponseData(), returnType);
} catch (Exception e) {
- throw new IdempotencyPersistenceLayerException("Unable to get function response as " + returnType.getSimpleName(), e);
+ throw new IdempotencyPersistenceLayerException(
+ "Unable to get function response as " + returnType.getSimpleName(), e);
}
}
@@ -172,7 +188,9 @@ private Object getFunctionResponse() throws Throwable {
} catch (IdempotencyKeyException ke) {
throw ke;
} catch (Exception e) {
- throw new IdempotencyPersistenceLayerException("Failed to delete record from idempotency store. If you believe this is a Powertools for AWS Lambda (Java) bug, please open an issue.", e);
+ throw new IdempotencyPersistenceLayerException(
+ "Failed to delete record from idempotency store. If you believe this is a Powertools for AWS Lambda (Java) bug, please open an issue.",
+ e);
}
throw handlerException;
}
@@ -180,7 +198,9 @@ private Object getFunctionResponse() throws Throwable {
try {
persistenceStore.saveSuccess(data, response, Instant.now());
} catch (Exception e) {
- throw new IdempotencyPersistenceLayerException("Failed to update record state to success in idempotency store. If you believe this is a Powertools for AWS Lambda (Java) bug, please open an issue.", e);
+ throw new IdempotencyPersistenceLayerException(
+ "Failed to update record state to success in idempotency store. If you believe this is a Powertools for AWS Lambda (Java) bug, please open an issue.",
+ e);
}
return response;
}
diff --git a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/internal/IdempotentAspect.java b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/internal/IdempotentAspect.java
index dc2703e64..d34dd72dd 100644
--- a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/internal/IdempotentAspect.java
+++ b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/internal/IdempotentAspect.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Amazon.com, Inc. or its affiliates.
+ * 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
@@ -11,15 +11,20 @@
* limitations under the License.
*
*/
+
package software.amazon.lambda.powertools.idempotency.internal;
+import static software.amazon.lambda.powertools.core.internal.LambdaHandlerProcessor.placedOnRequestHandler;
+
+import com.amazonaws.services.lambda.runtime.Context;
import com.fasterxml.jackson.databind.JsonNode;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
-import com.amazonaws.services.lambda.runtime.Context;
import software.amazon.lambda.powertools.idempotency.Constants;
import software.amazon.lambda.powertools.idempotency.Idempotency;
import software.amazon.lambda.powertools.idempotency.IdempotencyKey;
@@ -27,11 +32,6 @@
import software.amazon.lambda.powertools.idempotency.exceptions.IdempotencyConfigurationException;
import software.amazon.lambda.powertools.utilities.JsonConfig;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-
-import static software.amazon.lambda.powertools.core.internal.LambdaHandlerProcessor.placedOnRequestHandler;
-
/**
* Aspect that handles the {@link Idempotent} annotation.
* It uses the {@link IdempotencyHandler} to actually do the job.
@@ -48,19 +48,21 @@ public Object around(ProceedingJoinPoint pjp,
Idempotent idempotent) throws Throwable {
String idempotencyDisabledEnv = System.getenv().get(Constants.IDEMPOTENCY_DISABLED_ENV);
- if (idempotencyDisabledEnv != null && !idempotencyDisabledEnv.equalsIgnoreCase("false")) {
+ if (idempotencyDisabledEnv != null && !"false".equalsIgnoreCase(idempotencyDisabledEnv)) {
return pjp.proceed(pjp.getArgs());
}
Method method = ((MethodSignature) pjp.getSignature()).getMethod();
if (method.getReturnType().equals(void.class)) {
- throw new IdempotencyConfigurationException("The annotated method doesn't return anything. Unable to perform idempotency on void return type");
+ throw new IdempotencyConfigurationException(
+ "The annotated method doesn't return anything. Unable to perform idempotency on void return type");
}
boolean isHandler = placedOnRequestHandler(pjp);
JsonNode payload = getPayload(pjp, method, isHandler);
if (payload == null) {
- throw new IdempotencyConfigurationException("Unable to get payload from the method. Ensure there is at least one parameter or that you use @IdempotencyKey");
+ throw new IdempotencyConfigurationException(
+ "Unable to get payload from the method. Ensure there is at least one parameter or that you use @IdempotencyKey");
}
Context lambdaContext;
@@ -76,7 +78,8 @@ public Object around(ProceedingJoinPoint pjp,
/**
* Retrieve the payload from the annotated method parameters
- * @param pjp joinPoint
+ *
+ * @param pjp joinPoint
* @param method the annotated method
* @return the payload used for idempotency
*/
diff --git a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/internal/cache/LRUCache.java b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/internal/cache/LRUCache.java
index a017c211a..b57ad2977 100644
--- a/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/internal/cache/LRUCache.java
+++ b/powertools-idempotency/src/main/java/software/amazon/lambda/powertools/idempotency/internal/cache/LRUCache.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 Amazon.com, Inc. or its affiliates.
+ * 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
@@ -11,6 +11,7 @@
* limitations under the License.
*
*/
+
package software.amazon.lambda.powertools.idempotency.internal.cache;
import java.util.LinkedHashMap;
@@ -19,6 +20,7 @@
/**
* Implementation of a simple LRU Cache based on a {@link LinkedHashMap}
* See here.
+ *
* @param powertools_json(body)
for APIGatewayProxyRequestEvent and APIGatewayV2HTTPEventRecords[*].powertools_json(body)
for SQSEventRecords[0].Sns.Message | powertools_json(@)
for SNSEventdetail
for ScheduledEvent (EventBridge / CloudWatch events)Records[*].kinesis.powertools_json(powertools_base64(data))
for KinesisEventRecords[*].powertools_json(powertools_base64(data))
for KinesisFirehoseEventpowertools_json(body)
for APIGatewayProxyRequestEvent and APIGatewayV2HTTPEventRecords[*].powertools_json(body)
for SQSEventRecords[0].Sns.Message | powertools_json(@)
for SNSEventdetail
for ScheduledEvent (EventBridge / CloudWatch events)Records[*].kinesis.powertools_json(powertools_base64(data))
for KinesisEventRecords[*].powertools_json(powertools_base64(data))
for KinesisFirehoseEvent
* Use the {@link Builder} to create a new instance.
@@ -83,7 +89,7 @@ private DynamoDBPersistenceStore(String tableName,
this.dynamoDbClient = client;
} else {
String idempotencyDisabledEnv = System.getenv().get(Constants.IDEMPOTENCY_DISABLED_ENV);
- if (idempotencyDisabledEnv == null || idempotencyDisabledEnv.equalsIgnoreCase("false")) {
+ if (idempotencyDisabledEnv == null || "false".equalsIgnoreCase(idempotencyDisabledEnv)) {
this.dynamoDbClient = DynamoDbClient.builder()
.httpClient(UrlConnectionHttpClient.builder().build())
.region(Region.of(System.getenv(AWS_REGION_ENV)))
@@ -96,6 +102,10 @@ private DynamoDBPersistenceStore(String tableName,
}
}
+ public static Builder builder() {
+ return new Builder();
+ }
+
@Override
public DataRecord getRecord(String idempotencyKey) throws IdempotencyItemNotFoundException {
GetItemResponse response = dynamoDbClient.getItem(
@@ -133,7 +143,9 @@ public void putRecord(DataRecord record, Instant now) throws IdempotencyItemAlre
item.put(this.statusAttr, AttributeValue.builder().s(record.getStatus().toString()).build());
if (record.getInProgressExpiryTimestamp().isPresent()) {
- item.put(this.inProgressExpiryAttr, AttributeValue.builder().n(String.valueOf(record.getInProgressExpiryTimestamp().getAsLong())).build());
+ item.put(this.inProgressExpiryAttr,
+ AttributeValue.builder().n(String.valueOf(record.getInProgressExpiryTimestamp().getAsLong()))
+ .build());
}
if (this.payloadValidationEnabled) {
@@ -151,9 +163,12 @@ public void putRecord(DataRecord record, Instant now) throws IdempotencyItemAlre
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
Map
@@ -67,18 +75,18 @@ protected String getValue(String key) {
// so that we can the initial token. If we already have a session, we can take
// the next request token from there.
EstablishedSession establishedSession = establishedSessions.getOrDefault(key, null);
- String sessionToken = establishedSession != null?
+ String sessionToken = establishedSession != null ?
establishedSession.nextSessionToken :
client.startConfigurationSession(StartConfigurationSessionRequest.builder()
- .applicationIdentifier(this.application)
- .environmentIdentifier(this.environment)
- .configurationProfileIdentifier(key)
- .build())
- .initialConfigurationToken();
+ .applicationIdentifier(this.application)
+ .environmentIdentifier(this.environment)
+ .configurationProfileIdentifier(key)
+ .build())
+ .initialConfigurationToken();
// Get the configuration using the token
GetLatestConfigurationResponse response = client.getLatestConfiguration(GetLatestConfigurationRequest.builder()
- .configurationToken(sessionToken)
+ .configurationToken(sessionToken)
.build());
// Get the next session token we'll use next time we are asked for this key
@@ -87,11 +95,12 @@ protected String getValue(String key) {
// Get the value of the key. Note that AppConfig will return null if the value
// has not changed since we last asked for it in this session - in this case
// we return the value we stashed at last request.
- String value = response.configuration() != null?
+ String value = response.configuration() != null ?
response.configuration().asUtf8String() : // if we have a new value, use it
- establishedSession != null?
- establishedSession.lastConfigurationValue : // if we don't but we have a previous value, use that
- null; // otherwise we've got no value
+ establishedSession != null ?
+ establishedSession.lastConfigurationValue :
+ // if we don't but we have a previous value, use that
+ null; // otherwise we've got no value
// Update the cache so we can get the next value later
establishedSessions.put(key, new EstablishedSession(nextSessionToken, value));
@@ -102,16 +111,18 @@ protected String getValue(String key) {
@Override
protected Map
* You can specify {@link SecretsProvider}, {@link SSMProvider} or create your
* custom provider by extending {@link BaseProvider} if you need to integrate with a different parameter store.
- * @deprecated You should not use this method directly but a typed one (getSecretsProvider, getSsmProvider, getDynamoDbProvider, getAppConfigProvider), will be removed in v2
+ *
* @return a {@link SecretsProvider}
+ * @deprecated You should not use this method directly but a typed one (getSecretsProvider, getSsmProvider, getDynamoDbProvider, getAppConfigProvider), will be removed in v2
*/
// TODO in v2: remove public access to this and review how we get providers (it was not designed for DDB and AppConfig in mind initially)
public static
* If you need to customize the region, or other part of the client, use {@link ParamManager#getSecretsProvider(SecretsManagerClient)} instead.
+ *
* @return a {@link SecretsProvider}
*/
public static SecretsProvider getSecretsProvider() {
@@ -65,6 +68,7 @@ public static SecretsProvider getSecretsProvider() {
/**
* Get a {@link SSMProvider} with default {@link SsmClient}.
* If you need to customize the region, or other part of the client, use {@link ParamManager#getSsmProvider(SsmClient)} instead.
+ *
* @return a {@link SSMProvider}
*/
public static SSMProvider getSsmProvider() {
@@ -89,6 +93,7 @@ public static DynamoDbProvider getDynamoDbProvider(String tableName) {
/**
* Get a {@link AppConfigProvider} with default {@link AppConfigDataClient}.
* If you need to customize the region, or other part of the client, use {@link ParamManager#getAppConfigProvider(AppConfigDataClient, String, String)} instead.
+ *
* @return a {@link AppConfigProvider}
*/
public static AppConfigProvider getAppConfigProvider(String environment, String application) {
@@ -107,6 +112,7 @@ public static AppConfigProvider getAppConfigProvider(String environment, String
/**
* Get a {@link SecretsProvider} with your custom {@link SecretsManagerClient}.
* Use this to configure region or other part of the client. Use {@link ParamManager#getSsmProvider()} if you don't need this customization.
+ *
* @return a {@link SecretsProvider}
*/
public static SecretsProvider getSecretsProvider(SecretsManagerClient client) {
@@ -120,6 +126,7 @@ public static SecretsProvider getSecretsProvider(SecretsManagerClient client) {
/**
* Get a {@link SSMProvider} with your custom {@link SsmClient}.
* Use this to configure region or other part of the client. Use {@link ParamManager#getSsmProvider()} if you don't need this customization.
+ *
* @return a {@link SSMProvider}
*/
public static SSMProvider getSsmProvider(SsmClient client) {
@@ -133,6 +140,7 @@ public static SSMProvider getSsmProvider(SsmClient client) {
/**
* Get a {@link DynamoDbProvider} with your custom {@link DynamoDbClient}.
* Use this to configure region or other part of the client. Use {@link ParamManager#getDynamoDbProvider(String)} )} if you don't need this customization.
+ *
* @return a {@link DynamoDbProvider}
*/
public static DynamoDbProvider getDynamoDbProvider(DynamoDbClient client, String table) {
@@ -143,13 +151,15 @@ public static DynamoDbProvider getDynamoDbProvider(DynamoDbClient client, String
.withTransformationManager(transformationManager)
.build());
}
-
+
/**
* Get a {@link AppConfigProvider} with your custom {@link AppConfigDataClient}.
* Use this to configure region or other part of the client. Use {@link ParamManager#getAppConfigProvider(String, String)} if you don't need this customization.
+ *
* @return a {@link AppConfigProvider}
*/
- public static AppConfigProvider getAppConfigProvider(AppConfigDataClient client, String environment, String application) {
+ public static AppConfigProvider getAppConfigProvider(AppConfigDataClient client, String environment,
+ String application) {
return (AppConfigProvider) providers.computeIfAbsent(AppConfigProvider.class, (k) -> AppConfigProvider.builder()
.withClient(client)
.withCacheManager(cacheManager)
@@ -168,10 +178,11 @@ public static TransformationManager getTransformationManager() {
return transformationManager;
}
- static
*
@@ -88,14 +88,24 @@ public class SSMProvider extends BaseProvider {
/**
* Constructor with only a CacheManager
- *
+ *
*
@@ -59,7 +59,7 @@ public class SecretsProvider extends BaseProvider {
/**
* Constructor with custom {@link SecretsManagerClient}.
* Use when you need to customize region or any other attribute of the client.
- *
+ *
- *
+ *
@@ -50,15 +50,18 @@ public boolean shouldTransform() {
*/
public String performBasicTransformation(String value) {
if (transformer == null) {
- throw new IllegalStateException("You cannot perform a transformation without Transformer, use the provider.withTransformation() method to specify it.");
+ throw new IllegalStateException(
+ "You cannot perform a transformation without Transformer, use the provider.withTransformation() method to specify it.");
}
if (!BasicTransformer.class.isAssignableFrom(transformer)) {
throw new IllegalStateException("Wrong Transformer for a String, choose a BasicTransformer.");
}
try {
- BasicTransformer basicTransformer = (BasicTransformer) transformer.getDeclaredConstructor().newInstance(null);
+ BasicTransformer basicTransformer =
+ (BasicTransformer) transformer.getDeclaredConstructor().newInstance(null);
return basicTransformer.applyTransformation(value);
- } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
+ } catch (InstantiationException | IllegalAccessException | NoSuchMethodException |
+ InvocationTargetException e) {
throw new TransformationException(e);
}
}
@@ -66,19 +69,21 @@ public String performBasicTransformation(String value) {
/**
* Transform a String in a Java Object.
*
- * @param value the value to transform
+ * @param value the value to transform
* @param targetClass the type of the target object.
* @return the value transformed in an object ot type T.
*/
public