diff --git a/.doc_gen/metadata/controltower_metadata.yaml b/.doc_gen/metadata/controltower_metadata.yaml
index 083079b4db1..01f3fcfc2ab 100644
--- a/.doc_gen/metadata/controltower_metadata.yaml
+++ b/.doc_gen/metadata/controltower_metadata.yaml
@@ -4,6 +4,15 @@ controltower_Hello:
synopsis: get started using &CTower;.
category: Hello
languages:
+ Java:
+ versions:
+ - sdk_version: 2
+ github: javav2/example_code/controltower
+ sdkguide:
+ excerpts:
+ - description:
+ snippet_tags:
+ - controltower.java2.hello.main
Python:
versions:
- sdk_version: 3
@@ -25,6 +34,15 @@ controltower_Hello:
controltower_ListBaselines:
languages:
+ Java:
+ versions:
+ - sdk_version: 2
+ github: javav2/example_code/controltower
+ sdkguide:
+ excerpts:
+ - description:
+ snippet_tags:
+ - controltower.java2.list_baselines.main
Python:
versions:
- sdk_version: 3
@@ -47,6 +65,15 @@ controltower_ListBaselines:
controltower_ListEnabledBaselines:
languages:
+ Java:
+ versions:
+ - sdk_version: 2
+ github: javav2/example_code/controltower
+ sdkguide:
+ excerpts:
+ - description:
+ snippet_tags:
+ - controltower.java2.list_enabled_baselines.main
Python:
versions:
- sdk_version: 3
@@ -69,6 +96,15 @@ controltower_ListEnabledBaselines:
controltower_EnableBaseline:
languages:
+ Java:
+ versions:
+ - sdk_version: 2
+ github: javav2/example_code/controltower
+ sdkguide:
+ excerpts:
+ - description:
+ snippet_tags:
+ - controltower.java2.enable_baseline.main
Python:
versions:
- sdk_version: 3
@@ -91,6 +127,15 @@ controltower_EnableBaseline:
controltower_ResetEnabledBaseline:
languages:
+ Java:
+ versions:
+ - sdk_version: 2
+ github: javav2/example_code/controltower
+ sdkguide:
+ excerpts:
+ - description:
+ snippet_tags:
+ - controltower.java2.reset_enabled_baseline.main
Python:
versions:
- sdk_version: 3
@@ -113,6 +158,15 @@ controltower_ResetEnabledBaseline:
controltower_DisableBaseline:
languages:
+ Java:
+ versions:
+ - sdk_version: 2
+ github: javav2/example_code/controltower
+ sdkguide:
+ excerpts:
+ - description:
+ snippet_tags:
+ - controltower.java2.disable_baseline.main
Python:
versions:
- sdk_version: 3
@@ -135,6 +189,15 @@ controltower_DisableBaseline:
controltower_ListEnabledControls:
languages:
+ Java:
+ versions:
+ - sdk_version: 2
+ github: javav2/example_code/controltower
+ sdkguide:
+ excerpts:
+ - description:
+ snippet_tags:
+ - controltower.java2.list_enabled_controls.main
Python:
versions:
- sdk_version: 3
@@ -157,6 +220,15 @@ controltower_ListEnabledControls:
controltower_EnableControl:
languages:
+ Java:
+ versions:
+ - sdk_version: 2
+ github: javav2/example_code/controltower
+ sdkguide:
+ excerpts:
+ - description:
+ snippet_tags:
+ - controltower.java2.enable_control.main
Python:
versions:
- sdk_version: 3
@@ -179,6 +251,15 @@ controltower_EnableControl:
controltower_GetControlOperation:
languages:
+ Java:
+ versions:
+ - sdk_version: 2
+ github: javav2/example_code/controltower
+ sdkguide:
+ excerpts:
+ - description:
+ snippet_tags:
+ - controltower.java2.get_control_operation.main
Python:
versions:
- sdk_version: 3
@@ -201,6 +282,15 @@ controltower_GetControlOperation:
controltower_DisableControl:
languages:
+ Java:
+ versions:
+ - sdk_version: 2
+ github: javav2/example_code/controltower
+ sdkguide:
+ excerpts:
+ - description:
+ snippet_tags:
+ - controltower.java2.disable_control.main
Python:
versions:
- sdk_version: 3
@@ -223,6 +313,15 @@ controltower_DisableControl:
controltower_ListLandingZones:
languages:
+ Java:
+ versions:
+ - sdk_version: 2
+ github: javav2/example_code/controltower
+ sdkguide:
+ excerpts:
+ - description:
+ snippet_tags:
+ - controltower.java2.list_landing_zones.main
Python:
versions:
- sdk_version: 3
@@ -245,6 +344,15 @@ controltower_ListLandingZones:
controltower_GetBaselineOperation:
languages:
+ Java:
+ versions:
+ - sdk_version: 2
+ github: javav2/example_code/controltower
+ sdkguide:
+ excerpts:
+ - description:
+ snippet_tags:
+ - controltower.java2.list_landing_zones.main
Python:
versions:
- sdk_version: 3
@@ -272,6 +380,16 @@ controltower_Scenario:
- List, enable, get, and disable controls.
category: Basics
languages:
+ Java:
+ versions:
+ - sdk_version: 2
+ github: javav2/example_code/controltower
+ sdkguide:
+ excerpts:
+ - description: Run an interactive scenario demonstrating &CTowerlong; features.
+ snippet_tags:
+ - controltower.java2.controltower_scenario.main
+ - controltower.java2.controltower_actions.main
Python:
versions:
- sdk_version: 3
diff --git a/javav2/example_code/controltower/README.md b/javav2/example_code/controltower/README.md
new file mode 100644
index 00000000000..09d4fcc4a63
--- /dev/null
+++ b/javav2/example_code/controltower/README.md
@@ -0,0 +1,119 @@
+# AWS Control Tower code examples for the SDK for Java 2.x
+
+## Overview
+
+Shows how to use the AWS SDK for Java 2.x to work with AWS Control Tower.
+
+
+
+
+_AWS Control Tower enables you to enforce and manage governance rules for security, operations, and compliance at scale across all your organizations and accounts._
+
+## ⚠ Important
+
+* Running this code might result in charges to your AWS account. For more details, see [AWS Pricing](https://aws.amazon.com/pricing/) and [Free Tier](https://aws.amazon.com/free/).
+* Running the tests might result in charges to your AWS account.
+* We recommend that you grant your code least privilege. At most, grant only the minimum permissions required to perform the task. For more information, see [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege).
+* This code is not tested in every AWS Region. For more information, see [AWS Regional Services](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services).
+
+
+
+
+## Code examples
+
+### Prerequisites
+
+For prerequisites, see the [README](../../README.md#Prerequisites) in the `javav2` folder.
+
+
+
+
+
+### Get started
+
+- [Hello AWS Control Tower](src/main/java/com/example/controltower/HelloControlTower.java#L28) (`ListBaselines`)
+
+
+### Basics
+
+Code examples that show you how to perform the essential operations within a service.
+
+- [Learn the basics](src/main/java/com/example/controltower/ControlTowerActions.java)
+
+
+### Single actions
+
+Code excerpts that show you how to call individual service functions.
+
+- [DisableBaseline](src/main/java/com/example/controltower/ControlTowerActions.java#L241)
+- [DisableControl](src/main/java/com/example/controltower/ControlTowerActions.java#L431)
+- [EnableBaseline](src/main/java/com/example/controltower/ControlTowerActions.java#L188)
+- [EnableControl](src/main/java/com/example/controltower/ControlTowerActions.java#L377)
+- [GetBaselineOperation](src/main/java/com/example/controltower/ControlTowerActions.java#L38)
+- [GetControlOperation](src/main/java/com/example/controltower/ControlTowerActions.java#L474)
+- [ListBaselines](src/main/java/com/example/controltower/ControlTowerActions.java#L88)
+- [ListEnabledBaselines](src/main/java/com/example/controltower/ControlTowerActions.java#L138)
+- [ListEnabledControls](src/main/java/com/example/controltower/ControlTowerActions.java#L324)
+- [ListLandingZones](src/main/java/com/example/controltower/ControlTowerActions.java#L38)
+- [ResetEnabledBaseline](src/main/java/com/example/controltower/ControlTowerActions.java#L548)
+
+
+
+
+
+## Run the examples
+
+### Instructions
+
+
+
+
+
+#### Hello AWS Control Tower
+
+This example shows you how to get started using AWS Control Tower.
+
+
+#### Learn the basics
+
+This example shows you how to do the following:
+
+- List landing zones.
+- List, enable, get, reset, and disable baselines.
+- List, enable, get, and disable controls.
+
+
+
+
+
+
+
+
+
+### Tests
+
+⚠ Running tests might result in charges to your AWS account.
+
+
+To find instructions for running these tests, see the [README](../../README.md#Tests)
+in the `javav2` folder.
+
+
+
+
+
+
+## Additional resources
+
+- [AWS Control Tower User Guide](https://docs.aws.amazon.com/controltower/latest/userguide/what-is-control-tower.html)
+- [AWS Control Tower API Reference](https://docs.aws.amazon.com/controltower/latest/APIReference/Welcome.html)
+- [SDK for Java 2.x AWS Control Tower reference](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/controltower/package-summary.html)
+
+
+
+
+---
+
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+
+SPDX-License-Identifier: Apache-2.0
diff --git a/javav2/example_code/controltower/pom.xml b/javav2/example_code/controltower/pom.xml
new file mode 100644
index 00000000000..46e87718415
--- /dev/null
+++ b/javav2/example_code/controltower/pom.xml
@@ -0,0 +1,90 @@
+
+
+ 4.0.0
+ aws.example
+ controltower
+ 1.0-SNAPSHOT
+
+ 17
+ 17
+ UTF-8
+
+
+
+
+ software.amazon.awssdk
+ bom
+ 2.28.11
+ pom
+ import
+
+
+
+
+
+ software.amazon.awssdk
+ controltower
+
+
+ software.amazon.awssdk
+ controlcatalog
+
+
+ org.slf4j
+ slf4j-api
+ 2.0.7
+
+
+ ch.qos.logback
+ logback-classic
+ 1.4.8
+
+
+
+ software.amazon.awssdk
+ url-connection-client
+ 2.36.2
+ compile
+
+
+ software.amazon.awssdk
+ sdk-core
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ 5.10.0
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ 5.10.0
+ test
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.11.0
+
+ 17
+ 17
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 3.1.0
+
+ com.example.controltower.ControlTowerScenario
+ us-east-1
+
+
+
+
+
\ No newline at end of file
diff --git a/javav2/example_code/controltower/src/main/java/com/example/controltower/ControlTowerActions.java b/javav2/example_code/controltower/src/main/java/com/example/controltower/ControlTowerActions.java
new file mode 100644
index 00000000000..29b2f6db20b
--- /dev/null
+++ b/javav2/example_code/controltower/src/main/java/com/example/controltower/ControlTowerActions.java
@@ -0,0 +1,588 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package com.example.controltower;
+
+import software.amazon.awssdk.services.controltower.ControlTowerClient;
+import software.amazon.awssdk.services.controltower.model.*;
+import software.amazon.awssdk.services.controltower.paginators.ListBaselinesIterable;
+import software.amazon.awssdk.services.controltower.paginators.ListEnabledBaselinesIterable;
+import software.amazon.awssdk.services.controltower.paginators.ListEnabledControlsIterable;
+import software.amazon.awssdk.services.controltower.paginators.ListLandingZonesIterable;
+import software.amazon.awssdk.services.controlcatalog.ControlCatalogClient;
+import software.amazon.awssdk.services.controlcatalog.paginators.ListControlsIterable;
+import software.amazon.awssdk.core.exception.SdkException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * Before running this Java V2 code example, set up your development
+ * environment, including your credentials.
+ *
+ * For more information, see the following documentation topic:
+ *
+ * https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html
+ *
+ * This Java code example shows how to perform AWS Control Tower operations.
+ */
+
+// snippet-start:[controltower.java2.controltower_actions.main]
+public class ControlTowerActions {
+
+ private static final Logger logger = LoggerFactory.getLogger(ControlTowerActions.class);
+
+ // snippet-start:[controltower.java2.list_landing_zones.main]
+ /**
+ * Lists all landing zones using pagination to retrieve complete results.
+ *
+ * @param controlTowerClient the Control Tower client to use for the operation
+ * @return a list of all landing zones
+ * @throws ControlTowerException if a service-specific error occurs
+ * @throws SdkException if an SDK error occurs
+ */
+ public static List listLandingZones(ControlTowerClient controlTowerClient) {
+ try {
+ List landingZones = new ArrayList<>();
+
+ String nextToken = null;
+
+ do {
+ ListLandingZonesRequest.Builder requestBuilder = ListLandingZonesRequest.builder();
+ if (nextToken != null) {
+ requestBuilder.nextToken(nextToken);
+ }
+
+ ListLandingZonesResponse response = controlTowerClient.listLandingZones(requestBuilder.build());
+
+ if (response.landingZones() != null) {
+ landingZones.addAll(response.landingZones());
+ }
+
+ nextToken = response.nextToken();
+ } while (nextToken != null);
+
+ logger.info("Retrieved {} landing zones", landingZones.size());
+ return landingZones;
+
+ } catch (ControlTowerException e) {
+ String errorCode = e.awsErrorDetails().errorCode();
+ switch (errorCode) {
+ case "AccessDeniedException":
+ logger.error("Access denied when listing landing zones: {}", e.getMessage());
+ break;
+ default:
+ logger.error("Error listing landing zones: {}", e.getMessage());
+ }
+ throw e;
+ } catch (SdkException e) {
+ logger.error("SDK error listing landing zones: {}", e.getMessage());
+ throw e;
+ }
+ }
+ // snippet-end:[controltower.java2.list_landing_zones.main]
+
+ // snippet-start:[controltower.java2.list_baselines.main]
+ /**
+ * Lists all available baselines using pagination to retrieve complete results.
+ *
+ * @param controlTowerClient the Control Tower client to use for the operation
+ * @return a list of all baselines
+ * @throws ControlTowerException if a service-specific error occurs
+ * @throws SdkException if an SDK error occurs
+ */
+ public static List listBaselines(ControlTowerClient controlTowerClient) {
+ try {
+ List baselines = new ArrayList<>();
+
+ String nextToken = null;
+
+ do {
+ ListBaselinesRequest.Builder requestBuilder = ListBaselinesRequest.builder();
+ if (nextToken != null) {
+ requestBuilder.nextToken(nextToken);
+ }
+
+ ListBaselinesResponse response = controlTowerClient.listBaselines(requestBuilder.build());
+
+ if (response.baselines() != null) {
+ baselines.addAll(response.baselines());
+ }
+
+ nextToken = response.nextToken();
+ } while (nextToken != null);
+
+ logger.info("Retrieved {} baselines", baselines.size());
+ return baselines;
+
+ } catch (ControlTowerException e) {
+ String errorCode = e.awsErrorDetails().errorCode();
+ switch (errorCode) {
+ case "AccessDeniedException":
+ logger.error("Access denied when listing baselines: {}", e.getMessage());
+ break;
+ default:
+ logger.error("Error listing baselines: {}", e.getMessage());
+ }
+ throw e;
+ } catch (SdkException e) {
+ logger.error("SDK error listing baselines: {}", e.getMessage());
+ throw e;
+ }
+ }
+ // snippet-end:[controltower.java2.list_baselines.main]
+
+ // snippet-start:[controltower.java2.list_enabled_baselines.main]
+ /**
+ * Lists all enabled baselines using pagination to retrieve complete results.
+ *
+ * @param controlTowerClient the Control Tower client to use for the operation
+ * @return a list of all enabled baselines
+ * @throws ControlTowerException if a service-specific error occurs
+ * @throws SdkException if an SDK error occurs
+ */
+ public static List listEnabledBaselines(ControlTowerClient controlTowerClient) {
+ try {
+ List enabledBaselines = new ArrayList<>();
+
+ String nextToken = null;
+
+ do {
+ ListEnabledBaselinesRequest.Builder requestBuilder = ListEnabledBaselinesRequest.builder();
+ if (nextToken != null) {
+ requestBuilder.nextToken(nextToken);
+ }
+
+ ListEnabledBaselinesResponse response = controlTowerClient.listEnabledBaselines(requestBuilder.build());
+
+ if (response.enabledBaselines() != null) {
+ enabledBaselines.addAll(response.enabledBaselines());
+ }
+
+ nextToken = response.nextToken();
+ } while (nextToken != null);
+
+ logger.info("Retrieved {} enabled baselines", enabledBaselines.size());
+ return enabledBaselines;
+
+ } catch (ControlTowerException e) {
+ String errorCode = e.awsErrorDetails().errorCode();
+ switch (errorCode) {
+ case "ResourceNotFoundException":
+ logger.error("Target not found when listing enabled baselines: {}", e.getMessage());
+ break;
+ default:
+ logger.error("Error listing enabled baselines: {}", e.getMessage());
+ }
+ throw e;
+ } catch (SdkException e) {
+ logger.error("SDK error listing enabled baselines: {}", e.getMessage());
+ throw e;
+ }
+ }
+ // snippet-end:[controltower.java2.list_enabled_baselines.main]
+
+ // snippet-start:[controltower.java2.enable_baseline.main]
+ /**
+ * Enables a baseline for a specified target.
+ *
+ * @param controlTowerClient the Control Tower client to use for the operation
+ * @param baselineIdentifier the identifier of the baseline to enable
+ * @param baselineVersion the version of the baseline to enable
+ * @param targetIdentifier the identifier of the target (e.g., OU ARN)
+ * @return the operation identifier
+ * @throws ControlTowerException if a service-specific error occurs
+ * @throws SdkException if an SDK error occurs
+ */
+ public static String enableBaseline(ControlTowerClient controlTowerClient,
+ String baselineIdentifier,
+ String baselineVersion,
+ String targetIdentifier) {
+ try {
+ EnableBaselineRequest request = EnableBaselineRequest.builder()
+ .baselineIdentifier(baselineIdentifier)
+ .baselineVersion(baselineVersion)
+ .targetIdentifier(targetIdentifier)
+ .build();
+
+ EnableBaselineResponse response = controlTowerClient.enableBaseline(request);
+ String operationId = response.operationIdentifier();
+
+ logger.info("Enabled baseline with operation ID: {}", operationId);
+ return operationId;
+
+ } catch (ControlTowerException e) {
+ String errorCode = e.awsErrorDetails().errorCode();
+ switch (errorCode) {
+ case "ValidationException":
+ if (e.getMessage().contains("already enabled")) {
+ logger.info("Baseline is already enabled for this target");
+ return null;
+ }
+ logger.error("Validation error enabling baseline: {}", e.getMessage());
+ break;
+ case "ConflictException":
+ logger.error("Conflict enabling baseline: {}", e.getMessage());
+ break;
+ default:
+ logger.error("Error enabling baseline: {}", e.getMessage());
+ }
+ throw e;
+ } catch (SdkException e) {
+ logger.error("SDK error enabling baseline: {}", e.getMessage());
+ throw e;
+ }
+ }
+ // snippet-end:[controltower.java2.enable_baseline.main]
+
+ // snippet-start:[controltower.java2.disable_baseline.main]
+ /**
+ * Disables a baseline for a specified target.
+ *
+ * @param controlTowerClient the Control Tower client to use for the operation
+ * @param enabledBaselineIdentifier the identifier of the enabled baseline to disable
+ * @return the operation identifier
+ * @throws ControlTowerException if a service-specific error occurs
+ * @throws SdkException if an SDK error occurs
+ */
+ public static String disableBaseline(ControlTowerClient controlTowerClient,
+ String enabledBaselineIdentifier) {
+ try {
+ DisableBaselineRequest request = DisableBaselineRequest.builder()
+ .enabledBaselineIdentifier(enabledBaselineIdentifier)
+ .build();
+
+ DisableBaselineResponse response = controlTowerClient.disableBaseline(request);
+ String operationId = response.operationIdentifier();
+
+ logger.info("Disabled baseline with operation ID: {}", operationId);
+ return operationId;
+
+ } catch (ControlTowerException e) {
+ String errorCode = e.awsErrorDetails().errorCode();
+ switch (errorCode) {
+ case "ConflictException":
+ logger.error("Conflict disabling baseline: {}", e.getMessage());
+ break;
+ case "ResourceNotFoundException":
+ logger.error("Baseline not found for disabling: {}", e.getMessage());
+ break;
+ default:
+ logger.error("Error disabling baseline: {}", e.getMessage());
+ }
+ throw e;
+ } catch (SdkException e) {
+ logger.error("SDK error disabling baseline: {}", e.getMessage());
+ throw e;
+ }
+ }
+ // snippet-end:[controltower.java2.disable_baseline.main]
+
+ // snippet-start:[controltower.java2.get_baseline_operation.main]
+ /**
+ * Gets the status of a baseline operation.
+ *
+ * @param controlTowerClient the Control Tower client to use for the operation
+ * @param operationIdentifier the identifier of the operation
+ * @return the operation status
+ * @throws ControlTowerException if a service-specific error occurs
+ * @throws SdkException if an SDK error occurs
+ */
+ public static BaselineOperationStatus getBaselineOperation(ControlTowerClient controlTowerClient,
+ String operationIdentifier) {
+ try {
+ GetBaselineOperationRequest request = GetBaselineOperationRequest.builder()
+ .operationIdentifier(operationIdentifier)
+ .build();
+
+ GetBaselineOperationResponse response = controlTowerClient.getBaselineOperation(request);
+ BaselineOperationStatus status = response.baselineOperation().status();
+
+ logger.info("Baseline operation status: {}", status);
+ return status;
+
+ } catch (ControlTowerException e) {
+ String errorCode = e.awsErrorDetails().errorCode();
+ switch (errorCode) {
+ case "ResourceNotFoundException":
+ logger.error("Baseline operation not found: {}", e.getMessage());
+ break;
+ default:
+ logger.error("Error getting baseline operation status: {}", e.getMessage());
+ }
+ throw e;
+ } catch (SdkException e) {
+ logger.error("SDK error getting baseline operation status: {}", e.getMessage());
+ throw e;
+ }
+ }
+ // snippet-end:[controltower.java2.get_baseline_operation.main]
+
+ // snippet-start:[controltower.java2.list_enabled_controls.main]
+ /**
+ * Lists all enabled controls for a specific target using pagination.
+ *
+ * @param controlTowerClient the Control Tower client to use for the operation
+ * @param targetIdentifier the identifier of the target (e.g., OU ARN)
+ * @return a list of enabled controls
+ * @throws ControlTowerException if a service-specific error occurs
+ * @throws SdkException if an SDK error occurs
+ */
+ public static List listEnabledControls(ControlTowerClient controlTowerClient,
+ String targetIdentifier) {
+ try {
+ List enabledControls = new ArrayList<>();
+
+ // Use paginator to retrieve all results
+ ListEnabledControlsIterable listIterable = controlTowerClient.listEnabledControlsPaginator(
+ ListEnabledControlsRequest.builder()
+ .targetIdentifier(targetIdentifier)
+ .build()
+ );
+
+ listIterable.stream()
+ .flatMap(response -> response.enabledControls().stream())
+ .forEach(enabledControls::add);
+
+ logger.info("Retrieved {} enabled controls for target {}", enabledControls.size(), targetIdentifier);
+ return enabledControls;
+
+ } catch (ControlTowerException e) {
+ String errorCode = e.awsErrorDetails().errorCode();
+ switch (errorCode) {
+ case "AccessDeniedException":
+ logger.error("Access denied when listing enabled controls: {}", e.getMessage());
+ break;
+ case "ResourceNotFoundException":
+ if (e.getMessage().contains("not registered with AWS Control Tower")) {
+ logger.error("Control Tower must be enabled to work with controls");
+ } else {
+ logger.error("Target not found when listing enabled controls: {}", e.getMessage());
+ }
+ break;
+ default:
+ logger.error("Error listing enabled controls: {}", e.getMessage());
+ }
+ throw e;
+ } catch (SdkException e) {
+ logger.error("SDK error listing enabled controls: {}", e.getMessage());
+ throw e;
+ }
+ }
+ // snippet-end:[controltower.java2.list_enabled_controls.main]
+
+ // snippet-start:[controltower.java2.enable_control.main]
+ /**
+ * Enables a control for a specified target.
+ *
+ * @param controlTowerClient the Control Tower client to use for the operation
+ * @param controlIdentifier the identifier of the control to enable
+ * @param targetIdentifier the identifier of the target (e.g., OU ARN)
+ * @return the operation identifier
+ * @throws ControlTowerException if a service-specific error occurs
+ * @throws SdkException if an SDK error occurs
+ */
+ public static String enableControl(ControlTowerClient controlTowerClient,
+ String controlIdentifier,
+ String targetIdentifier) {
+ try {
+ EnableControlRequest request = EnableControlRequest.builder()
+ .controlIdentifier(controlIdentifier)
+ .targetIdentifier(targetIdentifier)
+ .build();
+
+ EnableControlResponse response = controlTowerClient.enableControl(request);
+ String operationId = response.operationIdentifier();
+
+ logger.info("Enabled control with operation ID: {}", operationId);
+ return operationId;
+
+ } catch (ControlTowerException e) {
+ String errorCode = e.awsErrorDetails().errorCode();
+ switch (errorCode) {
+ case "ValidationException":
+ if (e.getMessage().contains("already enabled")) {
+ logger.info("Control is already enabled for this target");
+ return null;
+ }
+ logger.error("Validation error enabling control: {}", e.getMessage());
+ break;
+ case "ResourceNotFoundException":
+ if (e.getMessage().contains("not registered with AWS Control Tower")) {
+ logger.error("Control Tower must be enabled to work with controls");
+ } else {
+ logger.error("Control not found: {}", e.getMessage());
+ }
+ break;
+ default:
+ logger.error("Error enabling control: {}", e.getMessage());
+ }
+ throw e;
+ } catch (SdkException e) {
+ logger.error("SDK error enabling control: {}", e.getMessage());
+ throw e;
+ }
+ }
+ // snippet-end:[controltower.java2.enable_control.main]
+
+ // snippet-start:[controltower.java2.disable_control.main]
+ /**
+ * Disables a control for a specified target.
+ *
+ * @param controlTowerClient the Control Tower client to use for the operation
+ * @param controlIdentifier the identifier of the control to disable
+ * @param targetIdentifier the identifier of the target (e.g., OU ARN)
+ * @return the operation identifier
+ * @throws ControlTowerException if a service-specific error occurs
+ * @throws SdkException if an SDK error occurs
+ */
+ public static String disableControl(ControlTowerClient controlTowerClient,
+ String controlIdentifier,
+ String targetIdentifier) {
+ try {
+ DisableControlRequest request = DisableControlRequest.builder()
+ .controlIdentifier(controlIdentifier)
+ .targetIdentifier(targetIdentifier)
+ .build();
+
+ DisableControlResponse response = controlTowerClient.disableControl(request);
+ String operationId = response.operationIdentifier();
+
+ logger.info("Disabled control with operation ID: {}", operationId);
+ return operationId;
+
+ } catch (ControlTowerException e) {
+ String errorCode = e.awsErrorDetails().errorCode();
+ switch (errorCode) {
+ case "ResourceNotFoundException":
+ logger.error("Control not found for disabling: {}", e.getMessage());
+ break;
+ default:
+ logger.error("Error disabling control: {}", e.getMessage());
+ }
+ throw e;
+ } catch (SdkException e) {
+ logger.error("SDK error disabling control: {}", e.getMessage());
+ throw e;
+ }
+ }
+ // snippet-end:[controltower.java2.disable_control.main]
+
+ // snippet-start:[controltower.java2.get_control_operation.main]
+ /**
+ * Gets the status of a control operation.
+ *
+ * @param controlTowerClient the Control Tower client to use for the operation
+ * @param operationIdentifier the identifier of the operation
+ * @return the operation status
+ * @throws ControlTowerException if a service-specific error occurs
+ * @throws SdkException if an SDK error occurs
+ */
+ public static ControlOperationStatus getControlOperation(ControlTowerClient controlTowerClient,
+ String operationIdentifier) {
+ try {
+ GetControlOperationRequest request = GetControlOperationRequest.builder()
+ .operationIdentifier(operationIdentifier)
+ .build();
+
+ GetControlOperationResponse response = controlTowerClient.getControlOperation(request);
+ ControlOperationStatus status = response.controlOperation().status();
+
+ logger.info("Control operation status: {}", status);
+ return status;
+
+ } catch (ControlTowerException e) {
+ String errorCode = e.awsErrorDetails().errorCode();
+ switch (errorCode) {
+ case "ResourceNotFoundException":
+ logger.error("Control operation not found: {}", e.getMessage());
+ break;
+ default:
+ logger.error("Error getting control operation status: {}", e.getMessage());
+ }
+ throw e;
+ } catch (SdkException e) {
+ logger.error("SDK error getting control operation status: {}", e.getMessage());
+ throw e;
+ }
+ }
+ // snippet-end:[controltower.java2.get_control_operation.main]
+
+ // snippet-start:[controltower.java2.list_controls.main]
+ /**
+ * Lists all controls in the Control Tower control catalog.
+ *
+ * @param controlCatalogClient the Control Catalog client to use for the operation
+ * @return a list of controls
+ * @throws SdkException if a service-specific error occurs
+ */
+ public static List listControls(
+ ControlCatalogClient controlCatalogClient) {
+ try {
+ List controls = new ArrayList<>();
+
+ ListControlsIterable paginator = controlCatalogClient.listControlsPaginator(
+ software.amazon.awssdk.services.controlcatalog.model.ListControlsRequest.builder().build());
+
+ paginator.stream()
+ .flatMap(response -> response.controls().stream())
+ .forEach(controls::add);
+
+ logger.info("Retrieved {} controls", controls.size());
+ return controls;
+
+ } catch (SdkException e) {
+ if (e.getMessage().contains("AccessDeniedException")) {
+ logger.error("Access denied. Please ensure you have the necessary permissions.");
+ } else {
+ logger.error("Couldn't list controls. Here's why: {}", e.getMessage());
+ }
+ throw e;
+ }
+ }
+ // snippet-end:[controltower.java2.list_controls.main]
+
+ // snippet-start:[controltower.java2.reset_enabled_baseline.main]
+ /**
+ * Resets an enabled baseline for a specific target.
+ *
+ * @param controlTowerClient the Control Tower client to use for the operation
+ * @param enabledBaselineIdentifier the identifier of the enabled baseline to reset
+ * @return the operation identifier
+ * @throws ControlTowerException if a service-specific error occurs
+ * @throws SdkException if an SDK error occurs
+ */
+ public static String resetEnabledBaseline(ControlTowerClient controlTowerClient,
+ String enabledBaselineIdentifier) {
+ try {
+ ResetEnabledBaselineRequest request = ResetEnabledBaselineRequest.builder()
+ .enabledBaselineIdentifier(enabledBaselineIdentifier)
+ .build();
+
+ ResetEnabledBaselineResponse response = controlTowerClient.resetEnabledBaseline(request);
+ String operationId = response.operationIdentifier();
+
+ logger.info("Reset enabled baseline with operation ID: {}", operationId);
+ return operationId;
+
+ } catch (ControlTowerException e) {
+ String errorCode = e.awsErrorDetails().errorCode();
+ switch (errorCode) {
+ case "ResourceNotFoundException":
+ logger.error("Target not found: {}", e.getMessage());
+ break;
+ default:
+ logger.error("Couldn't reset enabled baseline. Here's why: {}", e.getMessage());
+ }
+ throw e;
+ } catch (SdkException e) {
+ logger.error("SDK error resetting enabled baseline: {}", e.getMessage());
+ throw e;
+ }
+ }
+ // snippet-end:[controltower.java2.reset_enabled_baseline.main]
+}
+// snippet-end:[controltower.java2.controltower_actions.main]
\ No newline at end of file
diff --git a/javav2/example_code/controltower/src/main/java/com/example/controltower/ControlTowerScenario.java b/javav2/example_code/controltower/src/main/java/com/example/controltower/ControlTowerScenario.java
new file mode 100644
index 00000000000..89d75092781
--- /dev/null
+++ b/javav2/example_code/controltower/src/main/java/com/example/controltower/ControlTowerScenario.java
@@ -0,0 +1,159 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package com.example.controltower;
+
+import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
+import software.amazon.awssdk.regions.Region;
+import software.amazon.awssdk.services.controltower.ControlTowerClient;
+import software.amazon.awssdk.services.controltower.model.*;
+
+import java.util.List;
+import java.util.Scanner;
+
+/**
+ * Before running this Java V2 code example, set up your development
+ * environment, including your credentials.
+ *
+ * For more information, see the following documentation topic:
+ *
+ * https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html
+ *
+ * This Java code example performs the following tasks:
+ *
+ * 1. Check Control Tower setup and list landing zones
+ * 2. List available baselines for governance
+ * 3. List currently enabled baselines
+ * 4. Enable a baseline for a target organizational unit
+ * 5. List enabled controls for the target
+ * 6. Enable a control for a target organizational unit
+ * 7. Monitor operation status
+ * 8. Clean up by disabling controls and baselines
+ */
+
+// snippet-start:[controltower.java2.controltower_scenario.main]
+import software.amazon.awssdk.regions.Region;
+import software.amazon.awssdk.services.controltower.ControlTowerClient;
+import software.amazon.awssdk.services.controltower.model.ControlTowerException;
+import software.amazon.awssdk.services.controltower.model.LandingZoneSummary;
+import software.amazon.awssdk.services.controltower.model.BaselineSummary;
+import software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.Scanner;
+
+public class ControlTowerScenario {
+ private static final Logger logger = LoggerFactory.getLogger(ControlTowerScenario.class);
+ public static final String DASHES = new String(new char[80]).replace("\0", "-");
+ static Scanner scanner = new Scanner(System.in);
+
+ public static void main(String[] args) {
+ // Suppress AWS SDK internal debug logs
+ System.setProperty("software.amazon.awssdk.logging.level", "WARN");
+
+ logger.info(DASHES);
+ logger.info("Welcome to the AWS Control Tower basics scenario!");
+ logger.info(DASHES);
+ logger.info("""
+ AWS Control Tower is a service that enables you to set up and govern
+ a secure, multi-account AWS environment based on best practices.
+ Control Tower orchestrates several other AWS services to build a landing zone.
+
+ This scenario will guide you through the basic operations of
+ Control Tower, including managing baselines and controls for
+ governance and compliance.
+ """);
+
+ // waitForInputToContinue(scanner);
+
+ try {
+
+ ControlTowerClient controlTowerClient = ControlTowerClient.builder()
+ .region(Region.US_EAST_1)
+ .credentialsProvider(DefaultCredentialsProvider.create())
+ .httpClientBuilder(UrlConnectionHttpClient.builder()) // avoids Apache HTTP client
+ .build() ;
+
+ runScenario(controlTowerClient);
+
+ } catch (ControlTowerException e) {
+ logger.error("Control Tower service error: {}", e.awsErrorDetails().errorMessage());
+ } catch (Exception e) {
+ logger.error("Unexpected error: {}", e.getMessage(), e);
+ }
+ }
+
+ private static void runScenario(ControlTowerClient controlTowerClient) {
+ try {
+ // Step 1: Check Control Tower setup
+ logger.info(DASHES);
+ logger.info("Step 1: Checking Control Tower setup...");
+
+ /*
+ List landingZones = ControlTowerActions.listLandingZones(controlTowerClient);
+ if (landingZones.isEmpty()) {
+ logger.warn("⚠️ No landing zones found. Control Tower may not be set up.");
+ logger.warn("Please set up Control Tower in the AWS Console first.");
+ return;
+ }
+
+ logger.info("Found {} landing zone(s):", landingZones.size());
+ for (LandingZoneSummary landingZone : landingZones) {
+ logger.info(" - ARN: {}", landingZone.arn());
+ }
+
+ waitForInputToContinue(scanner);
+
+ */
+
+ // Step 2: List available baselines
+ logger.info(DASHES);
+ logger.info("Step 2: Listing available baselines...");
+
+ List baselines = ControlTowerActions.listBaselines(controlTowerClient);
+ if (baselines.isEmpty()) {
+ logger.warn("No baselines available.");
+ } else {
+ logger.info("Available baselines:");
+ for (BaselineSummary baseline : baselines) {
+ logger.info(" - Name: {}", baseline.name());
+ logger.info(" ARN: {}", baseline.arn());
+ logger.info(" Description: {}", baseline.description());
+ }
+ }
+
+ waitForInputToContinue(scanner);
+ /*
+
+ logger.info(DASHES);
+ logger.info("🎉 Control Tower Basics scenario completed successfully!");
+
+
+ */
+ } catch (ControlTowerException e) {
+ logger.error("Control Tower service error: {}", e.awsErrorDetails().errorMessage());
+ throw e;
+ } catch (Exception e) {
+ logger.error("Unexpected error: {}", e.getMessage(), e);
+ throw e;
+ }
+ }
+
+ private static void waitForInputToContinue(Scanner scanner) {
+ while (true) {
+ System.out.println("");
+ System.out.println("Enter 'c' followed by to continue:");
+ String input = scanner.nextLine();
+
+ if (input.trim().equalsIgnoreCase("c")) {
+ logger.info("Continuing with the program...\n");
+ break;
+ } else {
+ System.out.println("Invalid input. Please try again.");
+ }
+ }
+ }
+}
+// snippet-end:[controltower.java2.controltower_scenario.main]
\ No newline at end of file
diff --git a/javav2/example_code/controltower/src/main/java/com/example/controltower/HelloControlTower.java b/javav2/example_code/controltower/src/main/java/com/example/controltower/HelloControlTower.java
new file mode 100644
index 00000000000..d3c223dd182
--- /dev/null
+++ b/javav2/example_code/controltower/src/main/java/com/example/controltower/HelloControlTower.java
@@ -0,0 +1,77 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package com.example.controltower;
+
+import software.amazon.awssdk.regions.Region;
+import software.amazon.awssdk.services.controltower.ControlTowerClient;
+import software.amazon.awssdk.services.controltower.model.ControlTowerException;
+import software.amazon.awssdk.services.controltower.model.ListBaselinesRequest;
+import software.amazon.awssdk.services.controltower.paginators.ListBaselinesIterable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Before running this Java V2 code example, set up your development
+ * environment, including your credentials.
+ *
+ * For more information, see the following documentation topic:
+ *
+ * https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html
+ *
+ * Use the AWS SDK for Java (v2) to create an AWS Control Tower client
+ * and list all available baselines.
+ * This example uses the default settings specified in your shared credentials
+ * and config files.
+ */
+
+// snippet-start:[controltower.java2.hello.main]
+public class HelloControlTower {
+
+ public static void main(String[] args) {
+ try {
+ ControlTowerClient controlTowerClient = ControlTowerClient.builder()
+ .region(Region.US_EAST_1)
+ .build() ;
+ helloControlTower(controlTowerClient);
+ } catch (ControlTowerException e) {
+ System.err.println("Control Tower error occurred: " + e.awsErrorDetails().errorMessage());
+ }
+ }
+
+ /**
+ * Use the AWS SDK for Java (v2) to create an AWS Control Tower client
+ * and list all available baselines.
+ * This example uses the default settings specified in your shared credentials
+ * and config files.
+ *
+ * @param controlTowerClient A ControlTowerClient object. This object wraps
+ * the low-level AWS Control Tower service API.
+ */
+ public static void helloControlTower(ControlTowerClient controlTowerClient) {
+ System.out.println("Hello, AWS Control Tower! Let's list available baselines:\n");
+
+ ListBaselinesIterable paginator = controlTowerClient.listBaselinesPaginator(
+ ListBaselinesRequest.builder().build());
+ List baselineNames = new ArrayList<>();
+
+ try {
+ paginator.stream()
+ .flatMap(response -> response.baselines().stream())
+ .forEach(baseline -> baselineNames.add(baseline.name()));
+
+ System.out.println(baselineNames.size() + " baseline(s) retrieved.");
+ for (String baselineName : baselineNames) {
+ System.out.println("\t" + baselineName);
+ }
+
+ } catch (ControlTowerException e) {
+ if ("AccessDeniedException".equals(e.awsErrorDetails().errorCode())) {
+ System.out.println("Access denied. Please ensure you have the necessary permissions.");
+ } else {
+ System.out.println("An error occurred: " + e.getMessage());
+ }
+ }
+ }
+}
+// snippet-end:[controltower.java2.hello.main]
diff --git a/javav2/example_code/controltower/src/main/java/resources/config.properties b/javav2/example_code/controltower/src/main/java/resources/config.properties
new file mode 100644
index 00000000000..c18495c2f4c
--- /dev/null
+++ b/javav2/example_code/controltower/src/main/java/resources/config.properties
@@ -0,0 +1,3 @@
+dataAccessRoleArn =
+s3Uri =
+documentClassifier =
diff --git a/javav2/example_code/controltower/src/main/java/resources/log4j2.xml b/javav2/example_code/controltower/src/main/java/resources/log4j2.xml
new file mode 100644
index 00000000000..fcef26f34b8
--- /dev/null
+++ b/javav2/example_code/controltower/src/main/java/resources/log4j2.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/javav2/example_code/controltower/src/test/java/ControlTowerTest.java b/javav2/example_code/controltower/src/test/java/ControlTowerTest.java
new file mode 100644
index 00000000000..c16e0049dc0
--- /dev/null
+++ b/javav2/example_code/controltower/src/test/java/ControlTowerTest.java
@@ -0,0 +1,51 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+import com.example.controltower.ControlTowerActions;
+import com.example.controltower.HelloControlTower;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.TestMethodOrder;
+import software.amazon.awssdk.regions.Region;
+import software.amazon.awssdk.services.controltower.ControlTowerClient;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
+@TestInstance(TestInstance.Lifecycle.PER_METHOD)
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class ControlTowerTest {
+ private static ControlTowerClient controlTowerClient;
+
+ @BeforeAll
+ public static void setUp() {
+ controlTowerClient = ControlTowerClient.builder()
+ .region(Region.US_EAST_1)
+ .build();
+ }
+
+ @Test
+ @Order(1)
+ public void testHelloService() {
+ assertDoesNotThrow(() -> {
+ HelloControlTower.helloControlTower(controlTowerClient);
+ });
+ System.out.println("Test 1 passed");
+ }
+
+ @Test
+ @Order(2)
+ public void testControlTowerActions() {
+ assertDoesNotThrow(() -> {
+ ControlTowerActions.listLandingZones(controlTowerClient);
+ ControlTowerActions.listBaselines(controlTowerClient);
+ ControlTowerActions.listEnabledBaselines(controlTowerClient);
+
+ // Note: Enable/disable operations require valid ARNs and are not tested here
+ // to avoid modifying the actual Control Tower configuration
+ });
+ System.out.println("Test 2 passed");
+ }
+}
\ No newline at end of file