1 /** 2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 * SPDX-License-Identifier: Apache-2.0. 4 */ 5 package software.amazon.awssdk.crt.io; 6 7 import java.util.concurrent.CompletableFuture; 8 import software.amazon.awssdk.crt.CrtResource; 9 import software.amazon.awssdk.crt.CrtRuntimeException; 10 import software.amazon.awssdk.crt.Log; 11 12 /** 13 * This class wraps the aws_client_bootstrap from aws-c-io to provide 14 * a client context for all protocol stacks in the AWS Common Runtime. 15 */ 16 public final class ClientBootstrap extends CrtResource { 17 18 private final CompletableFuture<Void> shutdownComplete = new CompletableFuture<>(); 19 20 /** 21 * Creates a new ClientBootstrap with a default HostResolver and EventLoopGroup. 22 * Most applications will only ever need one instance of this. 23 */ ClientBootstrap()24 private ClientBootstrap() throws CrtRuntimeException { 25 EventLoopGroup elg = EventLoopGroup.getOrCreateStaticDefault(); 26 HostResolver hr = HostResolver.getOrCreateStaticDefault(); 27 acquireNativeHandle(clientBootstrapNew(this, elg.getNativeHandle(), hr.getNativeHandle())); 28 // Order is likely important here 29 addReferenceTo(HostResolver.getOrCreateStaticDefault()); 30 addReferenceTo(EventLoopGroup.getOrCreateStaticDefault()); 31 } 32 33 /** 34 * Creates a new ClientBootstrap. Most applications will only ever need one instance of this. 35 * @param hr A HostResolver instance, most applications only ever have one 36 * @param elg An EventLoopGroup instance, most applications only ever have one 37 * @throws CrtRuntimeException If the provided EventLoopGroup is null or invalid, 38 * or if the system is unable to allocate space for a native client bootstrap object 39 */ ClientBootstrap(EventLoopGroup elg, HostResolver hr)40 public ClientBootstrap(EventLoopGroup elg, HostResolver hr) throws CrtRuntimeException { 41 if (elg == null) { 42 elg = EventLoopGroup.getOrCreateStaticDefault(); 43 } 44 45 if (hr == null) { 46 hr = HostResolver.getOrCreateStaticDefault(); 47 } 48 49 acquireNativeHandle(clientBootstrapNew(this, elg.getNativeHandle(), hr.getNativeHandle())); 50 51 // Order is likely important here 52 addReferenceTo(hr); 53 addReferenceTo(elg); 54 } 55 56 /** 57 * Determines whether a resource releases its dependencies at the same time the native handle is released or if it waits. 58 * Resources that wait are responsible for calling releaseReferences() manually. 59 */ 60 @Override canReleaseReferencesImmediately()61 protected boolean canReleaseReferencesImmediately() { return false; } 62 63 /** 64 * Cleans up the client bootstrap's associated native handle 65 */ 66 @Override releaseNativeHandle()67 protected void releaseNativeHandle() { 68 if (!isNull()) { 69 clientBootstrapDestroy(getNativeHandle()); 70 } 71 } 72 73 /** 74 * Called from Native when the asynchronous cleanup process needed for client bootstrap has completed. 75 */ onShutdownComplete()76 private void onShutdownComplete() { 77 Log.log(Log.LogLevel.Trace, Log.LogSubject.IoChannelBootstrap, "ClientBootstrap.onShutdownComplete"); 78 79 releaseReferences(); 80 81 this.shutdownComplete.complete(null); 82 } 83 getShutdownCompleteFuture()84 public CompletableFuture<Void> getShutdownCompleteFuture() { return shutdownComplete; } 85 86 /** 87 * Closes the static ClientBootstrap, if it exists. Primarily intended for tests that use the static 88 * default ClientBootstrap, before they call waitForNoResources(). 89 */ closeStaticDefault()90 public static void closeStaticDefault() { 91 synchronized (ClientBootstrap.class) { 92 if (staticDefaultClientBootstrap != null) { 93 staticDefaultClientBootstrap.close(); 94 } 95 staticDefaultClientBootstrap = null; 96 } 97 } 98 99 /** 100 * This default will be used when a ClientBootstrap is not explicitly passed but is needed 101 * to allow the process to function. An example of this would be in the MQTT connection creation workflow. 102 * The default ClientBootstrap will use the default EventLoopGroup and HostResolver, creating them if 103 * necessary. 104 * 105 * The default ClientBootstrap will be automatically managed and released when it's 106 * resources are being freed, not requiring any manual memory management. 107 * @return the static default ClientBootstrap 108 */ getOrCreateStaticDefault()109 public static ClientBootstrap getOrCreateStaticDefault() { 110 ClientBootstrap client = null; 111 synchronized (ClientBootstrap.class) { 112 if (staticDefaultClientBootstrap == null) { 113 staticDefaultClientBootstrap = new ClientBootstrap(); 114 } 115 116 client = staticDefaultClientBootstrap; 117 } 118 119 return client; 120 } 121 private static ClientBootstrap staticDefaultClientBootstrap; 122 123 /******************************************************************************* 124 * native methods 125 ******************************************************************************/ clientBootstrapNew(ClientBootstrap bootstrap, long elg, long hr)126 private static native long clientBootstrapNew(ClientBootstrap bootstrap, long elg, long hr) throws CrtRuntimeException; clientBootstrapDestroy(long bootstrap)127 private static native void clientBootstrapDestroy(long bootstrap); 128 }; 129