diff --git a/javav2/example_code/ssm/pom.xml b/javav2/example_code/ssm/pom.xml
index 92529ae80a2..6f9a35d21fd 100644
--- a/javav2/example_code/ssm/pom.xml
+++ b/javav2/example_code/ssm/pom.xml
@@ -89,6 +89,10 @@
slf4j-api
2.0.13
+
+ software.amazon.awssdk
+ cloudformation
+
org.apache.logging.log4j
log4j-slf4j2-impl
diff --git a/javav2/example_code/ssm/src/main/java/com/example/scenario/CloudFormationHelper.java b/javav2/example_code/ssm/src/main/java/com/example/scenario/CloudFormationHelper.java
new file mode 100644
index 00000000000..91a83befabf
--- /dev/null
+++ b/javav2/example_code/ssm/src/main/java/com/example/scenario/CloudFormationHelper.java
@@ -0,0 +1,165 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package com.example.scenario;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
+import software.amazon.awssdk.core.retry.RetryMode;
+import software.amazon.awssdk.http.async.SdkAsyncHttpClient;
+import software.amazon.awssdk.http.nio.netty.NettyNioAsyncHttpClient;
+import software.amazon.awssdk.regions.Region;
+import software.amazon.awssdk.services.cloudformation.CloudFormationAsyncClient;
+import software.amazon.awssdk.services.cloudformation.model.Capability;
+import software.amazon.awssdk.services.cloudformation.model.CloudFormationException;
+import software.amazon.awssdk.services.cloudformation.model.DescribeStacksRequest;
+import software.amazon.awssdk.services.cloudformation.model.DescribeStacksResponse;
+import software.amazon.awssdk.services.cloudformation.model.Output;
+import software.amazon.awssdk.services.cloudformation.model.Stack;
+import software.amazon.awssdk.services.cloudformation.waiters.CloudFormationAsyncWaiter;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+
+public class CloudFormationHelper {
+ private static final String CFN_TEMPLATE = "ec2-stack.yaml";
+ private static final Logger logger = LoggerFactory.getLogger(CloudFormationHelper.class);
+
+ private static CloudFormationAsyncClient cloudFormationClient;
+
+ private static CloudFormationAsyncClient getCloudFormationClient() {
+ if (cloudFormationClient == null) {
+ SdkAsyncHttpClient httpClient = NettyNioAsyncHttpClient.builder()
+ .maxConcurrency(100)
+ .connectionTimeout(Duration.ofSeconds(60))
+ .readTimeout(Duration.ofSeconds(60))
+ .writeTimeout(Duration.ofSeconds(60))
+ .build();
+
+ ClientOverrideConfiguration overrideConfig = ClientOverrideConfiguration.builder()
+ .apiCallTimeout(Duration.ofMinutes(2))
+ .apiCallAttemptTimeout(Duration.ofSeconds(90))
+ .retryStrategy(RetryMode.STANDARD)
+ .build();
+
+ cloudFormationClient = CloudFormationAsyncClient.builder()
+ .httpClient(httpClient)
+ .region(Region.US_WEST_2)
+ .overrideConfiguration(overrideConfig)
+ .build();
+ }
+ return cloudFormationClient;
+ }
+
+ public static void deployCloudFormationStack(String stackName) {
+ String templateBody;
+ boolean doesExist = describeStack(stackName);
+ if (!doesExist) {
+ try {
+ ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+ Path filePath = Paths.get(classLoader.getResource(CFN_TEMPLATE).toURI());
+ templateBody = Files.readString(filePath);
+ } catch (IOException | URISyntaxException e) {
+ throw new RuntimeException(e);
+ }
+
+ getCloudFormationClient().createStack(b -> b.stackName(stackName)
+ .templateBody(templateBody)
+ .capabilities(Capability.CAPABILITY_IAM))
+ .whenComplete((csr, t) -> {
+ if (csr != null) {
+ System.out.println("Stack creation requested, ARN is " + csr.stackId());
+ try (CloudFormationAsyncWaiter waiter = getCloudFormationClient().waiter()) {
+ waiter.waitUntilStackCreateComplete(request -> request.stackName(stackName))
+ .whenComplete((dsr, th) -> {
+ if (th != null) {
+ System.out.println("Error waiting for stack creation: " + th.getMessage());
+ } else {
+ dsr.matched().response().orElseThrow(() -> new RuntimeException("Failed to deploy"));
+ System.out.println("Stack created successfully");
+ }
+ }).join();
+ }
+ } else {
+ System.out.format("Error creating stack: " + t.getMessage(), t);
+ throw new RuntimeException(t.getCause().getMessage(), t);
+ }
+ }).join();
+ } else {
+ logger.info("{} stack already exists", CFN_TEMPLATE);
+ }
+ }
+
+ // Check to see if the Stack exists before deploying it
+ public static Boolean describeStack(String stackName) {
+ try {
+ CompletableFuture> future = getCloudFormationClient().describeStacks();
+ DescribeStacksResponse stacksResponse = (DescribeStacksResponse) future.join();
+ List stacks = stacksResponse.stacks();
+ for (Stack myStack : stacks) {
+ if (myStack.stackName().compareTo(stackName) == 0) {
+ return true;
+ }
+ }
+ } catch (CloudFormationException e) {
+ System.err.println(e.getMessage());
+ }
+ return false;
+ }
+
+ public static void destroyCloudFormationStack(String stackName) {
+ getCloudFormationClient().deleteStack(b -> b.stackName(stackName))
+ .whenComplete((dsr, t) -> {
+ if (dsr != null) {
+ System.out.println("Delete stack requested ....");
+ try (CloudFormationAsyncWaiter waiter = getCloudFormationClient().waiter()) {
+ waiter.waitUntilStackDeleteComplete(request -> request.stackName(stackName))
+ .whenComplete((waiterResponse, throwable) ->
+ System.out.println("Stack deleted successfully."))
+ .join();
+ }
+ } else {
+ System.out.format("Error deleting stack: " + t.getMessage(), t);
+ throw new RuntimeException(t.getCause().getMessage(), t);
+ }
+ }).join();
+ }
+
+ public static CompletableFuture