@@ -726,73 +726,80 @@ public CompletableFuture<String> enableControlAsync(
726726 .build ();
727727
728728 return getAsyncClient ().enableControl (request )
729- .whenComplete ((response , exception ) -> {
730- if (exception != null ) {
731- Throwable cause = exception .getCause () != null
732- ? exception .getCause ()
733- : exception ;
729+ .thenCompose (response -> {
730+ String operationId = response .operationIdentifier ();
731+ System .out .println ("Enable control operation started. Operation ID: " + operationId );
734732
735- if (cause instanceof ControlTowerException e ) {
736- String errorCode = e .awsErrorDetails ().errorCode ();
733+ CompletableFuture <String > resultFuture = new CompletableFuture <>();
737734
738- switch (errorCode ) {
739- case "ValidationException" :
740- if (e .getMessage () != null
741- && e .getMessage ().contains ("already enabled" )) {
742- // Preserve sync behavior: treat as no-op
743- return ;
744- }
735+ Runnable poller = new Runnable () {
736+ @ Override
737+ public void run () {
738+ getControlOperationAsync (operationId )
739+ .thenAccept (status -> {
740+ System .out .println ("Control operation status: " + status );
745741
746- throw new CompletionException (
747- "Validation error enabling control: %s"
748- . formatted ( e . getMessage ()),
749- e
750- );
751-
752- case "ResourceNotFoundException" :
753- if ( e . getMessage () != null
754- && e . getMessage (). contains (
755- "not registered with AWS Control Tower" )) {
756- throw new CompletionException (
757- "Control Tower must be enabled to work with controls" ,
758- e
759- );
760- }
742+ if ( status == ControlOperationStatus . SUCCEEDED
743+ || status == ControlOperationStatus . FAILED ) {
744+ resultFuture . complete ( operationId );
745+ } else {
746+ // Poll again after 30 seconds
747+ CompletableFuture . delayedExecutor ( 30 , TimeUnit . SECONDS )
748+ . execute ( this );
749+ }
750+ })
751+ . exceptionally ( ex -> {
752+ resultFuture . completeExceptionally ( ex );
753+ return null ;
754+ });
755+ }
756+ };
761757
762- throw new CompletionException (
763- "Control not found: %s"
764- .formatted (e .getMessage ()),
765- e
766- );
758+ // Start polling immediately
759+ poller .run ();
767760
768- default :
769- throw new CompletionException (
770- "Error enabling control: %s"
771- .formatted (e .getMessage ()),
772- e
773- );
774- }
761+ return resultFuture ;
762+ })
763+ .exceptionally (ex -> {
764+ Throwable cause = ex .getCause () != null ? ex .getCause () : ex ;
765+
766+ if (cause instanceof ControlTowerException e ) {
767+ String errorCode = e .awsErrorDetails ().errorCode ();
768+ String message = e .getMessage () != null ? e .getMessage () : "" ;
769+
770+ if ("ValidationException" .equals (errorCode )
771+ && message .contains ("already enabled" )) {
772+ System .out .println ("Control is already enabled for this target" );
773+ return null ;
775774 }
776775
777- if (cause instanceof SdkException ) {
778- throw new CompletionException (
779- "SDK error enabling control: %s"
780- .formatted (cause .getMessage ()),
781- cause
782- );
776+ if ("ResourceNotFoundException" .equals (errorCode )
777+ && message .contains ("not registered with AWS Control Tower" )) {
778+ System .out .println (
779+ "Control Tower must be enabled to work with controls." );
780+ return null ;
783781 }
784782
785783 throw new CompletionException (
786- "Failed to enable control" ,
784+ "Couldn't enable control: %s" .formatted (message ),
785+ e
786+ );
787+ }
788+
789+ if (cause instanceof SdkException ) {
790+ throw new CompletionException (
791+ "SDK error enabling control: %s"
792+ .formatted (cause .getMessage ()),
787793 cause
788794 );
789795 }
790- })
791- .thenApply (response ->
792- response != null ? response .operationIdentifier () : null
793- );
794- }
795796
797+ throw new CompletionException (
798+ "Failed to enable control" ,
799+ cause
800+ );
801+ });
802+ }
796803 // snippet-end:[controltower.java2.enable_control.main]
797804
798805 // snippet-start:[controltower.java2.disable_control.main]
@@ -816,41 +823,66 @@ public CompletableFuture<String> disableControlAsync(
816823 .build ();
817824
818825 return getAsyncClient ().disableControl (request )
819- .handle ((response , exception ) -> {
820-
821- if (exception != null ) {
822- Throwable cause = exception .getCause () != null
823- ? exception .getCause ()
824- : exception ;
826+ .thenCompose (response -> {
827+ String operationId = response .operationIdentifier ();
828+ System .out .println ("Disable control operation started. Operation ID: " + operationId );
825829
826- if (cause instanceof ControlTowerException e ) {
827- String errorCode = e .awsErrorDetails ().errorCode ();
830+ CompletableFuture <String > resultFuture = new CompletableFuture <>();
828831
829- if ( "ResourceNotFoundException" . equals ( errorCode ) ) {
830- // SPEC: notify user and continue
831- System . out . println (
832- "Control not found for disabling: " + e . getMessage ());
833- return null ;
834- }
832+ Runnable poller = new Runnable ( ) {
833+ @ Override
834+ public void run () {
835+ getControlOperationAsync ( operationId )
836+ . thenAccept ( status -> {
837+ System . out . println ( "Control operation status: " + status );
835838
836- throw new CompletionException (
837- "Error disabling control: " + e .getMessage (), e );
839+ if (status == ControlOperationStatus .SUCCEEDED
840+ || status == ControlOperationStatus .FAILED ) {
841+ resultFuture .complete (operationId );
842+ } else {
843+ // poll again after 30 seconds
844+ CompletableFuture .delayedExecutor (30 , TimeUnit .SECONDS )
845+ .execute (this );
846+ }
847+ })
848+ .exceptionally (ex -> {
849+ resultFuture .completeExceptionally (ex );
850+ return null ;
851+ });
838852 }
853+ };
839854
840- if (cause instanceof SdkException ) {
841- throw new CompletionException (
842- "SDK error disabling control: " + cause .getMessage (), cause );
855+ // start polling immediately
856+ poller .run ();
857+
858+ return resultFuture ;
859+ })
860+ .exceptionally (ex -> {
861+ Throwable cause = ex .getCause () != null ? ex .getCause () : ex ;
862+
863+ if (cause instanceof ControlTowerException e ) {
864+ String errorCode = e .awsErrorDetails ().errorCode ();
865+
866+ if ("ResourceNotFoundException" .equals (errorCode )) {
867+ // SPEC: notify user and continue
868+ System .out .println ("Control not found for disabling: " + e .getMessage ());
869+ return null ;
843870 }
844871
845872 throw new CompletionException (
846- "Failed to disable control" , cause );
873+ "Error disabling control: " + e . getMessage (), e );
847874 }
848875
849- // Success path
850- return response .operationIdentifier ();
851- });
876+ if (cause instanceof SdkException ) {
877+ throw new CompletionException (
878+ "SDK error disabling control: " + cause .getMessage (), cause );
879+ }
852880
881+ throw new CompletionException (
882+ "Failed to disable control" , cause );
883+ });
853884 }
885+
854886 // snippet-end:[controltower.java2.disable_control.main]
855887
856888 // snippet-start:[controltower.java2.get_control_operation.main]
0 commit comments