diff --git a/eng/pipelines/docindex.yml b/eng/pipelines/docindex.yml index c128f858955d..21e623ada65c 100644 --- a/eng/pipelines/docindex.yml +++ b/eng/pipelines/docindex.yml @@ -90,7 +90,9 @@ jobs: parameters: DailyBranchVariableName: DailyDocsBranchName - - template: /eng/pipelines/templates/steps/mvn-linux-settings-for-docs.yml + - template: /eng/pipelines/templates/steps/mvn-linux-repository-settings.yml + + - template: /eng/pipelines/templates/steps/install-rex-validation-tool.yml - task: Powershell@2 inputs: diff --git a/eng/pipelines/partner-release.yml b/eng/pipelines/partner-release.yml index 8e6e5e544a6f..2a4052c95ac0 100644 --- a/eng/pipelines/partner-release.yml +++ b/eng/pipelines/partner-release.yml @@ -37,12 +37,20 @@ extends: - template: /eng/pipelines/templates/steps/download-credscan-suppressions.yml - - task: PowerShell@2 - displayName: 'Download packages from blob storage' + - task: AzurePowerShell@5 + displayName: 'Copy from azuresdkpartnerdrops' + condition: and(succeeded(), ne(variables['SkipCopyFromPartnerDrops'], 'true')) inputs: - targetType: filePath - filePath: '$(BuildToolScripts)/copy-from-azuresdkpartnerdrops.ps1' - arguments: '$(Artifacts) ${{ parameters.BlobPath }} $(azuresdkpartnerdrops-access-key)' + azureSubscription: 'azuresdkpartnerdrops - Storage Partner Drops' + ScriptType: 'InlineScript' + azurePowerShellVersion: LatestVersion + pwsh: true + Inline: | + azcopy copy 'https://azuresdkpartnerdrops.blob.core.windows.net/drops/${{ parameters.BlobPath }}/*' '$(Artifacts)' --recursive=true + echo "Copied files:" + dir '$(Artifacts)' -r | % { $_.FullName } + env: + AZCOPY_AUTO_LOGIN_TYPE: 'PSCRED' - template: tools/java-esrp-signing/java-esrp-signing.yml@azure-sdk-build-tools parameters: diff --git a/sdk/core/azure-core-http-jdk-httpclient/src/main/java/com/azure/core/http/jdk/httpclient/JdkHttpClient.java b/sdk/core/azure-core-http-jdk-httpclient/src/main/java/com/azure/core/http/jdk/httpclient/JdkHttpClient.java index 8f8a45ef498c..f2fcd2dad7d1 100644 --- a/sdk/core/azure-core-http-jdk-httpclient/src/main/java/com/azure/core/http/jdk/httpclient/JdkHttpClient.java +++ b/sdk/core/azure-core-http-jdk-httpclient/src/main/java/com/azure/core/http/jdk/httpclient/JdkHttpClient.java @@ -12,6 +12,7 @@ import com.azure.core.http.jdk.httpclient.implementation.InputStreamTimeoutResponseSubscriber; import com.azure.core.http.jdk.httpclient.implementation.JdkHttpResponseAsync; import com.azure.core.http.jdk.httpclient.implementation.JdkHttpResponseSync; +import com.azure.core.implementation.util.HttpUtils; import com.azure.core.util.Context; import com.azure.core.util.logging.ClientLogger; import reactor.core.publisher.Mono; @@ -31,8 +32,6 @@ */ class JdkHttpClient implements HttpClient { private static final ClientLogger LOGGER = new ClientLogger(JdkHttpClient.class); - private static final String AZURE_EAGERLY_READ_RESPONSE = "azure-eagerly-read-response"; - private static final String AZURE_IGNORE_RESPONSE_BODY = "azure-ignore-response-body"; private final java.net.http.HttpClient jdkHttpClient; @@ -79,8 +78,8 @@ public Mono send(HttpRequest request) { @Override public Mono send(HttpRequest request, Context context) { - boolean eagerlyReadResponse = (boolean) context.getData(AZURE_EAGERLY_READ_RESPONSE).orElse(false); - boolean ignoreResponseBody = (boolean) context.getData(AZURE_IGNORE_RESPONSE_BODY).orElse(false); + boolean eagerlyReadResponse = (boolean) context.getData(HttpUtils.AZURE_EAGERLY_READ_RESPONSE).orElse(false); + boolean ignoreResponseBody = (boolean) context.getData(HttpUtils.AZURE_IGNORE_RESPONSE_BODY).orElse(false); Mono jdkRequestMono = Mono.fromCallable(() -> toJdkHttpRequest(request, context)); @@ -111,8 +110,8 @@ public Mono send(HttpRequest request, Context context) { @Override public HttpResponse sendSync(HttpRequest request, Context context) { - boolean eagerlyReadResponse = (boolean) context.getData(AZURE_EAGERLY_READ_RESPONSE).orElse(false); - boolean ignoreResponseBody = (boolean) context.getData(AZURE_IGNORE_RESPONSE_BODY).orElse(false); + boolean eagerlyReadResponse = (boolean) context.getData(HttpUtils.AZURE_EAGERLY_READ_RESPONSE).orElse(false); + boolean ignoreResponseBody = (boolean) context.getData(HttpUtils.AZURE_IGNORE_RESPONSE_BODY).orElse(false); java.net.http.HttpRequest jdkRequest = toJdkHttpRequest(request, context); try { diff --git a/sdk/core/azure-core-http-jdk-httpclient/src/main/java/com/azure/core/http/jdk/httpclient/JdkHttpClientBuilder.java b/sdk/core/azure-core-http-jdk-httpclient/src/main/java/com/azure/core/http/jdk/httpclient/JdkHttpClientBuilder.java index 79e2da860819..c20b141ecb1f 100644 --- a/sdk/core/azure-core-http-jdk-httpclient/src/main/java/com/azure/core/http/jdk/httpclient/JdkHttpClientBuilder.java +++ b/sdk/core/azure-core-http-jdk-httpclient/src/main/java/com/azure/core/http/jdk/httpclient/JdkHttpClientBuilder.java @@ -25,11 +25,11 @@ import java.util.Set; import java.util.concurrent.Executor; -import static com.azure.core.util.Configuration.PROPERTY_AZURE_REQUEST_CONNECT_TIMEOUT; -import static com.azure.core.util.Configuration.PROPERTY_AZURE_REQUEST_READ_TIMEOUT; -import static com.azure.core.util.Configuration.PROPERTY_AZURE_REQUEST_RESPONSE_TIMEOUT; -import static com.azure.core.util.Configuration.PROPERTY_AZURE_REQUEST_WRITE_TIMEOUT; -import static com.azure.core.util.CoreUtils.getDefaultTimeoutFromEnvironment; +import static com.azure.core.implementation.util.HttpUtils.getDefaultConnectTimeout; +import static com.azure.core.implementation.util.HttpUtils.getDefaultReadTimeout; +import static com.azure.core.implementation.util.HttpUtils.getDefaultResponseTimeout; +import static com.azure.core.implementation.util.HttpUtils.getDefaultWriteTimeout; +import static com.azure.core.implementation.util.HttpUtils.getTimeout; /** * Builder to configure and build an instance of the azure-core {@link HttpClient} type using the JDK HttpClient APIs, @@ -38,12 +38,6 @@ public class JdkHttpClientBuilder { private static final ClientLogger LOGGER = new ClientLogger(JdkHttpClientBuilder.class); - private static final Duration MINIMUM_TIMEOUT = Duration.ofMillis(1); - private static final Duration DEFAULT_CONNECTION_TIMEOUT; - private static final Duration DEFAULT_WRITE_TIMEOUT; - private static final Duration DEFAULT_RESPONSE_TIMEOUT; - private static final Duration DEFAULT_READ_TIMEOUT; - private static final String JAVA_HOME = System.getProperty("java.home"); private static final String JDK_HTTPCLIENT_ALLOW_RESTRICTED_HEADERS = "jdk.httpclient.allowRestrictedHeaders"; @@ -57,17 +51,6 @@ public class JdkHttpClientBuilder { static final Set DEFAULT_RESTRICTED_HEADERS; static { - Configuration configuration = Configuration.getGlobalConfiguration(); - - DEFAULT_CONNECTION_TIMEOUT = getDefaultTimeoutFromEnvironment(configuration, - PROPERTY_AZURE_REQUEST_CONNECT_TIMEOUT, Duration.ofSeconds(10), LOGGER); - DEFAULT_WRITE_TIMEOUT = getDefaultTimeoutFromEnvironment(configuration, PROPERTY_AZURE_REQUEST_WRITE_TIMEOUT, - Duration.ofSeconds(60), LOGGER); - DEFAULT_RESPONSE_TIMEOUT = getDefaultTimeoutFromEnvironment(configuration, - PROPERTY_AZURE_REQUEST_RESPONSE_TIMEOUT, Duration.ofSeconds(60), LOGGER); - DEFAULT_READ_TIMEOUT = getDefaultTimeoutFromEnvironment(configuration, PROPERTY_AZURE_REQUEST_READ_TIMEOUT, - Duration.ofSeconds(60), LOGGER); - DEFAULT_RESTRICTED_HEADERS = Set.of("connection", "content-length", "expect", "host", "upgrade"); } @@ -248,11 +231,11 @@ public HttpClient build() { // Azure JDK http client supports HTTP 1.1 by default. httpClientBuilder.version(java.net.http.HttpClient.Version.HTTP_1_1); - httpClientBuilder = httpClientBuilder.connectTimeout(getTimeout(connectionTimeout, DEFAULT_CONNECTION_TIMEOUT)); + httpClientBuilder = httpClientBuilder.connectTimeout(getTimeout(connectionTimeout, getDefaultConnectTimeout())); - Duration writeTimeout = getTimeout(this.writeTimeout, DEFAULT_WRITE_TIMEOUT); - Duration responseTimeout = getTimeout(this.responseTimeout, DEFAULT_RESPONSE_TIMEOUT); - Duration readTimeout = getTimeout(this.readTimeout, DEFAULT_READ_TIMEOUT); + Duration writeTimeout = getTimeout(this.writeTimeout, getDefaultWriteTimeout()); + Duration responseTimeout = getTimeout(this.responseTimeout, getDefaultResponseTimeout()); + Duration readTimeout = getTimeout(this.readTimeout, getDefaultReadTimeout()); Configuration buildConfiguration = (configuration == null) ? Configuration.getGlobalConfiguration() : configuration; @@ -331,12 +314,4 @@ protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(this.userName, password.toCharArray()); } } - - private static Duration getTimeout(Duration configuredTimeout, Duration defaultTimeout) { - if (configuredTimeout == null) { - return defaultTimeout; - } - - return configuredTimeout.compareTo(MINIMUM_TIMEOUT) < 0 ? MINIMUM_TIMEOUT : configuredTimeout; - } } diff --git a/sdk/core/azure-core-http-jdk-httpclient/src/main/java/com/azure/core/http/jdk/httpclient/implementation/AzureJdkHttpRequest.java b/sdk/core/azure-core-http-jdk-httpclient/src/main/java/com/azure/core/http/jdk/httpclient/implementation/AzureJdkHttpRequest.java index 6cf58d3b4a36..4e833c2eec52 100644 --- a/sdk/core/azure-core-http-jdk-httpclient/src/main/java/com/azure/core/http/jdk/httpclient/implementation/AzureJdkHttpRequest.java +++ b/sdk/core/azure-core-http-jdk-httpclient/src/main/java/com/azure/core/http/jdk/httpclient/implementation/AzureJdkHttpRequest.java @@ -4,6 +4,7 @@ import com.azure.core.http.HttpMethod; import com.azure.core.implementation.util.HttpHeadersAccessHelper; +import com.azure.core.implementation.util.HttpUtils; import com.azure.core.util.Context; import com.azure.core.util.Contexts; import com.azure.core.util.ProgressReporter; @@ -51,6 +52,9 @@ public AzureJdkHttpRequest(com.azure.core.http.HttpRequest azureCoreRequest, Con Set restrictedHeaders, ClientLogger logger, Duration writeTimeout, Duration responseTimeout) { HttpMethod method = azureCoreRequest.getHttpMethod(); ProgressReporter progressReporter = Contexts.with(context).getHttpRequestProgressReporter(); + responseTimeout = (Duration) context.getData(HttpUtils.AZURE_RESPONSE_TIMEOUT) + .filter(timeoutDuration -> timeoutDuration instanceof Duration) + .orElse(responseTimeout); this.method = method.toString(); this.bodyPublisher = (method == HttpMethod.GET || method == HttpMethod.HEAD) diff --git a/sdk/core/azure-core-http-jdk-httpclient/src/test/java/com/azure/core/http/jdk/httpclient/JdkHttpClientLocalTestServer.java b/sdk/core/azure-core-http-jdk-httpclient/src/test/java/com/azure/core/http/jdk/httpclient/JdkHttpClientLocalTestServer.java index 48ce978de02a..4cac959b2dcf 100644 --- a/sdk/core/azure-core-http-jdk-httpclient/src/test/java/com/azure/core/http/jdk/httpclient/JdkHttpClientLocalTestServer.java +++ b/sdk/core/azure-core-http-jdk-httpclient/src/test/java/com/azure/core/http/jdk/httpclient/JdkHttpClientLocalTestServer.java @@ -22,6 +22,8 @@ public final class JdkHttpClientLocalTestServer { private static volatile LocalTestServer proxyServer; private static final Semaphore PROXY_SERVER_SEMAPHORE = new Semaphore(1); + public static final String TIMEOUT = "/timeout"; + public static final byte[] SHORT_BODY = "hi there".getBytes(StandardCharsets.UTF_8); public static final byte[] LONG_BODY = createLongBody(); @@ -104,6 +106,16 @@ private static LocalTestServer initializeServer() { resp.getHttpOutput().write(SHORT_BODY, 5, 3); resp.getHttpOutput().flush(); resp.getHttpOutput().complete(Callback.NOOP); + } else if (get && TIMEOUT.equals(path)) { + try { + Thread.sleep(5000); + resp.setStatus(200); + resp.getHttpOutput().write(SHORT_BODY); + resp.getHttpOutput().flush(); + resp.getHttpOutput().complete(Callback.NOOP); + } catch (InterruptedException e) { + throw new ServletException(e); + } } else { throw new ServletException("Unexpected request: " + req.getMethod() + " " + path); } diff --git a/sdk/core/azure-core-http-jdk-httpclient/src/test/java/com/azure/core/http/jdk/httpclient/JdkHttpClientTests.java b/sdk/core/azure-core-http-jdk-httpclient/src/test/java/com/azure/core/http/jdk/httpclient/JdkHttpClientTests.java index 35503e58c998..88b0ef8dca21 100644 --- a/sdk/core/azure-core-http-jdk-httpclient/src/test/java/com/azure/core/http/jdk/httpclient/JdkHttpClientTests.java +++ b/sdk/core/azure-core-http-jdk-httpclient/src/test/java/com/azure/core/http/jdk/httpclient/JdkHttpClientTests.java @@ -8,6 +8,7 @@ import com.azure.core.http.HttpMethod; import com.azure.core.http.HttpRequest; import com.azure.core.http.HttpResponse; +import com.azure.core.implementation.util.HttpUtils; import com.azure.core.util.BinaryData; import com.azure.core.util.Context; import com.azure.core.util.Contexts; @@ -55,6 +56,7 @@ import static com.azure.core.http.jdk.httpclient.JdkHttpClientLocalTestServer.LONG_BODY; import static com.azure.core.http.jdk.httpclient.JdkHttpClientLocalTestServer.SHORT_BODY; +import static com.azure.core.http.jdk.httpclient.JdkHttpClientLocalTestServer.TIMEOUT; import static com.azure.core.test.utils.TestUtils.assertArraysEqual; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertInstanceOf; @@ -469,6 +471,46 @@ public void slowEagerReadingTimesOutAsync() { .verify(Duration.ofSeconds(5)); } + @Test + public void perCallTimeout() { + HttpClient client = new JdkHttpClientBuilder().responseTimeout(Duration.ofSeconds(10)).build(); + + HttpRequest request = new HttpRequest(HttpMethod.GET, url(TIMEOUT)); + + // Verify a smaller timeout sent through Context times out the request. + StepVerifier.create(client.send(request, new Context(HttpUtils.AZURE_RESPONSE_TIMEOUT, Duration.ofSeconds(1)))) + .expectErrorMatches(e -> e instanceof HttpTimeoutException) + .verify(); + + // Then verify not setting a timeout through Context does not time out the request. + StepVerifier.create(client.send(request) + .flatMap(response -> Mono.zip(FluxUtil.collectBytesInByteBufferStream(response.getBody()), + Mono.just(response.getStatusCode())))) + .assertNext(tuple -> { + assertArraysEqual(SHORT_BODY, tuple.getT1()); + assertEquals(200, tuple.getT2()); + }) + .verifyComplete(); + } + + @Test + public void perCallTimeoutSync() { + HttpClient client = new JdkHttpClientBuilder().responseTimeout(Duration.ofSeconds(10)).build(); + + HttpRequest request = new HttpRequest(HttpMethod.GET, url(TIMEOUT)); + + // Verify a smaller timeout sent through Context times out the request. + RuntimeException ex = assertThrows(RuntimeException.class, + () -> client.sendSync(request, new Context(HttpUtils.AZURE_RESPONSE_TIMEOUT, Duration.ofSeconds(1)))); + assertInstanceOf(HttpTimeoutException.class, ex.getCause()); + + // Then verify not setting a timeout through Context does not time out the request. + try (HttpResponse response = client.sendSync(request, Context.NONE)) { + assertEquals(200, response.getStatusCode()); + assertArraysEqual(SHORT_BODY, response.getBodyAsBinaryData().toBytes()); + } + } + private static Mono getResponse(String path) { HttpClient client = new JdkHttpClientBuilder().build(); return doRequest(client, path); diff --git a/sdk/core/azure-core-http-netty/src/main/java/com/azure/core/http/netty/NettyAsyncHttpClient.java b/sdk/core/azure-core-http-netty/src/main/java/com/azure/core/http/netty/NettyAsyncHttpClient.java index 944b72081b40..e64b7b69fa1b 100644 --- a/sdk/core/azure-core-http-netty/src/main/java/com/azure/core/http/netty/NettyAsyncHttpClient.java +++ b/sdk/core/azure-core-http-netty/src/main/java/com/azure/core/http/netty/NettyAsyncHttpClient.java @@ -15,6 +15,7 @@ import com.azure.core.implementation.util.BinaryDataHelper; import com.azure.core.implementation.util.ByteArrayContent; import com.azure.core.implementation.util.FileContent; +import com.azure.core.implementation.util.HttpUtils; import com.azure.core.implementation.util.InputStreamContent; import com.azure.core.implementation.util.SerializableContent; import com.azure.core.implementation.util.StringContent; @@ -94,11 +95,6 @@ class NettyAsyncHttpClient implements HttpClient { private static final ClientLogger LOGGER = new ClientLogger(NettyAsyncHttpClient.class); private static final byte[] EMPTY_BYTES = new byte[0]; - private static final String AZURE_EAGERLY_READ_RESPONSE = "azure-eagerly-read-response"; - private static final String AZURE_IGNORE_RESPONSE_BODY = "azure-ignore-response-body"; - private static final String AZURE_RESPONSE_TIMEOUT = "azure-response-timeout"; - private static final String AZURE_EAGERLY_CONVERT_HEADERS = "azure-eagerly-convert-headers"; - final boolean disableBufferCopy; final boolean addProxyHandler; @@ -132,10 +128,11 @@ public Mono send(HttpRequest request, Context context) { Objects.requireNonNull(request.getUrl(), "'request.getUrl()' cannot be null."); Objects.requireNonNull(request.getUrl().getProtocol(), "'request.getUrl().getProtocol()' cannot be null."); - boolean eagerlyReadResponse = (boolean) context.getData(AZURE_EAGERLY_READ_RESPONSE).orElse(false); - boolean ignoreResponseBody = (boolean) context.getData(AZURE_IGNORE_RESPONSE_BODY).orElse(false); - boolean headersEagerlyConverted = (boolean) context.getData(AZURE_EAGERLY_CONVERT_HEADERS).orElse(false); - Long responseTimeout = context.getData(AZURE_RESPONSE_TIMEOUT) + boolean eagerlyReadResponse = (boolean) context.getData(HttpUtils.AZURE_EAGERLY_READ_RESPONSE).orElse(false); + boolean ignoreResponseBody = (boolean) context.getData(HttpUtils.AZURE_IGNORE_RESPONSE_BODY).orElse(false); + boolean headersEagerlyConverted + = (boolean) context.getData(HttpUtils.AZURE_EAGERLY_CONVERT_HEADERS).orElse(false); + Long responseTimeout = context.getData(HttpUtils.AZURE_RESPONSE_TIMEOUT) .filter(timeoutDuration -> timeoutDuration instanceof Duration) .map(timeoutDuration -> ((Duration) timeoutDuration).toMillis()) .orElse(null); diff --git a/sdk/core/azure-core-http-netty/src/main/java/com/azure/core/http/netty/NettyAsyncHttpClientBuilder.java b/sdk/core/azure-core-http-netty/src/main/java/com/azure/core/http/netty/NettyAsyncHttpClientBuilder.java index 75083d268df5..ccdadbe4e2c8 100644 --- a/sdk/core/azure-core-http-netty/src/main/java/com/azure/core/http/netty/NettyAsyncHttpClientBuilder.java +++ b/sdk/core/azure-core-http-netty/src/main/java/com/azure/core/http/netty/NettyAsyncHttpClientBuilder.java @@ -36,15 +36,14 @@ import java.nio.ByteBuffer; import java.time.Duration; import java.util.Objects; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Pattern; -import static com.azure.core.util.Configuration.PROPERTY_AZURE_REQUEST_CONNECT_TIMEOUT; -import static com.azure.core.util.Configuration.PROPERTY_AZURE_REQUEST_READ_TIMEOUT; -import static com.azure.core.util.Configuration.PROPERTY_AZURE_REQUEST_RESPONSE_TIMEOUT; -import static com.azure.core.util.Configuration.PROPERTY_AZURE_REQUEST_WRITE_TIMEOUT; -import static com.azure.core.util.CoreUtils.getDefaultTimeoutFromEnvironment; +import static com.azure.core.implementation.util.HttpUtils.getDefaultConnectTimeout; +import static com.azure.core.implementation.util.HttpUtils.getDefaultReadTimeout; +import static com.azure.core.implementation.util.HttpUtils.getDefaultResponseTimeout; +import static com.azure.core.implementation.util.HttpUtils.getDefaultWriteTimeout; +import static com.azure.core.implementation.util.HttpUtils.getTimeout; /** *

@@ -112,27 +111,10 @@ * @see NettyAsyncHttpClient */ public class NettyAsyncHttpClientBuilder { - private static final long MINIMUM_TIMEOUT = TimeUnit.MILLISECONDS.toMillis(1); - private static final long DEFAULT_CONNECT_TIMEOUT; - private static final long DEFAULT_WRITE_TIMEOUT; - private static final long DEFAULT_RESPONSE_TIMEOUT; - private static final long DEFAULT_READ_TIMEOUT; - // NettyAsyncHttpClientBuilder may be instantiated many times, use a static logger. private static final ClientLogger LOGGER = new ClientLogger(NettyAsyncHttpClientBuilder.class); static { - Configuration configuration = Configuration.getGlobalConfiguration(); - - DEFAULT_CONNECT_TIMEOUT = getDefaultTimeoutFromEnvironment(configuration, - PROPERTY_AZURE_REQUEST_CONNECT_TIMEOUT, Duration.ofSeconds(10), LOGGER).toMillis(); - DEFAULT_WRITE_TIMEOUT = getDefaultTimeoutFromEnvironment(configuration, PROPERTY_AZURE_REQUEST_WRITE_TIMEOUT, - Duration.ofSeconds(60), LOGGER).toMillis(); - DEFAULT_RESPONSE_TIMEOUT = getDefaultTimeoutFromEnvironment(configuration, - PROPERTY_AZURE_REQUEST_RESPONSE_TIMEOUT, Duration.ofSeconds(60), LOGGER).toMillis(); - DEFAULT_READ_TIMEOUT = getDefaultTimeoutFromEnvironment(configuration, PROPERTY_AZURE_REQUEST_READ_TIMEOUT, - Duration.ofSeconds(60), LOGGER).toMillis(); - Utility.validateNettyVersions(); } @@ -205,9 +187,9 @@ public com.azure.core.http.HttpClient build() { addressResolverWasSetByBuilder = true; } - long writeTimeout = getTimeoutMillis(this.writeTimeout, DEFAULT_WRITE_TIMEOUT); - long responseTimeout = getTimeoutMillis(this.responseTimeout, DEFAULT_RESPONSE_TIMEOUT); - long readTimeout = getTimeoutMillis(this.readTimeout, DEFAULT_READ_TIMEOUT); + long writeTimeout = getTimeout(this.writeTimeout, getDefaultWriteTimeout()).toMillis(); + long responseTimeout = getTimeout(this.responseTimeout, getDefaultResponseTimeout()).toMillis(); + long readTimeout = getTimeout(this.readTimeout, getDefaultReadTimeout()).toMillis(); // Get the initial HttpResponseDecoderSpec and update it. // .httpResponseDecoder passes a new HttpResponseDecoderSpec and any existing configuration should be updated @@ -215,7 +197,7 @@ public com.azure.core.http.HttpClient build() { HttpResponseDecoderSpec initialSpec = nettyHttpClient.configuration().decoder(); nettyHttpClient = nettyHttpClient.port(port) .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, - (int) getTimeoutMillis(connectTimeout, DEFAULT_CONNECT_TIMEOUT)) + (int) getTimeout(connectTimeout, getDefaultConnectTimeout()).toMillis()) // TODO (alzimmer): What does validating HTTP response headers get us? .httpResponseDecoder(httpResponseDecoderSpec -> initialSpec.validateHeaders(false)) .doOnRequest( @@ -562,27 +544,6 @@ private static ProxyProvider.Proxy toReactorNettyProxyType(ProxyOptions.Type azu } } - /* - * Returns the timeout in milliseconds to use based on the passed Duration and default timeout. - * - * If the timeout is {@code null} the default timeout will be used. If the timeout is less than or equal to zero - * no timeout will be used. If the timeout is less than one millisecond a timeout of one millisecond will be used. - */ - static long getTimeoutMillis(Duration configuredTimeout, long defaultTimeout) { - // Timeout is null, use the default timeout. - if (configuredTimeout == null) { - return defaultTimeout; - } - - // Timeout is less than or equal to zero, return no timeout. - if (configuredTimeout.isZero() || configuredTimeout.isNegative()) { - return 0; - } - - // Return the maximum of the timeout period and the minimum allowed timeout period. - return Math.max(configuredTimeout.toMillis(), MINIMUM_TIMEOUT); - } - private static boolean shouldApplyProxy(SocketAddress socketAddress, Pattern nonProxyHostsPattern) { if (nonProxyHostsPattern == null) { return true; diff --git a/sdk/core/azure-core-http-netty/src/test/java/com/azure/core/http/netty/NettyAsyncHttpClientBuilderTests.java b/sdk/core/azure-core-http-netty/src/test/java/com/azure/core/http/netty/NettyAsyncHttpClientBuilderTests.java index 85abd25bf71e..44e3e9ed1cb2 100644 --- a/sdk/core/azure-core-http-netty/src/test/java/com/azure/core/http/netty/NettyAsyncHttpClientBuilderTests.java +++ b/sdk/core/azure-core-http-netty/src/test/java/com/azure/core/http/netty/NettyAsyncHttpClientBuilderTests.java @@ -46,6 +46,7 @@ import static com.azure.core.http.netty.implementation.NettyHttpClientLocalTestServer.DEFAULT_PATH; import static com.azure.core.http.netty.implementation.NettyHttpClientLocalTestServer.PREBUILT_CLIENT_PATH; +import static com.azure.core.implementation.util.HttpUtils.getTimeout; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertInstanceOf; @@ -544,7 +545,7 @@ public void buildEventLoopClient() { @ParameterizedTest @MethodSource("getTimeoutMillisSupplier") public void getTimeoutMillis(Duration timeout, long expected) { - assertEquals(expected, NettyAsyncHttpClientBuilder.getTimeoutMillis(timeout, 60000)); + assertEquals(expected, getTimeout(timeout, Duration.ofMillis(60000)).toMillis()); } private static Stream getTimeoutMillisSupplier() { diff --git a/sdk/core/azure-core-http-netty/src/test/java/com/azure/core/http/netty/NettyAsyncHttpClientTests.java b/sdk/core/azure-core-http-netty/src/test/java/com/azure/core/http/netty/NettyAsyncHttpClientTests.java index 59e5a5dcd781..173061698aae 100644 --- a/sdk/core/azure-core-http-netty/src/test/java/com/azure/core/http/netty/NettyAsyncHttpClientTests.java +++ b/sdk/core/azure-core-http-netty/src/test/java/com/azure/core/http/netty/NettyAsyncHttpClientTests.java @@ -18,7 +18,7 @@ import com.azure.core.http.netty.implementation.NettyHttpClientLocalTestServer; import com.azure.core.http.policy.FixedDelay; import com.azure.core.http.policy.RetryPolicy; -import com.azure.core.test.utils.TestUtils; +import com.azure.core.implementation.util.HttpUtils; import com.azure.core.util.BinaryData; import com.azure.core.util.Context; import com.azure.core.util.Contexts; @@ -70,6 +70,7 @@ import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -89,9 +90,12 @@ import static com.azure.core.http.netty.implementation.NettyHttpClientLocalTestServer.SHORT_POST_BODY_PATH; import static com.azure.core.http.netty.implementation.NettyHttpClientLocalTestServer.SHORT_POST_BODY_WITH_VALIDATION_PATH; import static com.azure.core.http.netty.implementation.NettyHttpClientLocalTestServer.TEST_HEADER; +import static com.azure.core.http.netty.implementation.NettyHttpClientLocalTestServer.TIMEOUT; +import static com.azure.core.test.utils.TestUtils.assertArraysEqual; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertLinesMatch; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -237,7 +241,7 @@ public void testConcurrentRequests() { .flatMap(response -> Mono.using(() -> response, HttpResponse::getBodyAsByteArray, HttpResponse::close)); StepVerifier.create(responses).thenConsumeWhile(response -> { - TestUtils.assertArraysEqual(LONG_BODY, response); + assertArraysEqual(LONG_BODY, response); return true; }).expectComplete().verify(Duration.ofSeconds(60)); } @@ -254,7 +258,7 @@ public void testConcurrentRequestsSync() throws InterruptedException { requests.add(() -> { try (HttpResponse response = doRequestSync(client, "/long")) { byte[] body = response.getBodyAsBinaryData().toBytes(); - TestUtils.assertArraysEqual(LONG_BODY, body); + assertArraysEqual(LONG_BODY, body); return null; } }); @@ -591,6 +595,46 @@ public void httpClientWithResolverUsesConfiguredResolverWithProxy() { } } + @Test + public void perCallTimeout() { + HttpClient client = new NettyAsyncHttpClientBuilder().responseTimeout(Duration.ofSeconds(10)).build(); + + HttpRequest request = new HttpRequest(HttpMethod.GET, url(TIMEOUT)); + + // Verify a smaller timeout sent through Context times out the request. + StepVerifier.create(client.send(request, new Context(HttpUtils.AZURE_RESPONSE_TIMEOUT, Duration.ofSeconds(1)))) + .expectErrorMatches(e -> e instanceof TimeoutException) + .verify(); + + // Then verify not setting a timeout through Context does not time out the request. + StepVerifier.create(client.send(request) + .flatMap(response -> Mono.zip(FluxUtil.collectBytesInByteBufferStream(response.getBody()), + Mono.just(response.getStatusCode())))) + .assertNext(tuple -> { + assertArraysEqual(SHORT_BODY, tuple.getT1()); + assertEquals(200, tuple.getT2()); + }) + .verifyComplete(); + } + + @Test + public void perCallTimeoutSync() { + HttpClient client = new NettyAsyncHttpClientBuilder().responseTimeout(Duration.ofSeconds(10)).build(); + + HttpRequest request = new HttpRequest(HttpMethod.GET, url(TIMEOUT)); + + // Verify a smaller timeout sent through Context times out the request. + RuntimeException ex = assertThrows(RuntimeException.class, + () -> client.sendSync(request, new Context(HttpUtils.AZURE_RESPONSE_TIMEOUT, Duration.ofSeconds(1)))); + assertInstanceOf(TimeoutException.class, ex.getCause()); + + // Then verify not setting a timeout through Context does not time out the request. + try (HttpResponse response = client.sendSync(request, Context.NONE)) { + assertArraysEqual(SHORT_BODY, response.getBodyAsBinaryData().toBytes()); + assertEquals(200, response.getStatusCode()); + } + } + private static Stream requestHeaderSupplier() { return Stream.of(Arguments.of(null, NULL_REPLACEMENT), Arguments.of("", ""), Arguments.of("aValue", "aValue")); } diff --git a/sdk/core/azure-core-http-netty/src/test/java/com/azure/core/http/netty/implementation/NettyHttpClientLocalTestServer.java b/sdk/core/azure-core-http-netty/src/test/java/com/azure/core/http/netty/implementation/NettyHttpClientLocalTestServer.java index 0f8c8c52ba0b..35df2c17338b 100644 --- a/sdk/core/azure-core-http-netty/src/test/java/com/azure/core/http/netty/implementation/NettyHttpClientLocalTestServer.java +++ b/sdk/core/azure-core-http-netty/src/test/java/com/azure/core/http/netty/implementation/NettyHttpClientLocalTestServer.java @@ -36,6 +36,7 @@ public final class NettyHttpClientLocalTestServer { public static final String EXPECTED_HEADER = "userAgent"; public static final String RETURN_HEADERS_AS_IS_PATH = "/returnHeadersAsIs"; public static final String PROXY_TO_ADDRESS = "/proxyToAddress"; + public static final String TIMEOUT = "/timeout"; public static final byte[] SHORT_BODY = "hi there".getBytes(StandardCharsets.UTF_8); public static final byte[] LONG_BODY = createLongBody(); @@ -134,6 +135,16 @@ private static LocalTestServer initializeServer() { resp.getHttpOutput().write("I'm a teapot".getBytes(StandardCharsets.UTF_8)); resp.getHttpOutput().flush(); resp.getHttpOutput().complete(Callback.NOOP); + } else if (get && TIMEOUT.equals(path)) { + try { + Thread.sleep(5000); + resp.setStatus(200); + resp.getHttpOutput().write(SHORT_BODY); + resp.getHttpOutput().flush(); + resp.getHttpOutput().complete(Callback.NOOP); + } catch (InterruptedException e) { + throw new ServletException(e); + } } else { throw new ServletException("Unexpected request: " + req.getMethod() + " " + path); } diff --git a/sdk/core/azure-core-http-okhttp/src/main/java/com/azure/core/http/okhttp/OkHttpAsyncHttpClient.java b/sdk/core/azure-core-http-okhttp/src/main/java/com/azure/core/http/okhttp/OkHttpAsyncHttpClient.java index 0474465ff1ed..ed142df50ca4 100644 --- a/sdk/core/azure-core-http-okhttp/src/main/java/com/azure/core/http/okhttp/OkHttpAsyncHttpClient.java +++ b/sdk/core/azure-core-http-okhttp/src/main/java/com/azure/core/http/okhttp/OkHttpAsyncHttpClient.java @@ -10,20 +10,25 @@ import com.azure.core.http.HttpMethod; import com.azure.core.http.HttpRequest; import com.azure.core.http.HttpResponse; +import com.azure.core.http.ProxyOptions; import com.azure.core.http.okhttp.implementation.BinaryDataRequestBody; import com.azure.core.http.okhttp.implementation.OkHttpAsyncBufferedResponse; import com.azure.core.http.okhttp.implementation.OkHttpAsyncResponse; import com.azure.core.http.okhttp.implementation.OkHttpFluxRequestBody; import com.azure.core.http.okhttp.implementation.OkHttpProgressReportingRequestBody; +import com.azure.core.http.okhttp.implementation.PerCallTimeoutCall; +import com.azure.core.http.okhttp.implementation.ResponseTimeoutListenerFactory; import com.azure.core.implementation.util.BinaryDataContent; import com.azure.core.implementation.util.BinaryDataHelper; import com.azure.core.implementation.util.FluxByteBufferContent; +import com.azure.core.implementation.util.HttpUtils; import com.azure.core.util.BinaryData; import com.azure.core.util.Context; import com.azure.core.util.Contexts; import com.azure.core.util.ProgressReporter; import com.azure.core.util.logging.ClientLogger; import okhttp3.Call; +import okhttp3.EventListener; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; @@ -34,7 +39,9 @@ import reactor.core.publisher.MonoSink; import java.io.IOException; +import java.io.InterruptedIOException; import java.io.UncheckedIOException; +import java.time.Duration; /** * This class provides a OkHttp-based implementation for the {@link HttpClient} interface. Creating an instance of this @@ -70,14 +77,15 @@ class OkHttpAsyncHttpClient implements HttpClient { private static final byte[] EMPTY_BODY = new byte[0]; private static final RequestBody EMPTY_REQUEST_BODY = RequestBody.create(EMPTY_BODY); - private static final String AZURE_EAGERLY_READ_RESPONSE = "azure-eagerly-read-response"; - private static final String AZURE_IGNORE_RESPONSE_BODY = "azure-ignore-response-body"; - private static final String AZURE_EAGERLY_CONVERT_HEADERS = "azure-eagerly-convert-headers"; - final OkHttpClient httpClient; - OkHttpAsyncHttpClient(OkHttpClient httpClient) { - this.httpClient = httpClient; + private final Duration responseTimeout; + + OkHttpAsyncHttpClient(OkHttpClient httpClient, Duration responseTimeout) { + EventListener.Factory factory = httpClient.eventListenerFactory(); + this.httpClient + = httpClient.newBuilder().eventListenerFactory(new ResponseTimeoutListenerFactory(factory)).build(); + this.responseTimeout = responseTimeout; } @Override @@ -87,9 +95,13 @@ public Mono send(HttpRequest request) { @Override public Mono send(HttpRequest request, Context context) { - boolean eagerlyReadResponse = (boolean) context.getData(AZURE_EAGERLY_READ_RESPONSE).orElse(false); - boolean ignoreResponseBody = (boolean) context.getData(AZURE_IGNORE_RESPONSE_BODY).orElse(false); - boolean eagerlyConvertHeaders = (boolean) context.getData(AZURE_EAGERLY_CONVERT_HEADERS).orElse(false); + boolean eagerlyReadResponse = (boolean) context.getData(HttpUtils.AZURE_EAGERLY_READ_RESPONSE).orElse(false); + boolean ignoreResponseBody = (boolean) context.getData(HttpUtils.AZURE_IGNORE_RESPONSE_BODY).orElse(false); + boolean eagerlyConvertHeaders + = (boolean) context.getData(HttpUtils.AZURE_EAGERLY_CONVERT_HEADERS).orElse(false); + Duration perCallTimeout = (Duration) context.getData(HttpUtils.AZURE_RESPONSE_TIMEOUT) + .filter(timeoutDuration -> timeoutDuration instanceof Duration) + .orElse(responseTimeout); ProgressReporter progressReporter = Contexts.with(context).getHttpRequestProgressReporter(); @@ -106,47 +118,84 @@ public Mono send(HttpRequest request, Context context) { // 3. If Flux asynchronous then subscribe does not block caller thread // but block on the thread backing flux. This ignore any subscribeOn applied to send(r) // - Mono.fromCallable(() -> toOkHttpRequest(request, progressReporter)).subscribe(okHttpRequest -> { - try { - Call call = httpClient.newCall(okHttpRequest); - call.enqueue(new OkHttpCallback(sink, request, eagerlyReadResponse, ignoreResponseBody, - eagerlyConvertHeaders)); - sink.onCancel(call::cancel); - } catch (Exception ex) { - sink.error(ex); - } - }, sink::error); + Mono.fromCallable(() -> toOkHttpRequest(request, progressReporter, perCallTimeout)) + .subscribe(okHttpRequest -> { + try { + Call call = httpClient.newCall(okHttpRequest); + call.enqueue(new OkHttpCallback(sink, request, eagerlyReadResponse, ignoreResponseBody, + eagerlyConvertHeaders)); + sink.onCancel(call::cancel); + } catch (Exception ex) { + sink.error(ex); + } + }, sink::error); })); } @Override public HttpResponse sendSync(HttpRequest request, Context context) { - boolean eagerlyReadResponse = (boolean) context.getData(AZURE_EAGERLY_READ_RESPONSE).orElse(false); - boolean ignoreResponseBody = (boolean) context.getData(AZURE_IGNORE_RESPONSE_BODY).orElse(false); - boolean eagerlyConvertHeaders = (boolean) context.getData(AZURE_EAGERLY_CONVERT_HEADERS).orElse(false); + boolean eagerlyReadResponse = (boolean) context.getData(HttpUtils.AZURE_EAGERLY_READ_RESPONSE).orElse(false); + boolean ignoreResponseBody = (boolean) context.getData(HttpUtils.AZURE_IGNORE_RESPONSE_BODY).orElse(false); + boolean eagerlyConvertHeaders + = (boolean) context.getData(HttpUtils.AZURE_EAGERLY_CONVERT_HEADERS).orElse(false); + Duration perCallTimeout = (Duration) context.getData(HttpUtils.AZURE_RESPONSE_TIMEOUT) + .filter(timeoutDuration -> timeoutDuration instanceof Duration) + .orElse(responseTimeout); ProgressReporter progressReporter = Contexts.with(context).getHttpRequestProgressReporter(); - Request okHttpRequest = toOkHttpRequest(request, progressReporter); + Request okHttpRequest = toOkHttpRequest(request, progressReporter, perCallTimeout); + Call call = null; try { - Response okHttpResponse = httpClient.newCall(okHttpRequest).execute(); + call = httpClient.newCall(okHttpRequest); + Response okHttpResponse = call.execute(); return toHttpResponse(request, okHttpResponse, eagerlyReadResponse, ignoreResponseBody, eagerlyConvertHeaders); } catch (IOException e) { - throw LOGGER.logExceptionAsError(new UncheckedIOException(e)); + throw LOGGER.logExceptionAsError(new UncheckedIOException(mapIOException(e, call))); } } + /** + * Current design for response timeout uses call cancellation which throws an IOException with message "canceled". + * This isn't what we want, we want an InterruptedIOException with message "timeout". Use information stored on the + * call to determine if the IOException should be mapped to an InterruptedIOException. + * + * @param e the IOException to map + * @param call the Call to associate with the new IOException + * @return the new IOException + */ + private static IOException mapIOException(IOException e, Call call) { + if (call == null) { + return e; + } + + PerCallTimeoutCall perCallTimeoutCall = call.request().tag(PerCallTimeoutCall.class); + if (perCallTimeoutCall != null && perCallTimeoutCall.isTimedOut()) { + InterruptedIOException i = new InterruptedIOException("timedout"); + i.addSuppressed(e); + return i; + } + + return e; + } + /** * Converts the given azure-core request to okhttp request. * * @param request the azure-core request * @param progressReporter the {@link ProgressReporter}. Can be null. + * @param perCallTimeout the per call timeout * @return the okhttp request */ - private okhttp3.Request toOkHttpRequest(HttpRequest request, ProgressReporter progressReporter) { + private okhttp3.Request toOkHttpRequest(HttpRequest request, ProgressReporter progressReporter, + Duration perCallTimeout) { Request.Builder requestBuilder = new Request.Builder().url(request.getUrl()); + if (perCallTimeout != null) { + requestBuilder.tag(PerCallTimeoutCall.class, new PerCallTimeoutCall(perCallTimeout.toMillis())); + } + if (request.getHeaders() != null) { for (HttpHeader hdr : request.getHeaders()) { // OkHttp allows for headers with multiple values, but it treats them as separate headers, @@ -263,9 +312,14 @@ public void onFailure(okhttp3.Call call, IOException e) { if (e.getSuppressed().length == 1) { // Propagate suppressed exception when there is one. // This happens when body emission fails in the middle. - sink.error(e.getSuppressed()[0]); + Throwable suppressed = e.getSuppressed()[0]; + if (suppressed instanceof IOException) { + sink.error(mapIOException((IOException) suppressed, call)); + } else { + sink.error(suppressed); + } } else { - sink.error(e); + sink.error(mapIOException(e, call)); } } diff --git a/sdk/core/azure-core-http-okhttp/src/main/java/com/azure/core/http/okhttp/OkHttpAsyncHttpClientBuilder.java b/sdk/core/azure-core-http-okhttp/src/main/java/com/azure/core/http/okhttp/OkHttpAsyncHttpClientBuilder.java index f34406773f5c..ada7f41fd95b 100644 --- a/sdk/core/azure-core-http-okhttp/src/main/java/com/azure/core/http/okhttp/OkHttpAsyncHttpClientBuilder.java +++ b/sdk/core/azure-core-http-okhttp/src/main/java/com/azure/core/http/okhttp/OkHttpAsyncHttpClientBuilder.java @@ -4,10 +4,12 @@ package com.azure.core.http.okhttp; import com.azure.core.http.HttpClient; +import com.azure.core.http.HttpRequest; import com.azure.core.http.ProxyOptions; import com.azure.core.http.okhttp.implementation.OkHttpProxySelector; import com.azure.core.http.okhttp.implementation.ProxyAuthenticator; import com.azure.core.util.Configuration; +import com.azure.core.util.Context; import com.azure.core.util.logging.ClientLogger; import okhttp3.ConnectionPool; import okhttp3.Dispatcher; @@ -19,16 +21,17 @@ import java.util.List; import java.util.Objects; -import static com.azure.core.util.Configuration.PROPERTY_AZURE_REQUEST_CONNECT_TIMEOUT; -import static com.azure.core.util.Configuration.PROPERTY_AZURE_REQUEST_READ_TIMEOUT; -import static com.azure.core.util.Configuration.PROPERTY_AZURE_REQUEST_WRITE_TIMEOUT; -import static com.azure.core.util.CoreUtils.getDefaultTimeoutFromEnvironment; +import static com.azure.core.implementation.util.HttpUtils.getDefaultConnectTimeout; +import static com.azure.core.implementation.util.HttpUtils.getDefaultReadTimeout; +import static com.azure.core.implementation.util.HttpUtils.getDefaultResponseTimeout; +import static com.azure.core.implementation.util.HttpUtils.getDefaultWriteTimeout; +import static com.azure.core.implementation.util.HttpUtils.getTimeout; /** * Builder class responsible for creating instances of {@link com.azure.core.http.HttpClient} backed by OkHttp. - * The client built from this builder can support sending requests synchronously and asynchronously. - * Use {@link com.azure.core.http.HttpClient#sendSync(HttpRequest, Context)} to send the provided request - * synchronously with contextual information. + * The client built from this builder can support sending requests synchronously and asynchronously. Use + * {@link HttpClient#sendSync(HttpRequest, Context)} to send the provided request synchronously with contextual + * information. * *

* Building a new HttpClient instance @@ -114,24 +117,9 @@ public class OkHttpAsyncHttpClientBuilder { private final okhttp3.OkHttpClient okHttpClient; - private static final Duration MINIMUM_TIMEOUT = Duration.ofMillis(1); - private static final Duration DEFAULT_CONNECT_TIMEOUT; - private static final Duration DEFAULT_WRITE_TIMEOUT; - private static final Duration DEFAULT_READ_TIMEOUT; - - static { - ClientLogger logger = new ClientLogger(OkHttpAsyncHttpClientBuilder.class); - Configuration configuration = Configuration.getGlobalConfiguration(); - DEFAULT_CONNECT_TIMEOUT = getDefaultTimeoutFromEnvironment(configuration, - PROPERTY_AZURE_REQUEST_CONNECT_TIMEOUT, Duration.ofSeconds(10), logger); - DEFAULT_WRITE_TIMEOUT = getDefaultTimeoutFromEnvironment(configuration, PROPERTY_AZURE_REQUEST_WRITE_TIMEOUT, - Duration.ofSeconds(60), logger); - DEFAULT_READ_TIMEOUT = getDefaultTimeoutFromEnvironment(configuration, PROPERTY_AZURE_REQUEST_READ_TIMEOUT, - Duration.ofSeconds(60), logger); - } - private List networkInterceptors = new ArrayList<>(); private Duration readTimeout; + private Duration responseTimeout; private Duration writeTimeout; private Duration connectionTimeout; private Duration callTimeout; @@ -199,11 +187,31 @@ public OkHttpAsyncHttpClientBuilder networkInterceptors(List networ * @see OkHttpClient.Builder#readTimeout(Duration) */ public OkHttpAsyncHttpClientBuilder readTimeout(Duration readTimeout) { - // setReadTimeout can be null this.readTimeout = readTimeout; return this; } + /** + * Sets the response timeout duration used when waiting for a server to reply. + *

+ * The response timeout begins once the request write completes and finishes once the first response read is + * triggered when the server response is received. + *

+ * If {@code responseTimeout} is null either {@link Configuration#PROPERTY_AZURE_REQUEST_RESPONSE_TIMEOUT} or a + * 60-second timeout will be used, if it is a {@link Duration} less than or equal to zero then no timeout will be + * applied to the response. When applying the timeout the greatest of one millisecond and the value of {@code + * responseTimeout} will be used. + *

+ * Given OkHttp doesn't have an equivalent timeout for just responses, this is handled manually. + * + * @param responseTimeout Response timeout duration. + * @return The updated OkHttpAsyncHttpClientBuilder object. + */ + public OkHttpAsyncHttpClientBuilder responseTimeout(Duration responseTimeout) { + this.responseTimeout = responseTimeout; + return this; + } + /** * Sets the writing timeout for a request to be sent. *

@@ -355,9 +363,9 @@ public HttpClient build() { } // Configure operation timeouts. - httpClientBuilder = httpClientBuilder.connectTimeout(getTimeout(connectionTimeout, DEFAULT_CONNECT_TIMEOUT)) - .writeTimeout(getTimeout(writeTimeout, DEFAULT_WRITE_TIMEOUT)) - .readTimeout(getTimeout(readTimeout, DEFAULT_READ_TIMEOUT)); + httpClientBuilder = httpClientBuilder.connectTimeout(getTimeout(connectionTimeout, getDefaultConnectTimeout())) + .writeTimeout(getTimeout(writeTimeout, getDefaultWriteTimeout())) + .readTimeout(getTimeout(readTimeout, getDefaultReadTimeout())); if (callTimeout != null) { // Call timeout is disabled by default. @@ -397,31 +405,7 @@ public HttpClient build() { // Set the followRedirects property. httpClientBuilder.followRedirects(this.followRedirects); - return new OkHttpAsyncHttpClient(httpClientBuilder.build()); - } - - /* - * Returns the timeout in milliseconds to use based on the passed Duration and default timeout. - * - * If the timeout is {@code null} the default timeout will be used. If the timeout is less than or equal to zero - * no timeout will be used. If the timeout is less than one millisecond a timeout of one millisecond will be used. - */ - static Duration getTimeout(Duration configuredTimeout, Duration defaultTimeout) { - // Timeout is null, use the default timeout. - if (configuredTimeout == null) { - return defaultTimeout; - } - - // Timeout is less than or equal to zero, return no timeout. - if (configuredTimeout.isZero() || configuredTimeout.isNegative()) { - return Duration.ZERO; - } - - // Return the maximum of the timeout period and the minimum allowed timeout period. - if (configuredTimeout.compareTo(MINIMUM_TIMEOUT) < 0) { - return MINIMUM_TIMEOUT; - } else { - return configuredTimeout; - } + return new OkHttpAsyncHttpClient(httpClientBuilder.build(), + getTimeout(responseTimeout, getDefaultResponseTimeout())); } } diff --git a/sdk/core/azure-core-http-okhttp/src/main/java/com/azure/core/http/okhttp/implementation/PerCallTimeoutCall.java b/sdk/core/azure-core-http-okhttp/src/main/java/com/azure/core/http/okhttp/implementation/PerCallTimeoutCall.java new file mode 100644 index 000000000000..c37173dc47cf --- /dev/null +++ b/sdk/core/azure-core-http-okhttp/src/main/java/com/azure/core/http/okhttp/implementation/PerCallTimeoutCall.java @@ -0,0 +1,92 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.core.http.okhttp.implementation; + +import okhttp3.Call; + +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; + +/** + * Implementation of {@link Call} which applies a per-call response timeout to the call. + */ +public final class PerCallTimeoutCall { + // Singleton timer to schedule timeout tasks. + // TODO (alzimmer): Make sure one thread is sufficient for all timeout tasks. + private static final Timer TIMER = new Timer("azure-okhttp-response-timeout-tracker", true); + + private final long perCallTimeout; + + private volatile boolean timedOut; + + private static final AtomicReferenceFieldUpdater CURRENT_TIMEOUT_UPDATER + = AtomicReferenceFieldUpdater.newUpdater(PerCallTimeoutCall.class, TimerTask.class, "currentTimeout"); + private volatile TimerTask currentTimeout; + + /** + * Creates a new instance of PerCallTimeoutCall. + * + * @param perCallTimeout The per-call timeout to apply to the call. + */ + public PerCallTimeoutCall(long perCallTimeout) { + this.perCallTimeout = perCallTimeout; + } + + /** + * Starts the timer task to time out the call if it exceeds the per-call timeout. + *

+ * No timeout is applied if the per-call timeout is less than or equal to 0. + * + * @param call The call to apply the timeout to. + */ + public void beginPerCallTimeout(Call call) { + if (perCallTimeout > 0) { + TimerTask currentTimeout = new PerCallTimerTask(this, call); + + TIMER.schedule(currentTimeout, perCallTimeout); + TimerTask existing = CURRENT_TIMEOUT_UPDATER.getAndSet(this, currentTimeout); + if (existing != null) { + existing.cancel(); + } + } + } + + /** + * Cancels the per-call timeout task. + *

+ * Cancellations happen if the response returned before the timeout or if the call was cancelled externally. + */ + public void endPerCallTimeout() { + TimerTask currentTimeout = CURRENT_TIMEOUT_UPDATER.getAndSet(this, null); + if (currentTimeout != null) { + currentTimeout.cancel(); + } + } + + /** + * Returns whether the call timed out. + * + * @return Whether the call timed out. + */ + public boolean isTimedOut() { + return timedOut; + } + + private static final class PerCallTimerTask extends TimerTask { + private final PerCallTimeoutCall perCallTimeoutCall; + private final Call call; + + PerCallTimerTask(PerCallTimeoutCall perCallTimeoutCall, Call call) { + this.perCallTimeoutCall = perCallTimeoutCall; + this.call = call; + } + + @Override + public void run() { + // Set timeout first. + perCallTimeoutCall.timedOut = true; + call.cancel(); + } + } +} diff --git a/sdk/core/azure-core-http-okhttp/src/main/java/com/azure/core/http/okhttp/implementation/ResponseTimeoutListener.java b/sdk/core/azure-core-http-okhttp/src/main/java/com/azure/core/http/okhttp/implementation/ResponseTimeoutListener.java new file mode 100644 index 000000000000..fde446e419b7 --- /dev/null +++ b/sdk/core/azure-core-http-okhttp/src/main/java/com/azure/core/http/okhttp/implementation/ResponseTimeoutListener.java @@ -0,0 +1,220 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.core.http.okhttp.implementation; + +import okhttp3.Call; +import okhttp3.Connection; +import okhttp3.EventListener; +import okhttp3.Handshake; +import okhttp3.HttpUrl; +import okhttp3.Protocol; +import okhttp3.Request; +import okhttp3.Response; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.util.List; + +/** + * Implementation of {@link EventListener} that watches {@link #requestHeadersEnd(Call, Request)} and + * {@link #requestBodyEnd(Call, long)} to detect when a request has completed being sent and + * {@link #responseHeadersStart(Call)} and {@link #responseFailed(Call, IOException)} to detect when a response has + * started being received. This is used to determine a response timeout for the call. + *

+ * Both completing the request headers and the response body need to be watched as requests without a body will never + * trigger the request body events. + */ +public class ResponseTimeoutListener extends EventListener { + private final EventListener delegate; + + /** + * Creates a new instance of ResponseTimeoutListener. + * + * @param delegate The {@link EventListener} to delegate to. + */ + public ResponseTimeoutListener(EventListener delegate) { + this.delegate = delegate; + } + + @Override + public void requestHeadersEnd(Call call, Request request) { + PerCallTimeoutCall perCallTimeoutCall = request.tag(PerCallTimeoutCall.class); + if (perCallTimeoutCall != null) { + if (request.body() == null) { + // Start the per call timeout when the request headers have been sent if there isn't a body. + perCallTimeoutCall.beginPerCallTimeout(call); + } + } + + delegate.requestHeadersEnd(call, request); + } + + @Override + public void requestFailed(Call call, IOException ioe) { + PerCallTimeoutCall perCallTimeoutCall = call.request().tag(PerCallTimeoutCall.class); + if (perCallTimeoutCall != null) { + // End the per call timeout if the request fails. + perCallTimeoutCall.endPerCallTimeout(); + } + + delegate.requestFailed(call, ioe); + } + + @Override + public void requestBodyEnd(Call call, long byteCount) { + PerCallTimeoutCall perCallTimeoutCall = call.request().tag(PerCallTimeoutCall.class); + if (perCallTimeoutCall != null) { + // Start the per call timeout when the request body has been sent. + perCallTimeoutCall.beginPerCallTimeout(call); + } + delegate.requestBodyEnd(call, byteCount); + } + + @Override + public void responseHeadersStart(Call call) { + PerCallTimeoutCall perCallTimeoutCall = call.request().tag(PerCallTimeoutCall.class); + if (perCallTimeoutCall != null) { + // End the per call timeout when the response headers have started being received. + perCallTimeoutCall.endPerCallTimeout(); + } + delegate.responseHeadersStart(call); + } + + @Override + public void responseFailed(Call call, IOException ioe) { + PerCallTimeoutCall perCallTimeoutCall = call.request().tag(PerCallTimeoutCall.class); + if (perCallTimeoutCall != null) { + // End the per call timeout if the response fails. + perCallTimeoutCall.endPerCallTimeout(); + } + delegate.responseFailed(call, ioe); + } + + @Override + public void canceled(Call call) { + PerCallTimeoutCall perCallTimeoutCall = call.request().tag(PerCallTimeoutCall.class); + if (perCallTimeoutCall != null) { + // End the per call timeout if the call is cancelled. + perCallTimeoutCall.endPerCallTimeout(); + } + delegate.canceled(call); + } + + @Override + public void cacheConditionalHit(Call call, Response cachedResponse) { + delegate.cacheConditionalHit(call, cachedResponse); + } + + @Override + public void cacheHit(Call call, Response response) { + delegate.cacheHit(call, response); + } + + @Override + public void cacheMiss(Call call) { + delegate.cacheMiss(call); + } + + @Override + public void callEnd(Call call) { + delegate.callEnd(call); + } + + @Override + public void callFailed(Call call, IOException ioe) { + delegate.callFailed(call, ioe); + } + + @Override + public void callStart(Call call) { + delegate.callStart(call); + } + + @Override + public void connectEnd(Call call, InetSocketAddress inetSocketAddress, Proxy proxy, Protocol protocol) { + delegate.connectEnd(call, inetSocketAddress, proxy, protocol); + } + + @Override + public void connectFailed(Call call, InetSocketAddress inetSocketAddress, Proxy proxy, Protocol protocol, + IOException ioe) { + delegate.connectFailed(call, inetSocketAddress, proxy, protocol, ioe); + } + + @Override + public void connectStart(Call call, InetSocketAddress inetSocketAddress, Proxy proxy) { + delegate.connectStart(call, inetSocketAddress, proxy); + } + + @Override + public void connectionAcquired(Call call, Connection connection) { + delegate.connectionAcquired(call, connection); + } + + @Override + public void connectionReleased(Call call, Connection connection) { + delegate.connectionReleased(call, connection); + } + + @Override + public void dnsEnd(Call call, String domainName, List inetAddressList) { + delegate.dnsEnd(call, domainName, inetAddressList); + } + + @Override + public void dnsStart(Call call, String domainName) { + delegate.dnsStart(call, domainName); + } + + @Override + public void proxySelectEnd(Call call, HttpUrl url, List proxies) { + delegate.proxySelectEnd(call, url, proxies); + } + + @Override + public void proxySelectStart(Call call, HttpUrl url) { + delegate.proxySelectStart(call, url); + } + + @Override + public void requestHeadersStart(Call call) { + delegate.requestHeadersStart(call); + } + + @Override + public void requestBodyStart(Call call) { + delegate.requestBodyStart(call); + } + + @Override + public void responseBodyEnd(Call call, long byteCount) { + delegate.responseBodyEnd(call, byteCount); + } + + @Override + public void responseBodyStart(Call call) { + delegate.responseBodyStart(call); + } + + @Override + public void responseHeadersEnd(Call call, Response response) { + delegate.responseHeadersEnd(call, response); + } + + @Override + public void satisfactionFailure(Call call, Response response) { + delegate.satisfactionFailure(call, response); + } + + @Override + public void secureConnectEnd(Call call, Handshake handshake) { + delegate.secureConnectEnd(call, handshake); + } + + @Override + public void secureConnectStart(Call call) { + delegate.secureConnectStart(call); + } +} diff --git a/sdk/core/azure-core-http-okhttp/src/main/java/com/azure/core/http/okhttp/implementation/ResponseTimeoutListenerFactory.java b/sdk/core/azure-core-http-okhttp/src/main/java/com/azure/core/http/okhttp/implementation/ResponseTimeoutListenerFactory.java new file mode 100644 index 000000000000..c6b57b19933e --- /dev/null +++ b/sdk/core/azure-core-http-okhttp/src/main/java/com/azure/core/http/okhttp/implementation/ResponseTimeoutListenerFactory.java @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.core.http.okhttp.implementation; + +import okhttp3.Call; +import okhttp3.EventListener; + +/** + * Implementation of {@link EventListener.Factory} that creates {@link ResponseTimeoutListener} instances. + */ +public final class ResponseTimeoutListenerFactory implements EventListener.Factory { + private final EventListener.Factory delegate; + + /** + * Creates a new instance of ResponseTimeoutListenerFactory. + * @param delegate The delegate factory to create the listener. + */ + public ResponseTimeoutListenerFactory(EventListener.Factory delegate) { + this.delegate = delegate; + } + + @Override + public EventListener create(Call call) { + return new ResponseTimeoutListener(delegate.create(call)); + } +} diff --git a/sdk/core/azure-core-http-okhttp/src/test/java/com/azure/core/http/okhttp/OkHttpAsyncHttpClientTests.java b/sdk/core/azure-core-http-okhttp/src/test/java/com/azure/core/http/okhttp/OkHttpAsyncHttpClientTests.java index 1c0783c436d6..3ff9611c8a28 100644 --- a/sdk/core/azure-core-http-okhttp/src/test/java/com/azure/core/http/okhttp/OkHttpAsyncHttpClientTests.java +++ b/sdk/core/azure-core-http-okhttp/src/test/java/com/azure/core/http/okhttp/OkHttpAsyncHttpClientTests.java @@ -10,7 +10,9 @@ import com.azure.core.http.HttpMethod; import com.azure.core.http.HttpRequest; import com.azure.core.http.HttpResponse; +import com.azure.core.implementation.util.HttpUtils; import com.azure.core.util.Context; +import com.azure.core.util.FluxUtil; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.parallel.Execution; @@ -23,6 +25,8 @@ import reactor.test.StepVerifierOptions; import java.io.IOException; +import java.io.InterruptedIOException; +import java.io.UncheckedIOException; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; @@ -40,10 +44,14 @@ import static com.azure.core.http.okhttp.OkHttpClientLocalTestServer.LONG_BODY; import static com.azure.core.http.okhttp.OkHttpClientLocalTestServer.RETURN_HEADERS_AS_IS_PATH; import static com.azure.core.http.okhttp.OkHttpClientLocalTestServer.SHORT_BODY; +import static com.azure.core.http.okhttp.OkHttpClientLocalTestServer.TIMEOUT; import static com.azure.core.http.okhttp.TestUtils.createQuietDispatcher; +import static com.azure.core.test.utils.TestUtils.assertArraysEqual; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertLinesMatch; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @Execution(ExecutionMode.SAME_THREAD) @@ -224,6 +232,46 @@ public void validateHeadersReturnAsIs() { .verify(Duration.ofSeconds(10)); } + @Test + public void perCallTimeout() { + HttpClient client = new OkHttpAsyncHttpClientBuilder().responseTimeout(Duration.ofSeconds(20)).build(); + + HttpRequest request = new HttpRequest(HttpMethod.GET, url(TIMEOUT)); + + // Verify a smaller timeout sent through Context times out the request. + StepVerifier.create(client.send(request, new Context(HttpUtils.AZURE_RESPONSE_TIMEOUT, Duration.ofSeconds(1)))) + .expectErrorMatches(e -> e instanceof InterruptedIOException) + .verify(); + + // Then verify not setting a timeout through Context does not time out the request. + StepVerifier.create(client.send(request) + .flatMap(response -> Mono.zip(FluxUtil.collectBytesInByteBufferStream(response.getBody()), + Mono.just(response.getStatusCode())))) + .assertNext(tuple -> { + assertArraysEqual(SHORT_BODY, tuple.getT1()); + assertEquals(200, tuple.getT2()); + }) + .verifyComplete(); + } + + @Test + public void perCallTimeoutSync() { + HttpClient client = new OkHttpAsyncHttpClientBuilder().responseTimeout(Duration.ofSeconds(20)).build(); + + HttpRequest request = new HttpRequest(HttpMethod.GET, url(TIMEOUT)); + + // Verify a smaller timeout sent through Context times out the request. + UncheckedIOException ex = assertThrows(UncheckedIOException.class, + () -> client.sendSync(request, new Context(HttpUtils.AZURE_RESPONSE_TIMEOUT, Duration.ofSeconds(1)))); + assertInstanceOf(InterruptedIOException.class, ex.getCause()); + + // Then verify not setting a timeout through Context does not time out the request. + try (HttpResponse response = client.sendSync(request, Context.NONE)) { + assertEquals(200, response.getStatusCode()); + assertArraysEqual(SHORT_BODY, response.getBodyAsBinaryData().toBytes()); + } + } + private static Mono getResponse(String path) { HttpClient client = new OkHttpAsyncHttpClientBuilder().build(); return getResponse(client, path); diff --git a/sdk/core/azure-core-http-okhttp/src/test/java/com/azure/core/http/okhttp/OkHttpClientLocalTestServer.java b/sdk/core/azure-core-http-okhttp/src/test/java/com/azure/core/http/okhttp/OkHttpClientLocalTestServer.java index ad5a00e7ab52..cd1ec54f932a 100644 --- a/sdk/core/azure-core-http-okhttp/src/test/java/com/azure/core/http/okhttp/OkHttpClientLocalTestServer.java +++ b/sdk/core/azure-core-http-okhttp/src/test/java/com/azure/core/http/okhttp/OkHttpClientLocalTestServer.java @@ -28,6 +28,7 @@ public final class OkHttpClientLocalTestServer { public static final String DISPATCHER_PATH = "/dispatcher"; public static final String REDIRECT_PATH = "/redirect"; public static final String LOCATION_PATH = "/location"; + public static final String TIMEOUT = "/timeout"; public static final byte[] SHORT_BODY = "hi there".getBytes(StandardCharsets.UTF_8); public static final byte[] LONG_BODY = createLongBody(); @@ -119,6 +120,16 @@ private static LocalTestServer initializeServer() { }); } else if (get && "/connectionClose".equals(path)) { resp.getHttpChannel().getConnection().close(); + } else if (get && TIMEOUT.equals(path)) { + try { + Thread.sleep(5000); + resp.setStatus(200); + resp.getHttpOutput().write(SHORT_BODY); + resp.getHttpOutput().flush(); + resp.getHttpOutput().complete(Callback.NOOP); + } catch (InterruptedException e) { + throw new ServletException(e); + } } else { throw new ServletException("Unexpected request: " + req.getMethod() + " " + path); } diff --git a/sdk/core/azure-core-http-vertx/pom.xml b/sdk/core/azure-core-http-vertx/pom.xml index b077001bce30..7e2283c0db87 100644 --- a/sdk/core/azure-core-http-vertx/pom.xml +++ b/sdk/core/azure-core-http-vertx/pom.xml @@ -96,12 +96,6 @@ 4.5.7 - - io.vertx - vertx-reactive-streams - 4.5.7 - - com.azure diff --git a/sdk/core/azure-core-http-vertx/spotbugs-exclude.xml b/sdk/core/azure-core-http-vertx/spotbugs-exclude.xml index 034d19a0d9fa..9e5076b8694f 100644 --- a/sdk/core/azure-core-http-vertx/spotbugs-exclude.xml +++ b/sdk/core/azure-core-http-vertx/spotbugs-exclude.xml @@ -16,4 +16,12 @@ + + + + + + + + diff --git a/sdk/core/azure-core-http-vertx/src/main/java/com/azure/core/http/vertx/VertxAsyncHttpClient.java b/sdk/core/azure-core-http-vertx/src/main/java/com/azure/core/http/vertx/VertxAsyncHttpClient.java index 7083892be4d2..2ea83eb4d1cd 100644 --- a/sdk/core/azure-core-http-vertx/src/main/java/com/azure/core/http/vertx/VertxAsyncHttpClient.java +++ b/sdk/core/azure-core-http-vertx/src/main/java/com/azure/core/http/vertx/VertxAsyncHttpClient.java @@ -11,51 +11,55 @@ import com.azure.core.http.vertx.implementation.BufferedVertxHttpResponse; import com.azure.core.http.vertx.implementation.VertxHttpAsyncResponse; import com.azure.core.http.vertx.implementation.VertxRequestWriteSubscriber; +import com.azure.core.http.vertx.implementation.VertxUtils; import com.azure.core.implementation.util.BinaryDataContent; import com.azure.core.implementation.util.BinaryDataHelper; import com.azure.core.implementation.util.ByteArrayContent; import com.azure.core.implementation.util.ByteBufferContent; -import com.azure.core.implementation.util.FileContent; +import com.azure.core.implementation.util.HttpUtils; import com.azure.core.implementation.util.SerializableContent; import com.azure.core.implementation.util.StringContent; import com.azure.core.util.BinaryData; import com.azure.core.util.Context; import com.azure.core.util.Contexts; import com.azure.core.util.ProgressReporter; +import com.azure.core.util.logging.ClientLogger; import io.netty.buffer.Unpooled; -import io.vertx.core.Vertx; +import io.vertx.core.Future; +import io.vertx.core.Promise; import io.vertx.core.buffer.Buffer; -import io.vertx.core.file.AsyncFile; -import io.vertx.core.file.OpenOptions; import io.vertx.core.http.HttpClientRequest; import io.vertx.core.http.HttpClientResponse; import io.vertx.core.http.HttpMethod; import io.vertx.core.http.RequestOptions; import reactor.core.publisher.Mono; -import reactor.core.publisher.MonoSink; +import reactor.util.context.ContextView; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.time.Duration; import java.util.Objects; - -import static com.azure.core.http.vertx.implementation.VertxUtils.wrapVertxException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; /** * {@link HttpClient} implementation for the Vert.x {@link io.vertx.core.http.HttpClient}. */ class VertxAsyncHttpClient implements HttpClient { - private static final String AZURE_EAGERLY_READ_RESPONSE = "azure-eagerly-read-response"; - private static final String AZURE_IGNORE_RESPONSE_BODY = "azure-ignore-response-body"; + private static final ClientLogger LOGGER = new ClientLogger(VertxAsyncHttpClient.class); - private final Vertx vertx; final io.vertx.core.http.HttpClient client; + private final Duration responseTimeout; /** * Constructs a {@link VertxAsyncHttpClient}. * * @param client The Vert.x {@link io.vertx.core.http.HttpClient} */ - VertxAsyncHttpClient(io.vertx.core.http.HttpClient client, Vertx vertx) { + VertxAsyncHttpClient(io.vertx.core.http.HttpClient client, Duration responseTimeout) { this.client = Objects.requireNonNull(client, "client cannot be null"); - this.vertx = Objects.requireNonNull(vertx, "vertx cannot be null"); + this.responseTimeout = responseTimeout; } @Override @@ -65,17 +69,57 @@ public Mono send(HttpRequest request) { @Override public Mono send(HttpRequest request, Context context) { - boolean eagerlyReadResponse = (boolean) context.getData(AZURE_EAGERLY_READ_RESPONSE).orElse(false); - boolean ignoreResponseBody = (boolean) context.getData(AZURE_IGNORE_RESPONSE_BODY).orElse(false); + return Mono.deferContextual(contextView -> Mono.fromFuture(sendInternal(request, context, contextView))) + .onErrorMap(VertxUtils::wrapVertxException); + } + + @Override + public HttpResponse sendSync(HttpRequest request, Context context) { + try { + return sendInternal(request, context, reactor.util.context.Context.empty()).get(); + } catch (Exception e) { + Throwable mapped = e; + if (e instanceof ExecutionException) { + mapped = e.getCause(); + } + + mapped = VertxUtils.wrapVertxException(mapped); + if (mapped instanceof Error) { + throw LOGGER.logThrowableAsError((Error) mapped); + } else if (mapped instanceof IOException) { + throw LOGGER.logExceptionAsError(new UncheckedIOException((IOException) mapped)); + } else if (mapped instanceof RuntimeException) { + throw LOGGER.logExceptionAsError((RuntimeException) mapped); + } else { + throw LOGGER.logExceptionAsError(new RuntimeException(mapped)); + } + } + } + + private CompletableFuture sendInternal(HttpRequest request, Context context, + ContextView contextView) { + boolean eagerlyReadResponse = (boolean) context.getData(HttpUtils.AZURE_EAGERLY_READ_RESPONSE).orElse(false); + boolean ignoreResponseBody = (boolean) context.getData(HttpUtils.AZURE_IGNORE_RESPONSE_BODY).orElse(false); + Duration perCallTimeout = (Duration) context.getData(HttpUtils.AZURE_RESPONSE_TIMEOUT) + .filter(timeoutDuration -> timeoutDuration instanceof Duration) + .orElse(responseTimeout); ProgressReporter progressReporter = Contexts.with(context).getHttpRequestProgressReporter(); RequestOptions options = new RequestOptions().setMethod(HttpMethod.valueOf(request.getHttpMethod().name())) .setAbsoluteURI(request.getUrl()); - return Mono.create(sink -> client.request(options, requestResult -> { + // This is the shared design for sending a request and receiving a response in Vert.x. The design relies on + // using a Vert.x Promise and the handler methods to control the flow of the request-response cycle. The Promise + // will be completed upon failure during the request-response cycle or upon completion of the response. This can + // be shared between sync and async as Reactor can use Mono.fromCompletionStage to convert the Promise to a Mono + // and the sync path can convert the Promise to a Future and block it. + + // Create the Promise that will be returned. Promise.promise() is an uncompleted Promise. + Promise promise = Promise.promise(); + client.request(options, requestResult -> { if (requestResult.failed()) { - sink.error(wrapVertxException(requestResult.cause())); + promise.fail(requestResult.cause()); return; } @@ -89,98 +133,70 @@ public Mono send(HttpRequest request, Context context) { vertxRequest.setChunked(true); } - vertxRequest.response(event -> { - if (event.succeeded()) { - HttpClientResponse vertxHttpResponse = event.result(); - vertxHttpResponse.exceptionHandler(exception -> sink.error(wrapVertxException(exception))); - - // TODO (alzimmer) - // For now Vertx will always use a buffered response until reliability issues when using streaming - // can be resolved. - if (eagerlyReadResponse || ignoreResponseBody) { - vertxHttpResponse.body(bodyEvent -> { - if (bodyEvent.succeeded()) { - sink.success( - new BufferedVertxHttpResponse(request, vertxHttpResponse, bodyEvent.result())); - } else { - sink.error(wrapVertxException(bodyEvent.cause())); - } - }); + Future responseFuture; + if (!perCallTimeout.isZero() && !perCallTimeout.isNegative()) { + responseFuture = vertxRequest.response().timeout(perCallTimeout.toMillis(), TimeUnit.MILLISECONDS); + } else { + responseFuture = vertxRequest.response(); + } + + responseFuture = responseFuture.onFailure(promise::fail); + + if (eagerlyReadResponse || ignoreResponseBody) { + responseFuture.andThen(responseResult -> { + if (responseResult.failed()) { + promise.fail(responseResult.cause()); + return; + } + + HttpClientResponse vertxHttpResponse = responseResult.result(); + vertxHttpResponse.body().andThen(bodyResult -> { + if (bodyResult.succeeded()) { + promise.complete( + new BufferedVertxHttpResponse(request, vertxHttpResponse, bodyResult.result())); + } else { + promise.fail(bodyResult.cause()); + } + }); + }); + } else { + responseFuture.andThen(responseResult -> { + if (responseResult.succeeded()) { + promise.complete(new VertxHttpAsyncResponse(request, responseResult.result())); } else { - sink.success(new VertxHttpAsyncResponse(request, vertxHttpResponse)); + promise.fail(responseResult.cause()); } - } else { - sink.error(wrapVertxException(event.cause())); - } - }); + }); + } - sendBody(sink, request, progressReporter, vertxRequest); - })); - } + sendBody(contextView, request, progressReporter, vertxRequest, promise); + }); - @Override - public HttpResponse sendSync(HttpRequest request, Context context) { - return send(request, context).block(); + return promise.future().toCompletionStage().toCompletableFuture(); } @SuppressWarnings("deprecation") - private void sendBody(MonoSink sink, HttpRequest azureRequest, ProgressReporter progressReporter, - HttpClientRequest vertxRequest) { + private void sendBody(ContextView contextView, HttpRequest azureRequest, ProgressReporter progressReporter, + HttpClientRequest vertxRequest, Promise promise) { BinaryData body = azureRequest.getBodyAsBinaryData(); - if (body == null) { - vertxRequest.send(result -> { - if (result.failed()) { - sink.error(wrapVertxException(result.cause())); - } - }); - return; - } - - BinaryDataContent bodyContent = BinaryDataHelper.getContent(body); - if (bodyContent instanceof ByteArrayContent - || bodyContent instanceof StringContent - || bodyContent instanceof SerializableContent) { - byte[] content = bodyContent.toBytes(); - vertxRequest.send(Buffer.buffer(Unpooled.wrappedBuffer(content)), result -> { - if (result.succeeded()) { - reportProgress(content.length, progressReporter); - } else { - sink.error(wrapVertxException(result.cause())); - } - }); - } else if (bodyContent instanceof ByteBufferContent) { - long contentLength = bodyContent.getLength(); - vertxRequest.send(Buffer.buffer(Unpooled.wrappedBuffer(bodyContent.toByteBuffer())), result -> { - if (result.succeeded()) { - reportProgress(contentLength, progressReporter); - } else { - sink.error(wrapVertxException(result.cause())); - } - }); - } else if (bodyContent instanceof FileContent) { - FileContent fileContent = (FileContent) bodyContent; - vertx.fileSystem().open(fileContent.getFile().toString(), new OpenOptions().setRead(true), event -> { - if (event.succeeded()) { - AsyncFile file = event.result(); - file.setReadPos(fileContent.getPosition()); - if (fileContent.getLength() != null) { - file.setReadLength(fileContent.getLength()); - } - vertxRequest.send(file, result -> { - if (result.succeeded()) { - reportProgress(fileContent.getLength(), progressReporter); - } else { - sink.error(wrapVertxException(result.cause())); - } - }); - } else { - sink.error(wrapVertxException(event.cause())); - } - }); + if (body == null) { + vertxRequest.send().onFailure(promise::fail); } else { - // Right now both Flux and InputStream bodies are being handled reactively. - azureRequest.getBody().subscribe(new VertxRequestWriteSubscriber(vertxRequest, sink, progressReporter)); + BinaryDataContent bodyContent = BinaryDataHelper.getContent(body); + if (bodyContent instanceof ByteArrayContent + || bodyContent instanceof ByteBufferContent + || bodyContent instanceof StringContent + || bodyContent instanceof SerializableContent) { + long contentLength = bodyContent.getLength(); + vertxRequest.send(Buffer.buffer(Unpooled.wrappedBuffer(bodyContent.toByteBuffer()))) + .onSuccess(ignored -> reportProgress(contentLength, progressReporter)) + .onFailure(promise::fail); + } else { + // Right now both Flux and InputStream bodies are being handled reactively. + azureRequest.getBody() + .subscribe(new VertxRequestWriteSubscriber(vertxRequest, promise, progressReporter, contextView)); + } } } diff --git a/sdk/core/azure-core-http-vertx/src/main/java/com/azure/core/http/vertx/VertxAsyncHttpClientBuilder.java b/sdk/core/azure-core-http-vertx/src/main/java/com/azure/core/http/vertx/VertxAsyncHttpClientBuilder.java index 270479074f73..ceca3b582e78 100644 --- a/sdk/core/azure-core-http-vertx/src/main/java/com/azure/core/http/vertx/VertxAsyncHttpClientBuilder.java +++ b/sdk/core/azure-core-http-vertx/src/main/java/com/azure/core/http/vertx/VertxAsyncHttpClientBuilder.java @@ -20,10 +20,11 @@ import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; -import static com.azure.core.util.Configuration.PROPERTY_AZURE_REQUEST_CONNECT_TIMEOUT; -import static com.azure.core.util.Configuration.PROPERTY_AZURE_REQUEST_READ_TIMEOUT; -import static com.azure.core.util.Configuration.PROPERTY_AZURE_REQUEST_WRITE_TIMEOUT; -import static com.azure.core.util.CoreUtils.getDefaultTimeoutFromEnvironment; +import static com.azure.core.implementation.util.HttpUtils.getDefaultConnectTimeout; +import static com.azure.core.implementation.util.HttpUtils.getDefaultReadTimeout; +import static com.azure.core.implementation.util.HttpUtils.getDefaultResponseTimeout; +import static com.azure.core.implementation.util.HttpUtils.getDefaultWriteTimeout; +import static com.azure.core.implementation.util.HttpUtils.getTimeout; /** * Builds a {@link VertxAsyncHttpClient}. @@ -34,24 +35,11 @@ public class VertxAsyncHttpClientBuilder { private static final Pattern NON_PROXY_HOSTS_SPLIT = Pattern.compile("(? + * The connection timeout begins once the request attempts to connect to the remote host and finishes once the + * connection is resolved. + *

+ * If {@code connectTimeout} is null either {@link Configuration#PROPERTY_AZURE_REQUEST_CONNECT_TIMEOUT} or a + * 10-second timeout will be used, if it is a {@link Duration} less than or equal to zero then no timeout will be + * applied. When applying the timeout the greatest of one millisecond and the value of {@code connectTimeout} will + * be used. *

- * The default read idle timeout is 60 seconds. + * By default, the connection timeout is 10 seconds. * - * @param readIdleTimeout the read idle timeout - * @return the updated VertxAsyncHttpClientBuilder object + * @param connectTimeout Connect timeout duration. + * @return The updated OkHttpAsyncHttpClientBuilder object. */ - public VertxAsyncHttpClientBuilder readIdleTimeout(Duration readIdleTimeout) { - this.readIdleTimeout = readIdleTimeout; + public VertxAsyncHttpClientBuilder connectTimeout(Duration connectTimeout) { + // setConnectionTimeout can be null + this.connectTimeout = connectTimeout; return this; } /** - * Sets the write idle timeout. + * Sets the read timeout duration used when reading the server response. *

- * The default read idle timeout is 60 seconds. + * The read timeout begins once the first response read is triggered after the server response is received. This + * timeout triggers periodically but won't fire its operation if another read operation has completed between when + * the timeout is triggered and completes. + *

+ * If {@code readTimeout} is null or {@link Configuration#PROPERTY_AZURE_REQUEST_READ_TIMEOUT} or a 60-second + * timeout will be used, if it is a {@link Duration} less than or equal to zero then no timeout period will be + * applied to response read. When applying the timeout the greatest of one millisecond and the value of {@code + * readTimeout} will be used. * - * @param writeIdleTimeout the write idle timeout - * @return the updated VertxAsyncHttpClientBuilder object + * @param readTimeout Read timeout duration. + * @return The updated OkHttpAsyncHttpClientBuilder object. */ - public VertxAsyncHttpClientBuilder writeIdleTimeout(Duration writeIdleTimeout) { - this.writeIdleTimeout = writeIdleTimeout; + public VertxAsyncHttpClientBuilder readTimeout(Duration readTimeout) { + this.readTimeout = readTimeout; return this; } /** - * Sets the connect timeout. + * Sets the response timeout duration used when waiting for a server to reply. + *

+ * The response timeout begins once the request write completes and finishes once the first response read is + * triggered when the server response is received. + *

+ * If {@code responseTimeout} is null either {@link Configuration#PROPERTY_AZURE_REQUEST_RESPONSE_TIMEOUT} or a + * 60-second timeout will be used, if it is a {@link Duration} less than or equal to zero then no timeout will be + * applied to the response. When applying the timeout the greatest of one millisecond and the value of {@code + * responseTimeout} will be used. *

- * The default connect timeout is 10 seconds. + * Given OkHttp doesn't have an equivalent timeout for just responses, this is handled manually. * - * @param connectTimeout the connection timeout - * @return the updated VertxAsyncHttpClientBuilder object + * @param responseTimeout Response timeout duration. + * @return The updated VertxAsyncHttpClientBuilder object. */ - public VertxAsyncHttpClientBuilder connectTimeout(Duration connectTimeout) { - this.connectTimeout = connectTimeout; + public VertxAsyncHttpClientBuilder responseTimeout(Duration responseTimeout) { + this.responseTimeout = responseTimeout; return this; } /** - * Sets the connection idle timeout. + * Sets the writing timeout for a request to be sent. + *

+ * The writing timeout does not apply to the entire request but to the request being sent over the wire. For example + * a request body which emits {@code 10} {@code 8KB} buffers will trigger {@code 10} write operations, the last + * write tracker will update when each operation completes and the outbound buffer will be periodically checked to + * determine if it is still draining. *

- * The default connect timeout is 60 seconds. + * If {@code writeTimeout} is null either {@link Configuration#PROPERTY_AZURE_REQUEST_WRITE_TIMEOUT} or a 60-second + * timeout will be used, if it is a {@link Duration} less than or equal to zero then no write timeout will be + * applied. When applying the timeout the greatest of one millisecond and the value of {@code writeTimeout} will be + * used. * - * @param idleTimeout the connection idle timeout - * @return the updated VertxAsyncHttpClientBuilder object + * @param writeTimeout Write operation timeout duration. + * @return The updated VertxAsyncHttpClientBuilder object. */ - public VertxAsyncHttpClientBuilder idleTimeout(Duration idleTimeout) { - this.idleTimeout = idleTimeout; + public VertxAsyncHttpClientBuilder writeTimeout(Duration writeTimeout) { + this.writeTimeout = writeTimeout; return this; } @@ -178,35 +198,18 @@ public HttpClient build() { configuredVertx = getVertx(vertxProviders.iterator()); } - if (this.httpClientOptions == null) { - this.httpClientOptions = new HttpClientOptions(); - - if (this.connectTimeout != null) { - this.httpClientOptions.setConnectTimeout((int) this.connectTimeout.toMillis()); - } else { - this.httpClientOptions.setConnectTimeout((int) DEFAULT_CONNECT_TIMEOUT); - } - - if (this.readIdleTimeout != null) { - this.httpClientOptions.setReadIdleTimeout((int) this.readIdleTimeout.getSeconds()); - } else { - this.httpClientOptions.setReadIdleTimeout((int) DEFAULT_READ_TIMEOUT); - } - - if (this.writeIdleTimeout != null) { - this.httpClientOptions.setWriteIdleTimeout((int) this.writeIdleTimeout.getSeconds()); - } else { - this.httpClientOptions.setWriteIdleTimeout((int) DEFAULT_WRITE_TIMEOUT); - } - - this.httpClientOptions.setIdleTimeout((int) this.idleTimeout.getSeconds()); + HttpClientOptions buildOptions = this.httpClientOptions; + if (buildOptions == null) { + buildOptions = new HttpClientOptions().setIdleTimeoutUnit(TimeUnit.MILLISECONDS) + .setConnectTimeout((int) getTimeout(this.connectTimeout, getDefaultConnectTimeout()).toMillis()) + .setReadIdleTimeout((int) getTimeout(this.readTimeout, getDefaultReadTimeout()).toMillis()) + .setWriteIdleTimeout((int) getTimeout(this.writeTimeout, getDefaultWriteTimeout()).toMillis()); Configuration buildConfiguration - = (this.configuration == null) ? Configuration.getGlobalConfiguration() : configuration; + = (configuration == null) ? Configuration.getGlobalConfiguration() : configuration; - ProxyOptions buildProxyOptions = (this.proxyOptions == null) - ? ProxyOptions.fromConfiguration(buildConfiguration, true) - : this.proxyOptions; + ProxyOptions buildProxyOptions + = (proxyOptions == null) ? ProxyOptions.fromConfiguration(buildConfiguration, true) : proxyOptions; if (buildProxyOptions != null) { io.vertx.core.net.ProxyOptions vertxProxyOptions = new io.vertx.core.net.ProxyOptions(); @@ -238,16 +241,16 @@ public HttpClient build() { String nonProxyHosts = buildProxyOptions.getNonProxyHosts(); if (!CoreUtils.isNullOrEmpty(nonProxyHosts)) { for (String nonProxyHost : desanitizedNonProxyHosts(nonProxyHosts)) { - this.httpClientOptions.addNonProxyHost(nonProxyHost); + buildOptions.addNonProxyHost(nonProxyHost); } } - this.httpClientOptions.setProxyOptions(vertxProxyOptions); + buildOptions.setProxyOptions(vertxProxyOptions); } } - io.vertx.core.http.HttpClient client = configuredVertx.createHttpClient(this.httpClientOptions); - return new VertxAsyncHttpClient(client, configuredVertx); + io.vertx.core.http.HttpClient client = configuredVertx.createHttpClient(buildOptions); + return new VertxAsyncHttpClient(client, getTimeout(this.responseTimeout, getDefaultResponseTimeout())); } static Vertx getVertx(Iterator iterator) { diff --git a/sdk/core/azure-core-http-vertx/src/main/java/com/azure/core/http/vertx/VertxAsyncHttpClientProvider.java b/sdk/core/azure-core-http-vertx/src/main/java/com/azure/core/http/vertx/VertxAsyncHttpClientProvider.java index 46c1a2476340..fba579502404 100644 --- a/sdk/core/azure-core-http-vertx/src/main/java/com/azure/core/http/vertx/VertxAsyncHttpClientProvider.java +++ b/sdk/core/azure-core-http-vertx/src/main/java/com/azure/core/http/vertx/VertxAsyncHttpClientProvider.java @@ -60,9 +60,9 @@ public HttpClient createInstance(HttpClientOptions clientOptions) { return new VertxAsyncHttpClientBuilder().proxy(clientOptions.getProxyOptions()) .configuration(clientOptions.getConfiguration()) .connectTimeout(clientOptions.getConnectTimeout()) - .idleTimeout(clientOptions.getConnectionIdleTimeout()) - .writeIdleTimeout(clientOptions.getWriteTimeout()) - .readIdleTimeout(clientOptions.getReadTimeout()) + .writeTimeout(clientOptions.getWriteTimeout()) + .responseTimeout(clientOptions.getResponseTimeout()) + .readTimeout(clientOptions.getReadTimeout()) .build(); } } diff --git a/sdk/core/azure-core-http-vertx/src/main/java/com/azure/core/http/vertx/implementation/VertxRequestWriteSubscriber.java b/sdk/core/azure-core-http-vertx/src/main/java/com/azure/core/http/vertx/implementation/VertxRequestWriteSubscriber.java index 7324a2bf38a0..2c9d12e16870 100644 --- a/sdk/core/azure-core-http-vertx/src/main/java/com/azure/core/http/vertx/implementation/VertxRequestWriteSubscriber.java +++ b/sdk/core/azure-core-http-vertx/src/main/java/com/azure/core/http/vertx/implementation/VertxRequestWriteSubscriber.java @@ -5,7 +5,6 @@ import com.azure.core.http.HttpResponse; import com.azure.core.util.ProgressReporter; -import com.azure.core.util.logging.ClientLogger; import io.netty.buffer.Unpooled; import io.vertx.core.buffer.Buffer; import io.vertx.core.http.HttpClientRequest; @@ -14,21 +13,19 @@ import reactor.core.publisher.MonoSink; import reactor.core.publisher.Operators; import reactor.util.context.Context; +import reactor.util.context.ContextView; import java.nio.ByteBuffer; -import static com.azure.core.http.vertx.implementation.VertxUtils.wrapVertxException; - /** * Subscriber that writes a stream of {@link ByteBuffer ByteBuffers} to a {@link HttpClientRequest Vert.x request}. */ @SuppressWarnings("ReactiveStreamsSubscriberImplementation") public final class VertxRequestWriteSubscriber implements Subscriber { - private static final ClientLogger LOGGER = new ClientLogger(VertxRequestWriteSubscriber.class); - private final HttpClientRequest request; - private final MonoSink emitter; + private final io.vertx.core.Promise promise; private final ProgressReporter progressReporter; + private final ContextView contextView; // This subscriber is effectively synchronous so there is no need for these fields to be volatile. private volatile Subscription subscription; @@ -41,14 +38,16 @@ public final class VertxRequestWriteSubscriber implements Subscriber * {@link HttpClientRequest Vert.x request}. * * @param request The {@link HttpClientRequest Vert.x request} to write to. - * @param emitter The {@link MonoSink} to emit the {@link HttpResponse response} to. + * @param promise The {@link MonoSink} to emit the {@link HttpResponse response} to. * @param progressReporter The {@link ProgressReporter} to report progress to. + * @param contextView The {@link ContextView} to use when dropping errors. */ - public VertxRequestWriteSubscriber(HttpClientRequest request, MonoSink emitter, - ProgressReporter progressReporter) { + public VertxRequestWriteSubscriber(HttpClientRequest request, io.vertx.core.Promise promise, + ProgressReporter progressReporter, ContextView contextView) { this.request = request.exceptionHandler(this::onError).drainHandler(ignored -> requestNext()); - this.emitter = emitter; + this.promise = promise; this.progressReporter = progressReporter; + this.contextView = contextView; } @Override @@ -122,7 +121,7 @@ private void onErrorInternal(Throwable throwable) { State state = this.state; // code 2 and greater are completion states which means the error should be dropped as we already completed. if (state.code >= 2) { - Operators.onErrorDropped(throwable, Context.of(emitter.contextView())); + Operators.onErrorDropped(throwable, Context.of(contextView)); } this.state = State.ERROR; @@ -135,7 +134,7 @@ private void onErrorInternal(Throwable throwable) { private void resetRequest(Throwable throwable) { subscription.cancel(); - emitter.error(wrapVertxException(throwable)); + promise.fail(throwable); request.reset(0, throwable); } @@ -156,11 +155,7 @@ public void onComplete() { } private void endRequest() { - request.end(result -> { - if (result.failed()) { - emitter.error(wrapVertxException(result.cause())); - } - }); + request.end().onFailure(promise::fail); } private enum State { diff --git a/sdk/core/azure-core-http-vertx/src/samples/java/com/azure/core/http/vertx/VertxHttpClientBuilderJavaDocCodeSnippets.java b/sdk/core/azure-core-http-vertx/src/samples/java/com/azure/core/http/vertx/VertxHttpClientBuilderJavaDocCodeSnippets.java index 8a8da69d7664..6150813bb45d 100644 --- a/sdk/core/azure-core-http-vertx/src/samples/java/com/azure/core/http/vertx/VertxHttpClientBuilderJavaDocCodeSnippets.java +++ b/sdk/core/azure-core-http-vertx/src/samples/java/com/azure/core/http/vertx/VertxHttpClientBuilderJavaDocCodeSnippets.java @@ -12,6 +12,7 @@ /** * Code snippets for {@link VertxHttpClientBuilderJavaDocCodeSnippets} */ +@SuppressWarnings("unused") public class VertxHttpClientBuilderJavaDocCodeSnippets { /** @@ -55,25 +56,15 @@ public void proxyBasicAuthenticationSample() { } - public void connectionTimeoutSample() { - - // BEGIN: com.azure.core.http.vertx.vertxAsyncHttpClientBuilder#connextTimeout - final Duration connextTimeout = Duration.ofSeconds(250); // connection timeout of 250 seconds - HttpClient client = new VertxAsyncHttpClientBuilder() - .connectTimeout(connextTimeout) - .build(); - // END: com.azure.core.http.vertx.vertxAsyncHttpClientBuilder#connextTimeout - - } - - public void readTimeoutSample() { - - // BEGIN: com.azure.core.http.vertx.vertxAsyncHttpClientBuilder#readTimeout - final Duration readIdleTimeout = Duration.ofSeconds(100); // read timeout of 100 seconds + public void timeoutSample() { + // BEGIN: com.azure.core.http.vertx.VertxAsyncHttpClientBuilder#timeoutSample HttpClient client = new VertxAsyncHttpClientBuilder() - .readIdleTimeout(readIdleTimeout) - .build(); - // END: com.azure.core.http.vertx.vertxAsyncHttpClientBuilder#readTimeout + .connectTimeout(Duration.ofSeconds(10)) // Timeout of 10 seconds for establishing a connection + .writeTimeout(Duration.ofSeconds(100)) // Timeout of 100 seconds when network writing is idle + .responseTimeout(Duration.ofSeconds(30)) // Timeout of 30 seconds for the server to return a response + .readTimeout(Duration.ofSeconds(100)) // Timeout of 100 seconds when network reading is idle + .build(); + // END: com.azure.core.http.vertx.VertxAsyncHttpClientBuilder#timeoutSample } } diff --git a/sdk/core/azure-core-http-vertx/src/test/java/com/azure/core/http/vertx/VertxAsyncHttpClientBuilderTests.java b/sdk/core/azure-core-http-vertx/src/test/java/com/azure/core/http/vertx/VertxAsyncHttpClientBuilderTests.java index 56a9bade3cb1..6a642cbf9ee5 100644 --- a/sdk/core/azure-core-http-vertx/src/test/java/com/azure/core/http/vertx/VertxAsyncHttpClientBuilderTests.java +++ b/sdk/core/azure-core-http-vertx/src/test/java/com/azure/core/http/vertx/VertxAsyncHttpClientBuilderTests.java @@ -63,8 +63,7 @@ public void buildWithConfigurationNone() { @Test public void buildWithDefaultConnectionOptions() { - VertxAsyncHttpClientBuilder builder = new VertxAsyncHttpClientBuilder(); - HttpClient httpClient = builder.build(); + HttpClient httpClient = new VertxAsyncHttpClientBuilder().build(); io.vertx.core.http.HttpClient client = ((VertxAsyncHttpClient) httpClient).client; io.vertx.core.http.HttpClientOptions options = ((HttpClientImpl) client).options(); @@ -76,18 +75,16 @@ public void buildWithDefaultConnectionOptions() { .verifyComplete(); assertEquals(10000, options.getConnectTimeout()); - assertEquals(60, options.getIdleTimeout()); - assertEquals(60, options.getReadIdleTimeout()); - assertEquals(60, options.getWriteIdleTimeout()); + assertEquals(60000, options.getReadIdleTimeout()); + assertEquals(60000, options.getWriteIdleTimeout()); } @Test public void buildWithConnectionOptions() { VertxAsyncHttpClientBuilder builder = new VertxAsyncHttpClientBuilder(); VertxAsyncHttpClient httpClient = (VertxAsyncHttpClient) builder.connectTimeout(Duration.ofSeconds(10)) - .idleTimeout(Duration.ofSeconds(20)) - .readIdleTimeout(Duration.ofSeconds(30)) - .writeIdleTimeout(Duration.ofSeconds(40)) + .readTimeout(Duration.ofSeconds(30)) + .writeTimeout(Duration.ofSeconds(40)) .build(); io.vertx.core.http.HttpClientOptions options = ((HttpClientImpl) httpClient.client).options(); @@ -99,9 +96,8 @@ public void buildWithConnectionOptions() { .verifyComplete(); assertEquals(10000, options.getConnectTimeout()); - assertEquals(20, options.getIdleTimeout()); - assertEquals(30, options.getReadIdleTimeout()); - assertEquals(40, options.getWriteIdleTimeout()); + assertEquals(30000, options.getReadIdleTimeout()); + assertEquals(40000, options.getWriteIdleTimeout()); } @ParameterizedTest @@ -214,15 +210,13 @@ public void buildWithCustomHttpClientOptions() { options.setWriteIdleTimeout(70); HttpClient httpClient = new VertxAsyncHttpClientBuilder().connectTimeout(Duration.ofSeconds(10)) - .idleTimeout(Duration.ofSeconds(20)) - .readIdleTimeout(Duration.ofSeconds(30)) - .writeIdleTimeout(Duration.ofSeconds(40)) + .readTimeout(Duration.ofSeconds(30)) + .writeTimeout(Duration.ofSeconds(40)) .httpClientOptions(options) .build(); // Verify the original configuration was preserved and not overwritten assertEquals(30000, options.getConnectTimeout()); - assertEquals(50, options.getIdleTimeout()); assertEquals(60, options.getReadIdleTimeout()); assertEquals(70, options.getWriteIdleTimeout()); diff --git a/sdk/core/azure-core-http-vertx/src/test/java/com/azure/core/http/vertx/VertxAsyncHttpClientProviderTests.java b/sdk/core/azure-core-http-vertx/src/test/java/com/azure/core/http/vertx/VertxAsyncHttpClientProviderTests.java index e7e68f08c110..1714f4a0f566 100644 --- a/sdk/core/azure-core-http-vertx/src/test/java/com/azure/core/http/vertx/VertxAsyncHttpClientProviderTests.java +++ b/sdk/core/azure-core-http-vertx/src/test/java/com/azure/core/http/vertx/VertxAsyncHttpClientProviderTests.java @@ -107,9 +107,8 @@ public void optionsWithTimeouts() { io.vertx.core.http.HttpClientOptions options = ((HttpClientImpl) httpClient.client).options(); assertEquals(timeout.toMillis(), options.getConnectTimeout()); - assertEquals(timeout.getSeconds(), options.getIdleTimeout()); - assertEquals(timeout.getSeconds(), options.getReadIdleTimeout()); - assertEquals(timeout.getSeconds(), options.getWriteIdleTimeout()); + assertEquals(timeout.toMillis(), options.getReadIdleTimeout()); + assertEquals(timeout.toMillis(), options.getWriteIdleTimeout()); } @Test diff --git a/sdk/core/azure-core-http-vertx/src/test/java/com/azure/core/http/vertx/VertxAsyncHttpClientTests.java b/sdk/core/azure-core-http-vertx/src/test/java/com/azure/core/http/vertx/VertxAsyncHttpClientTests.java index 8e3e699f49f4..fa4742430177 100644 --- a/sdk/core/azure-core-http-vertx/src/test/java/com/azure/core/http/vertx/VertxAsyncHttpClientTests.java +++ b/sdk/core/azure-core-http-vertx/src/test/java/com/azure/core/http/vertx/VertxAsyncHttpClientTests.java @@ -10,10 +10,10 @@ import com.azure.core.http.HttpMethod; import com.azure.core.http.HttpRequest; import com.azure.core.http.HttpResponse; +import com.azure.core.implementation.util.HttpUtils; import com.azure.core.util.Context; +import com.azure.core.util.FluxUtil; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.parallel.Execution; -import org.junit.jupiter.api.parallel.ExecutionMode; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.publisher.ParallelFlux; @@ -36,16 +36,20 @@ import java.util.concurrent.Callable; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import static com.azure.core.http.vertx.VertxHttpClientLocalTestServer.LONG_BODY; import static com.azure.core.http.vertx.VertxHttpClientLocalTestServer.RETURN_HEADERS_AS_IS_PATH; import static com.azure.core.http.vertx.VertxHttpClientLocalTestServer.SHORT_BODY; +import static com.azure.core.http.vertx.VertxHttpClientLocalTestServer.TIMEOUT; +import static com.azure.core.test.utils.TestUtils.assertArraysEqual; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertLinesMatch; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -@Execution(ExecutionMode.SAME_THREAD) public class VertxAsyncHttpClientTests { private static final String SERVER_HTTP_URI = VertxHttpClientLocalTestServer.getServer().getHttpUri(); @@ -236,6 +240,46 @@ public void testEmptyBufferedResponse() { .verifyComplete(); } + @Test + public void perCallTimeout() { + HttpClient client = new VertxAsyncHttpClientBuilder().responseTimeout(Duration.ofSeconds(10)).build(); + + HttpRequest request = new HttpRequest(HttpMethod.GET, url(TIMEOUT)); + + // Verify a smaller timeout sent through Context times out the request. + StepVerifier.create(client.send(request, new Context(HttpUtils.AZURE_RESPONSE_TIMEOUT, Duration.ofSeconds(1)))) + .expectErrorMatches(e -> e instanceof TimeoutException) + .verify(); + + // Then verify not setting a timeout through Context does not time out the request. + StepVerifier.create(client.send(request) + .flatMap(response -> Mono.zip(FluxUtil.collectBytesInByteBufferStream(response.getBody()), + Mono.just(response.getStatusCode())))) + .assertNext(tuple -> { + assertArraysEqual(SHORT_BODY, tuple.getT1()); + assertEquals(200, tuple.getT2()); + }) + .verifyComplete(); + } + + @Test + public void perCallTimeoutSync() { + HttpClient client = new VertxAsyncHttpClientBuilder().responseTimeout(Duration.ofSeconds(10)).build(); + + HttpRequest request = new HttpRequest(HttpMethod.GET, url(TIMEOUT)); + + // Verify a smaller timeout sent through Context times out the request. + RuntimeException ex = assertThrows(RuntimeException.class, + () -> client.sendSync(request, new Context(HttpUtils.AZURE_RESPONSE_TIMEOUT, Duration.ofSeconds(1)))); + assertInstanceOf(TimeoutException.class, ex.getCause()); + + // Then verify not setting a timeout through Context does not time out the request. + try (HttpResponse response = client.sendSync(request, Context.NONE)) { + assertEquals(200, response.getStatusCode()); + assertArraysEqual(SHORT_BODY, response.getBodyAsByteArray().block()); + } + } + private static Mono getResponse(String path) { HttpClient client = new VertxAsyncHttpClientBuilder().build(); return getResponse(client, path, Context.NONE); diff --git a/sdk/core/azure-core-http-vertx/src/test/java/com/azure/core/http/vertx/VertxHttpClientLocalTestServer.java b/sdk/core/azure-core-http-vertx/src/test/java/com/azure/core/http/vertx/VertxHttpClientLocalTestServer.java index 01c63e032632..1d533180191a 100644 --- a/sdk/core/azure-core-http-vertx/src/test/java/com/azure/core/http/vertx/VertxHttpClientLocalTestServer.java +++ b/sdk/core/azure-core-http-vertx/src/test/java/com/azure/core/http/vertx/VertxHttpClientLocalTestServer.java @@ -30,6 +30,7 @@ public final class VertxHttpClientLocalTestServer { public static final byte[] SHORT_BODY = "hi there".getBytes(StandardCharsets.UTF_8); public static final byte[] LONG_BODY = createLongBody(); public static final String RETURN_HEADERS_AS_IS_PATH = "/returnHeadersAsIs"; + public static final String TIMEOUT = "/timeout"; public static final String PROXY_USERNAME = "foo"; public static final String PROXY_PASSWORD = "bar"; @@ -109,6 +110,16 @@ private static LocalTestServer initializeServer() { resp.setContentLength(0); } else if (get && "/connectionClose".equals(path)) { resp.getHttpChannel().getConnection().close(); + } else if (get && TIMEOUT.equals(path)) { + try { + Thread.sleep(5000); + resp.setStatus(200); + resp.getHttpOutput().write(SHORT_BODY); + resp.getHttpOutput().flush(); + resp.getHttpOutput().complete(Callback.NOOP); + } catch (InterruptedException e) { + throw new ServletException(e); + } } else { throw new ServletException("Unexpected request " + req.getMethod() + " " + path); } diff --git a/sdk/core/azure-core-management/src/main/java/com/azure/core/management/SubResource.java b/sdk/core/azure-core-management/src/main/java/com/azure/core/management/SubResource.java index 5e73c158412b..f1bb6c775512 100644 --- a/sdk/core/azure-core-management/src/main/java/com/azure/core/management/SubResource.java +++ b/sdk/core/azure-core-management/src/main/java/com/azure/core/management/SubResource.java @@ -3,10 +3,17 @@ package com.azure.core.management; +import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; + +import java.io.IOException; + /** * The SubResource model. */ -public class SubResource { +public class SubResource implements JsonSerializable { /** * Resource Id. */ @@ -37,4 +44,35 @@ public SubResource withId(String id) { this.id = id; return this; } + + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + return jsonWriter.writeStartObject().writeStringField("id", id).writeEndObject(); + } + + /** + * Reads a JSON stream into a {@link SubResource}. + * + * @param jsonReader The {@link JsonReader} being read. + * @return The {@link SubResource} that the JSON stream represented, may return null. + * @throws IOException If a {@link SubResource} fails to be read from the {@code jsonReader}. + */ + public static SubResource fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + SubResource subResource = new SubResource(); + + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("id".equals(fieldName)) { + subResource.id = reader.getString(); + } else { + reader.skipChildren(); + } + } + + return subResource; + }); + } } diff --git a/sdk/core/azure-core-management/src/test/java/com/azure/core/management/ResourceTests.java b/sdk/core/azure-core-management/src/test/java/com/azure/core/management/ResourceTests.java index 2235c58b5fcd..0cf0e543213a 100644 --- a/sdk/core/azure-core-management/src/test/java/com/azure/core/management/ResourceTests.java +++ b/sdk/core/azure-core-management/src/test/java/com/azure/core/management/ResourceTests.java @@ -6,6 +6,7 @@ import com.azure.core.management.implementation.ProxyResourceAccessHelper; import com.azure.json.JsonProviders; import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; import com.azure.json.JsonToken; import com.azure.json.JsonWriter; import com.azure.json.ReadValueCallback; @@ -14,6 +15,10 @@ import org.junit.jupiter.api.Test; import java.io.IOException; +import java.io.StringWriter; +import java.util.Collections; +import java.util.List; +import java.util.UUID; public class ResourceTests { @@ -127,6 +132,102 @@ public static ResourceWithSystemData fromJson(JsonReader jsonReader) throws IOEx } } + private static class SubResourceResource extends SubResource { + private SubResource subResource; + private List subResourceList; + private SubResourceResource subResourceResource; + private List subResourceResourceList; + + public SubResource subResource() { + return subResource; + } + + public SubResourceResource withSubResource(SubResource subResource) { + this.subResource = subResource; + return this; + } + + public List subResourceList() { + return subResourceList; + } + + public SubResourceResource withSubResourceList(List subResourceList) { + this.subResourceList = subResourceList; + return this; + } + + public SubResourceResource subResourceResource() { + return subResourceResource; + } + + public SubResourceResource withSubResourceResource(SubResourceResource subResourceResource) { + this.subResourceResource = subResourceResource; + return this; + } + + public List subResourceResourceList() { + return subResourceResourceList; + } + + public SubResourceResource withSubResourceResourceList(List subResourceResourceList) { + this.subResourceResourceList = subResourceResourceList; + return this; + } + + @Override + public SubResourceResource withId(String id) { + super.withId(id); + return this; + } + + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + return jsonWriter.writeStartObject() + .writeStringField("id", id()) + .writeJsonField("subResource", this.subResource) + .writeArrayField("subResourceList", this.subResourceList, JsonWriter::writeJson) + .writeJsonField("subResourceResource", this.subResourceResource) + .writeArrayField("subResourceResourceList", this.subResourceResourceList, JsonWriter::writeJson) + .writeEndObject(); + } + + /** + * Reads a JSON stream into a {@link SubResourceResource}. + * + * @param jsonReader The {@link JsonReader} being read. + * @return The {@link SubResourceResource} that the JSON stream represented, may return null. + * @throws IOException If a {@link SubResourceResource} fails to be read from the {@code jsonReader}. + */ + public static SubResourceResource fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + SubResourceResource subResource = new SubResourceResource(); + + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("id".equals(fieldName)) { + subResource.withId(reader.getString()); + } else if ("subResource".equals(fieldName)) { + subResource.withSubResource(reader.readObject(reader1 -> SubResource.fromJson(reader1))); + } else if ("subResourceList".equals(fieldName)) { + subResource.withSubResourceList(reader.readArray(reader1 -> SubResource.fromJson(reader1))); + } else if ("subResourceResource".equals(fieldName)) { + subResource.withSubResourceResource( + reader.readObject(reader1 -> SubResourceResource.fromJson(reader1))); + } else if ("subResourceResourceList".equals(fieldName)) { + subResource.withSubResourceResourceList( + reader.readArray(reader1 -> SubResourceResource.fromJson(reader1))); + } else { + reader.skipChildren(); + } + } + + return subResource; + }); + } + } + @Test public void testSerialization() throws IOException { String cosmosAccountJson @@ -190,6 +291,33 @@ public void testSerialization() throws IOException { Assertions.assertEquals("Microsoft.KeyVault/vaults", vaultResource.type()); Assertions.assertEquals(0, vaultResource.tags().size()); Assertions.assertNull(vaultResource.systemData()); + + // test SubResource + SubResourceResource subResourceResourceRoot = new SubResourceResource(); + SubResource subResource = new SubResource().withId(UUID.randomUUID().toString()); + SubResourceResource subResourceResourceNest = new SubResourceResource().withId(UUID.randomUUID().toString()); + subResourceResourceRoot.withSubResource(subResource) + .withSubResourceList(Collections.singletonList(subResource)) + .withSubResourceResource(subResourceResourceNest) + .withSubResourceResourceList(Collections.singletonList(subResourceResourceNest)); + + String json = serializeToString(subResourceResourceRoot); + SubResourceResource subResourceResourceRootDeserialized = deserialize(json, SubResourceResource::fromJson); + Assertions.assertEquals(subResource.id(), subResourceResourceRootDeserialized.subResource().id()); + Assertions.assertEquals(subResource.id(), + subResourceResourceRootDeserialized.subResourceList().iterator().next().id()); + Assertions.assertEquals(subResourceResourceNest.id(), + subResourceResourceRootDeserialized.subResourceResource().id()); + Assertions.assertEquals(subResourceResourceNest.id(), + subResourceResourceRootDeserialized.subResourceResourceList().iterator().next().id()); + } + + private static > String serializeToString(T serializable) throws IOException { + StringWriter writer = new StringWriter(); + JsonWriter jsonWriter = JsonProviders.createWriter(writer); + serializable.toJson(jsonWriter); + jsonWriter.flush(); + return writer.toString(); } private static T deserialize(String json, ReadValueCallback reader) throws IOException { diff --git a/sdk/core/azure-core-serializer-json-jackson/src/main/java/com/azure/core/serializer/json/jackson/implementation/ObjectMapperShim.java b/sdk/core/azure-core-serializer-json-jackson/src/main/java/com/azure/core/serializer/json/jackson/implementation/ObjectMapperShim.java index 0ba4f95ca0a7..7b772355ec1c 100644 --- a/sdk/core/azure-core-serializer-json-jackson/src/main/java/com/azure/core/serializer/json/jackson/implementation/ObjectMapperShim.java +++ b/sdk/core/azure-core-serializer-json-jackson/src/main/java/com/azure/core/serializer/json/jackson/implementation/ObjectMapperShim.java @@ -6,10 +6,12 @@ import com.azure.core.annotation.HeaderCollection; import com.azure.core.http.HttpHeader; import com.azure.core.http.HttpHeaders; -import com.azure.core.implementation.ReflectiveInvoker; +import com.azure.core.implementation.ReflectionSerializable; import com.azure.core.implementation.ReflectionUtils; +import com.azure.core.implementation.ReflectiveInvoker; import com.azure.core.implementation.TypeUtil; import com.azure.core.util.logging.ClientLogger; +import com.azure.json.JsonSerializable; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -264,6 +266,7 @@ public JsonNode readTree(byte[] content) throws IOException { } } + @SuppressWarnings("unchecked") private JavaType createJavaType(Type type) { if (type == null) { return null; @@ -280,7 +283,28 @@ private JavaType createJavaType(Type type) { return getFromTypeCache(type, t -> mapper.getTypeFactory() .constructParametricType((Class) parameterizedType.getRawType(), javaTypeArguments)); } else { - return getFromTypeCache(type, t -> mapper.getTypeFactory().constructType(t)); + return getFromTypeCache(type, t -> { + JavaType javaType = mapper.constructType(t); + + // Need additional handling here so that the JavaType returned has the correct value handler for + // JsonSerializable types. + // While JsonSerializableDeserializer is registered with the ObjectMapper, and it mutates the + // JsonSerializer used by Jackson to handle as a JsonSerializable type, there have been cases where + // collection types (List, Map, etc) have not been handled correctly. So, additional handling is done + // here to ensure that the JavaType returned has the correct value handler. + + if (!(t instanceof Class)) { + // Not a Class, so can't be a JsonSerializable type. + return javaType; + } + + if (ReflectionSerializable.supportsJsonSerializable((Class) t)) { + // JsonSerializable type, so add the JsonSerializableDeserializer as the value handler. + return javaType.withValueHandler(new JsonSerializableDeserializer((Class>) t)); + } + + return javaType; + }); } } diff --git a/sdk/core/azure-core-test/src/main/java/com/azure/core/test/http/HttpClientTests.java b/sdk/core/azure-core-test/src/main/java/com/azure/core/test/http/HttpClientTests.java index cd1a10576a7d..ae9d33241b2e 100644 --- a/sdk/core/azure-core-test/src/main/java/com/azure/core/test/http/HttpClientTests.java +++ b/sdk/core/azure-core-test/src/main/java/com/azure/core/test/http/HttpClientTests.java @@ -584,7 +584,7 @@ private static void canSendBinaryDataSync(URL requestUrl, BinaryData requestBody HttpRequest request = new HttpRequest(HttpMethod.PUT, requestUrl, new HttpHeaders(), requestBody); try (HttpResponse httpResponse = httpClient.sendSync(request, Context.NONE)) { - byte[] responseBytes = httpResponse.getBodyAsByteArray().block(); + byte[] responseBytes = httpResponse.getBodyAsBinaryData().toBytes(); assertArraysEqual(expectedResponseBody, responseBytes); } } @@ -615,7 +615,7 @@ private static void canSendBinaryDataSyncWithProgressReporter(URL requestUrl, Bi .getContext(); try (HttpResponse httpResponse = httpClient.sendSync(request, context)) { - byte[] responseBytes = httpResponse.getBodyAsByteArray().block(); + byte[] responseBytes = httpResponse.getBodyAsBinaryData().toBytes(); assertArraysEqual(expectedResponseBody, responseBytes); assertEquals(expectedResponseBody.length, progress.intValue()); } diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/implementation/http/rest/RestProxyBase.java b/sdk/core/azure-core/src/main/java/com/azure/core/implementation/http/rest/RestProxyBase.java index 67f4ea40662e..a33abec128a8 100644 --- a/sdk/core/azure-core/src/main/java/com/azure/core/implementation/http/rest/RestProxyBase.java +++ b/sdk/core/azure-core/src/main/java/com/azure/core/implementation/http/rest/RestProxyBase.java @@ -27,6 +27,7 @@ import com.azure.core.implementation.http.UnexpectedExceptionInformation; import com.azure.core.implementation.serializer.HttpResponseDecoder; import com.azure.core.implementation.serializer.MalformedValueException; +import com.azure.core.implementation.util.HttpUtils; import com.azure.core.util.BinaryData; import com.azure.core.util.Context; import com.azure.core.util.UrlBuilder; @@ -109,15 +110,15 @@ public final Object invoke(Object proxy, Method method, RequestOptions options, // For the following Context options only set a value if it's true. This is to avoid adding a key to the // context with a value of false, which will increase all subsequent lookups of the context. if (methodParser.isResponseEagerlyRead()) { - context = context.addData("azure-eagerly-read-response", true); + context = context.addData(HttpUtils.AZURE_EAGERLY_READ_RESPONSE, true); } if (methodParser.isResponseBodyIgnored()) { - context = context.addData("azure-ignore-response-body", true); + context = context.addData(HttpUtils.AZURE_IGNORE_RESPONSE_BODY, true); } if (methodParser.isHeadersEagerlyConverted()) { - context = context.addData("azure-eagerly-convert-headers", true); + context = context.addData(HttpUtils.AZURE_EAGERLY_CONVERT_HEADERS, true); } return invoke(proxy, method, options, errorOptions, requestCallback, methodParser, request, context); diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/implementation/jackson/ObjectMapperShim.java b/sdk/core/azure-core/src/main/java/com/azure/core/implementation/jackson/ObjectMapperShim.java index b6a7af7a6372..4a2c2ac214cb 100644 --- a/sdk/core/azure-core/src/main/java/com/azure/core/implementation/jackson/ObjectMapperShim.java +++ b/sdk/core/azure-core/src/main/java/com/azure/core/implementation/jackson/ObjectMapperShim.java @@ -6,12 +6,14 @@ import com.azure.core.annotation.HeaderCollection; import com.azure.core.http.HttpHeader; import com.azure.core.http.HttpHeaders; +import com.azure.core.implementation.ReflectionSerializable; import com.azure.core.implementation.ReflectionUtils; import com.azure.core.implementation.ReflectiveInvoker; import com.azure.core.implementation.TypeUtil; import com.azure.core.util.logging.ClientLogger; import com.azure.core.util.logging.LogLevel; import com.azure.core.util.serializer.MemberNameConverter; +import com.azure.json.JsonSerializable; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -294,6 +296,7 @@ public JsonNode readTree(byte[] content) throws IOException { } } + @SuppressWarnings("unchecked") private JavaType createJavaType(Type type) { if (type == null) { return null; @@ -310,7 +313,28 @@ private JavaType createJavaType(Type type) { return getFromTypeCache(type, t -> mapper.getTypeFactory() .constructParametricType((Class) parameterizedType.getRawType(), javaTypeArguments)); } else { - return getFromTypeCache(type, t -> mapper.getTypeFactory().constructType(t)); + return getFromTypeCache(type, t -> { + JavaType javaType = mapper.constructType(t); + + // Need additional handling here so that the JavaType returned has the correct value handler for + // JsonSerializable types. + // While JsonSerializableDeserializer is registered with the ObjectMapper, and it mutates the + // JsonSerializer used by Jackson to handle as a JsonSerializable type, there have been cases where + // collection types (List, Map, etc) have not been handled correctly. So, additional handling is done + // here to ensure that the JavaType returned has the correct value handler. + + if (!(t instanceof Class)) { + // Not a Class, so can't be a JsonSerializable type. + return javaType; + } + + if (ReflectionSerializable.supportsJsonSerializable((Class) t)) { + // JsonSerializable type, so add the JsonSerializableDeserializer as the value handler. + return javaType.withValueHandler(new JsonSerializableDeserializer((Class>) t)); + } + + return javaType; + }); } } diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/implementation/util/HttpUtils.java b/sdk/core/azure-core/src/main/java/com/azure/core/implementation/util/HttpUtils.java new file mode 100644 index 000000000000..0fd02b8f9f3a --- /dev/null +++ b/sdk/core/azure-core/src/main/java/com/azure/core/implementation/util/HttpUtils.java @@ -0,0 +1,130 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.core.implementation.util; + +import com.azure.core.util.Configuration; +import com.azure.core.util.logging.ClientLogger; + +import java.time.Duration; + +import static com.azure.core.util.Configuration.PROPERTY_AZURE_REQUEST_CONNECT_TIMEOUT; +import static com.azure.core.util.Configuration.PROPERTY_AZURE_REQUEST_READ_TIMEOUT; +import static com.azure.core.util.Configuration.PROPERTY_AZURE_REQUEST_RESPONSE_TIMEOUT; +import static com.azure.core.util.Configuration.PROPERTY_AZURE_REQUEST_WRITE_TIMEOUT; +import static com.azure.core.util.CoreUtils.getDefaultTimeoutFromEnvironment; + +/** + * Utilities shared with HttpClient implementations. + */ +public final class HttpUtils { + private static final ClientLogger LOGGER = new ClientLogger(HttpUtils.class); + + private static final Duration MINIMUM_TIMEOUT = Duration.ofMillis(1); + private static final Duration DEFAULT_CONNECT_TIMEOUT; + private static final Duration DEFAULT_WRITE_TIMEOUT; + private static final Duration DEFAULT_RESPONSE_TIMEOUT; + private static final Duration DEFAULT_READ_TIMEOUT; + + static { + Configuration configuration = Configuration.getGlobalConfiguration(); + DEFAULT_CONNECT_TIMEOUT = getDefaultTimeoutFromEnvironment(configuration, + PROPERTY_AZURE_REQUEST_CONNECT_TIMEOUT, Duration.ofSeconds(10), LOGGER); + DEFAULT_WRITE_TIMEOUT = getDefaultTimeoutFromEnvironment(configuration, PROPERTY_AZURE_REQUEST_WRITE_TIMEOUT, + Duration.ofSeconds(60), LOGGER); + DEFAULT_RESPONSE_TIMEOUT = getDefaultTimeoutFromEnvironment(configuration, + PROPERTY_AZURE_REQUEST_RESPONSE_TIMEOUT, Duration.ofSeconds(60), LOGGER); + DEFAULT_READ_TIMEOUT = getDefaultTimeoutFromEnvironment(configuration, PROPERTY_AZURE_REQUEST_READ_TIMEOUT, + Duration.ofSeconds(60), LOGGER); + } + + /** + * Context key used to indicate to an HttpClient implementation if it should eagerly read the response from the + * network. + */ + public static final String AZURE_EAGERLY_READ_RESPONSE = "azure-eagerly-read-response"; + + /** + * Context key used to indicate to an HttpClient implementation if the response body should be ignored and eagerly + * drained from the network. + */ + public static final String AZURE_IGNORE_RESPONSE_BODY = "azure-ignore-response-body"; + + /** + * Context key used to indicate to an HttpClient a per-call response timeout. + */ + public static final String AZURE_RESPONSE_TIMEOUT = "azure-response-timeout"; + + /** + * Context key used to indicate to an HttpClient if the implementation specific HTTP headers should be converted to + * Azure Core HttpHeaders. + */ + public static final String AZURE_EAGERLY_CONVERT_HEADERS = "azure-eagerly-convert-headers"; + + /** + * Gets the default connect timeout. + * + * @return The default connect timeout. + */ + public static Duration getDefaultConnectTimeout() { + return DEFAULT_CONNECT_TIMEOUT; + } + + /** + * Gets the default write timeout. + * + * @return The default write timeout. + */ + public static Duration getDefaultWriteTimeout() { + return DEFAULT_WRITE_TIMEOUT; + } + + /** + * Gets the default response timeout. + * + * @return The default response timeout. + */ + public static Duration getDefaultResponseTimeout() { + return DEFAULT_RESPONSE_TIMEOUT; + } + + /** + * Gets the default read timeout. + * + * @return The default read timeout. + */ + public static Duration getDefaultReadTimeout() { + return DEFAULT_READ_TIMEOUT; + } + + /** + * Returns the timeout Duration to use based on the configured timeout and the default timeout. + *

+ * If the configured timeout is null the default timeout will be used. If the timeout is less than or equal to zero + * no timeout will be used. If the timeout is less than one millisecond a timeout of one millisecond will be used. + * + * @param configuredTimeout The configured timeout. + * @param defaultTimeout The default timeout. + * @return The timeout to use. + */ + public static Duration getTimeout(Duration configuredTimeout, Duration defaultTimeout) { + // Timeout is null, use the default timeout. + if (configuredTimeout == null) { + return defaultTimeout; + } + + // Timeout is less than or equal to zero, return no timeout. + if (configuredTimeout.isZero() || configuredTimeout.isNegative()) { + return Duration.ZERO; + } + + // Return the maximum of the timeout period and the minimum allowed timeout period. + if (configuredTimeout.compareTo(MINIMUM_TIMEOUT) < 0) { + return MINIMUM_TIMEOUT; + } else { + return configuredTimeout; + } + } + + private HttpUtils() { + } +} diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/util/HttpClientOptions.java b/sdk/core/azure-core/src/main/java/com/azure/core/util/HttpClientOptions.java index 43808efe0eea..6d9a4e1bb2b6 100644 --- a/sdk/core/azure-core/src/main/java/com/azure/core/util/HttpClientOptions.java +++ b/sdk/core/azure-core/src/main/java/com/azure/core/util/HttpClientOptions.java @@ -11,11 +11,11 @@ import java.time.Duration; -import static com.azure.core.util.Configuration.PROPERTY_AZURE_REQUEST_CONNECT_TIMEOUT; -import static com.azure.core.util.Configuration.PROPERTY_AZURE_REQUEST_READ_TIMEOUT; -import static com.azure.core.util.Configuration.PROPERTY_AZURE_REQUEST_RESPONSE_TIMEOUT; -import static com.azure.core.util.Configuration.PROPERTY_AZURE_REQUEST_WRITE_TIMEOUT; -import static com.azure.core.util.CoreUtils.getDefaultTimeoutFromEnvironment; +import static com.azure.core.implementation.util.HttpUtils.getDefaultConnectTimeout; +import static com.azure.core.implementation.util.HttpUtils.getDefaultReadTimeout; +import static com.azure.core.implementation.util.HttpUtils.getDefaultResponseTimeout; +import static com.azure.core.implementation.util.HttpUtils.getDefaultWriteTimeout; +import static com.azure.core.implementation.util.HttpUtils.getTimeout; /** * General configuration options for {@link HttpClient HttpClients}. @@ -24,29 +24,10 @@ */ @Fluent public final class HttpClientOptions extends ClientOptions { - private static final Duration MINIMUM_TIMEOUT = Duration.ofMillis(1); - private static final Duration DEFAULT_CONNECT_TIMEOUT; - private static final Duration DEFAULT_WRITE_TIMEOUT; - private static final Duration DEFAULT_RESPONSE_TIMEOUT; - private static final Duration DEFAULT_READ_TIMEOUT; private static final Duration DEFAULT_CONNECTION_IDLE_TIMEOUT = Duration.ofSeconds(60); - private static final Duration NO_TIMEOUT = Duration.ZERO; private static final ClientLogger LOGGER = new ClientLogger(HttpClientOptions.class); - static { - Configuration configuration = Configuration.getGlobalConfiguration(); - - DEFAULT_CONNECT_TIMEOUT = getDefaultTimeoutFromEnvironment(configuration, - PROPERTY_AZURE_REQUEST_CONNECT_TIMEOUT, Duration.ofSeconds(10), LOGGER); - DEFAULT_WRITE_TIMEOUT = getDefaultTimeoutFromEnvironment(configuration, PROPERTY_AZURE_REQUEST_WRITE_TIMEOUT, - Duration.ofSeconds(60), LOGGER); - DEFAULT_RESPONSE_TIMEOUT = getDefaultTimeoutFromEnvironment(configuration, - PROPERTY_AZURE_REQUEST_RESPONSE_TIMEOUT, Duration.ofSeconds(60), LOGGER); - DEFAULT_READ_TIMEOUT = getDefaultTimeoutFromEnvironment(configuration, PROPERTY_AZURE_REQUEST_READ_TIMEOUT, - Duration.ofSeconds(60), LOGGER); - } - private ProxyOptions proxyOptions; private Configuration configuration; private Duration connectTimeout; @@ -141,12 +122,20 @@ public HttpClientOptions setConnectTimeout(Duration connectTimeout) { /** * Gets the connection timeout for a request to be sent. *

+ * The connection timeout begins once the request attempts to connect to the remote host and finishes when the + * connection is resolved. + *

+ * If {@code connectTimeout} is null either {@link Configuration#PROPERTY_AZURE_REQUEST_CONNECT_TIMEOUT} or a + * 10-second timeout will be used, if it is a {@link Duration} less than or equal to zero then no timeout will be + * applied. When applying the timeout the greatest of one millisecond and the value of {@code connectTimeout} will + * be used. + *

* The default connection timeout is 10 seconds. * * @return The connection timeout of a request to be sent. */ public Duration getConnectTimeout() { - return getTimeout(connectTimeout, DEFAULT_CONNECT_TIMEOUT); + return getTimeout(connectTimeout, getDefaultConnectTimeout()); } /** @@ -174,12 +163,21 @@ public HttpClientOptions setWriteTimeout(Duration writeTimeout) { /** * Gets the writing timeout for a request to be sent. *

+ * The writing timeout does not apply to the entire request but to each emission being sent over the wire. For + * example a request body which emits {@code 10} {@code 8KB} buffers will trigger {@code 10} write operations, the + * outbound buffer will be periodically checked to determine if it is still draining. + *

+ * If {@code writeTimeout} is null either {@link Configuration#PROPERTY_AZURE_REQUEST_WRITE_TIMEOUT} or a 60-second + * timeout will be used, if it is a {@link Duration} less than or equal to zero then no write timeout will be + * applied. When applying the timeout the greatest of one millisecond and the value of {@code writeTimeout} will be + * used. + *

* The default writing timeout is 60 seconds. * * @return The writing timeout of a request to be sent. */ public Duration getWriteTimeout() { - return getTimeout(writeTimeout, DEFAULT_WRITE_TIMEOUT); + return getTimeout(writeTimeout, getDefaultWriteTimeout()); } /** @@ -227,12 +225,20 @@ public HttpClientOptions setResponseTimeout(Duration responseTimeout) { /** * Gets the response timeout duration used when waiting for a server to reply. *

+ * The response timeout begins once the request write completes and finishes once the first response read is + * triggered when the server response is received. + *

+ * If {@code responseTimeout} is null either {@link Configuration#PROPERTY_AZURE_REQUEST_RESPONSE_TIMEOUT} or a + * 60-second timeout will be used, if it is a {@link Duration} less than or equal to zero then no timeout will be + * applied to the response. When applying the timeout the greatest of one millisecond and the value of + * {@code responseTimeout} will be used. + *

* The default response timeout is 60 seconds. * * @return The response timeout duration. */ public Duration getResponseTimeout() { - return getTimeout(responseTimeout, DEFAULT_RESPONSE_TIMEOUT); + return getTimeout(responseTimeout, getDefaultResponseTimeout()); } /** @@ -287,7 +293,7 @@ public HttpClientOptions setReadTimeout(Duration readTimeout) { * @return The read timeout duration. */ public Duration getReadTimeout() { - return getTimeout(readTimeout, DEFAULT_READ_TIMEOUT); + return getTimeout(readTimeout, getDefaultReadTimeout()); } /** @@ -398,19 +404,4 @@ public HttpClientOptions setHttpClientProvider(Class getHttpClientProvider() { return httpClientProvider; } - - private static Duration getTimeout(Duration configuredTimeout, Duration defaultTimeout) { - // Timeout is null, use the default timeout. - if (configuredTimeout == null) { - return defaultTimeout; - } - - // Timeout is less than or equal to zero, return no timeout. - if (configuredTimeout.isZero() || configuredTimeout.isNegative()) { - return NO_TIMEOUT; - } - - // Return the maximum of the timeout period and the minimum allowed timeout period. - return configuredTimeout.compareTo(MINIMUM_TIMEOUT) > 0 ? configuredTimeout : MINIMUM_TIMEOUT; - } } diff --git a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/VectorIndexTest.java b/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/VectorIndexTest.java deleted file mode 100644 index 74f13be9d4f4..000000000000 --- a/sdk/cosmos/azure-cosmos-tests/src/test/java/com/azure/cosmos/rx/VectorIndexTest.java +++ /dev/null @@ -1,345 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.cosmos.rx; - -import com.azure.cosmos.ConsistencyLevel; -import com.azure.cosmos.CosmosAsyncClient; -import com.azure.cosmos.CosmosAsyncContainer; -import com.azure.cosmos.CosmosAsyncDatabase; -import com.azure.cosmos.CosmosClientBuilder; -import com.azure.cosmos.CosmosDatabaseForTest; -import com.azure.cosmos.CosmosException; -import com.azure.cosmos.DirectConnectionConfig; -import com.azure.cosmos.implementation.TestConfigurations; -import com.azure.cosmos.implementation.Utils; -import com.azure.cosmos.implementation.guava25.collect.ImmutableList; -import com.azure.cosmos.models.CosmosContainerProperties; -import com.azure.cosmos.models.CosmosVectorDataType; -import com.azure.cosmos.models.CosmosVectorDistanceFunction; -import com.azure.cosmos.models.CosmosVectorEmbedding; -import com.azure.cosmos.models.CosmosVectorEmbeddingPolicy; -import com.azure.cosmos.models.ExcludedPath; -import com.azure.cosmos.models.IncludedPath; -import com.azure.cosmos.models.IndexingMode; -import com.azure.cosmos.models.IndexingPolicy; -import com.azure.cosmos.models.PartitionKeyDefinition; -import com.azure.cosmos.models.CosmosVectorIndexSpec; -import com.azure.cosmos.models.CosmosVectorIndexType; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Ignore; -import org.testng.annotations.Test; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.UUID; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; - -@Ignore("TODO: Ignore these test cases until the public emulator with vector indexes is released.") -public class VectorIndexTest extends TestSuiteBase { - protected static final int TIMEOUT = 30000; - protected static final int SETUP_TIMEOUT = 20000; - protected static final int SHUTDOWN_TIMEOUT = 20000; - - protected static Logger logger = LoggerFactory.getLogger(VectorIndexTest.class.getSimpleName()); - private final ObjectMapper simpleObjectMapper = Utils.getSimpleObjectMapper(); - private final String databaseId = CosmosDatabaseForTest.generateId(); - private CosmosAsyncClient client; - private CosmosAsyncDatabase database; - - @BeforeClass(groups = {"emulator"}, timeOut = SETUP_TIMEOUT) - public void before_VectorIndexTest() { - // set up the client - client = new CosmosClientBuilder() - .endpoint(TestConfigurations.HOST) - .key(TestConfigurations.MASTER_KEY) - .directMode(DirectConnectionConfig.getDefaultConfig()) - .consistencyLevel(ConsistencyLevel.SESSION) - .contentResponseOnWriteEnabled(true) - .buildAsyncClient(); - - database = createDatabase(client, databaseId); - } - - @AfterClass(groups = {"emulator"}, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) - public void afterClass() { - safeDeleteDatabase(database); - safeClose(client); - } - - @Test(groups = {"emulator"}, timeOut = TIMEOUT*10000) - public void shouldCreateVectorEmbeddingPolicy() { - PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); - ArrayList paths = new ArrayList(); - paths.add("/mypk"); - partitionKeyDef.setPaths(paths); - - CosmosContainerProperties collectionDefinition = new CosmosContainerProperties(UUID.randomUUID().toString(), partitionKeyDef); - - IndexingPolicy indexingPolicy = new IndexingPolicy(); - indexingPolicy.setIndexingMode(IndexingMode.CONSISTENT); - ExcludedPath excludedPath = new ExcludedPath("/*"); - indexingPolicy.setExcludedPaths(Collections.singletonList(excludedPath)); - - IncludedPath includedPath1 = new IncludedPath("/name/?"); - IncludedPath includedPath2 = new IncludedPath("/description/?"); - indexingPolicy.setIncludedPaths(ImmutableList.of(includedPath1, includedPath2)); - - indexingPolicy.setVectorIndexes(populateVectorIndexes()); - - CosmosVectorEmbeddingPolicy cosmosVectorEmbeddingPolicy = new CosmosVectorEmbeddingPolicy(); - cosmosVectorEmbeddingPolicy.setCosmosVectorEmbeddings(populateEmbeddings()); - - collectionDefinition.setIndexingPolicy(indexingPolicy); - collectionDefinition.setVectorEmbeddingPolicy(cosmosVectorEmbeddingPolicy); - - database.createContainer(collectionDefinition).block(); - CosmosAsyncContainer createdCollection = database.getContainer(collectionDefinition.getId()); - CosmosContainerProperties collectionProperties = createdCollection.read().block().getProperties(); - validateCollectionProperties(collectionDefinition, collectionProperties); - } - - @Test(groups = {"emulator"}, timeOut = TIMEOUT) - public void shouldFailOnEmptyVectorEmbeddingPolicy() { - PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); - ArrayList paths = new ArrayList(); - paths.add("/mypk"); - partitionKeyDef.setPaths(paths); - - CosmosContainerProperties collectionDefinition = new CosmosContainerProperties(UUID.randomUUID().toString(), partitionKeyDef); - - IndexingPolicy indexingPolicy = new IndexingPolicy(); - indexingPolicy.setIndexingMode(IndexingMode.CONSISTENT); - ExcludedPath excludedPath = new ExcludedPath("/*"); - indexingPolicy.setExcludedPaths(Collections.singletonList(excludedPath)); - - IncludedPath includedPath1 = new IncludedPath("/name/?"); - IncludedPath includedPath2 = new IncludedPath("/description/?"); - indexingPolicy.setIncludedPaths(ImmutableList.of(includedPath1, includedPath2)); - - CosmosVectorIndexSpec cosmosVectorIndexSpec = new CosmosVectorIndexSpec(); - cosmosVectorIndexSpec.setPath("/vector1"); - cosmosVectorIndexSpec.setType(CosmosVectorIndexType.FLAT.toString()); - indexingPolicy.setVectorIndexes(ImmutableList.of(cosmosVectorIndexSpec)); - - collectionDefinition.setIndexingPolicy(indexingPolicy); - - try { - database.createContainer(collectionDefinition).block(); - fail("Container creation will fail as no vector embedding policy is being passed"); - } catch (CosmosException ex) { - assertThat(ex.getStatusCode()).isEqualTo(400); - assertThat(ex.getMessage()).contains("vector1 not matching in Embedding's path"); - } - } - - @Test(groups = {"emulator"}, timeOut = TIMEOUT) - public void shouldFailOnWrongVectorIndex() { - PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); - ArrayList paths = new ArrayList(); - paths.add("/mypk"); - partitionKeyDef.setPaths(paths); - - CosmosContainerProperties collectionDefinition = new CosmosContainerProperties(UUID.randomUUID().toString(), partitionKeyDef); - - IndexingPolicy indexingPolicy = new IndexingPolicy(); - indexingPolicy.setIndexingMode(IndexingMode.CONSISTENT); - ExcludedPath excludedPath = new ExcludedPath("/*"); - indexingPolicy.setExcludedPaths(Collections.singletonList(excludedPath)); - - IncludedPath includedPath1 = new IncludedPath("/name/?"); - IncludedPath includedPath2 = new IncludedPath("/description/?"); - indexingPolicy.setIncludedPaths(ImmutableList.of(includedPath1, includedPath2)); - - CosmosVectorIndexSpec cosmosVectorIndexSpec = new CosmosVectorIndexSpec(); - cosmosVectorIndexSpec.setPath("/vector1"); - cosmosVectorIndexSpec.setType("NonFlat"); - indexingPolicy.setVectorIndexes(ImmutableList.of(cosmosVectorIndexSpec)); - collectionDefinition.setIndexingPolicy(indexingPolicy); - - CosmosVectorEmbedding embedding = new CosmosVectorEmbedding(); - embedding.setPath("/vector1"); - embedding.setDataType(CosmosVectorDataType.FLOAT32); - embedding.setDimensions(3L); - embedding.setDistanceFunction(CosmosVectorDistanceFunction.COSINE); - CosmosVectorEmbeddingPolicy cosmosVectorEmbeddingPolicy = new CosmosVectorEmbeddingPolicy(); - cosmosVectorEmbeddingPolicy.setCosmosVectorEmbeddings(ImmutableList.of(embedding)); - collectionDefinition.setVectorEmbeddingPolicy(cosmosVectorEmbeddingPolicy); - - try { - database.createContainer(collectionDefinition).block(); - fail("Container creation will fail as wrong vector index type is being passed"); - } catch (CosmosException ex) { - assertThat(ex.getStatusCode()).isEqualTo(400); - assertThat(ex.getMessage()).contains("NonFlat is invalid, Valid types are 'flat' or 'quantizedFlat'"); - } - } - - @Test(groups = {"emulator"}, timeOut = TIMEOUT) - public void shouldCreateVectorIndexSimilarPathDifferentVectorType() { - PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); - ArrayList paths = new ArrayList(); - paths.add("/mypk"); - partitionKeyDef.setPaths(paths); - - CosmosContainerProperties collectionDefinition = new CosmosContainerProperties(UUID.randomUUID().toString(), partitionKeyDef); - - IndexingPolicy indexingPolicy = new IndexingPolicy(); - indexingPolicy.setIndexingMode(IndexingMode.CONSISTENT); - ExcludedPath excludedPath = new ExcludedPath("/*"); - indexingPolicy.setExcludedPaths(Collections.singletonList(excludedPath)); - - IncludedPath includedPath1 = new IncludedPath("/name/?"); - IncludedPath includedPath2 = new IncludedPath("/description/?"); - indexingPolicy.setIncludedPaths(ImmutableList.of(includedPath1, includedPath2)); - - List vectorIndexes = populateVectorIndexes(); - vectorIndexes.get(2).setPath("/vector2"); - indexingPolicy.setVectorIndexes(vectorIndexes); - - List embeddings = populateEmbeddings(); - embeddings.get(2).setPath("/vector2"); - CosmosVectorEmbeddingPolicy cosmosVectorEmbeddingPolicy = new CosmosVectorEmbeddingPolicy(); - cosmosVectorEmbeddingPolicy.setCosmosVectorEmbeddings(embeddings); - - collectionDefinition.setIndexingPolicy(indexingPolicy); - collectionDefinition.setVectorEmbeddingPolicy(cosmosVectorEmbeddingPolicy); - - database.createContainer(collectionDefinition).block(); - CosmosAsyncContainer createdCollection = database.getContainer(collectionDefinition.getId()); - CosmosContainerProperties collectionProperties = createdCollection.read().block().getProperties(); - validateCollectionProperties(collectionDefinition, collectionProperties); - } - - @Test(groups = {"unit"}, timeOut = TIMEOUT) - public void shouldFailOnWrongVectorEmbeddingPolicy() { - CosmosVectorEmbedding embedding = new CosmosVectorEmbedding(); - try { - - embedding.setDataType(null); - fail("Embedding creation failed because cosmosVectorDataType argument is empty"); - } catch (NullPointerException ex) { - assertThat(ex.getMessage()).isEqualTo("cosmosVectorDataType cannot be empty"); - } - - try { - embedding.setDistanceFunction(null); - fail("Embedding creation failed because cosmosVectorDistanceFunction argument is empty"); - } catch (NullPointerException ex) { - assertThat(ex.getMessage()).isEqualTo("cosmosVectorDistanceFunction cannot be empty"); - } - - try { - embedding.setDimensions(null); - fail("Embedding creation failed because dimensions argument is empty"); - } catch (NullPointerException ex) { - assertThat(ex.getMessage()).isEqualTo("dimensions cannot be empty"); - } - - try { - embedding.setDimensions(-1L); - fail("Vector Embedding policy creation will fail for negative dimensions being passed"); - } catch (IllegalArgumentException ex) { - assertThat(ex.getMessage()).isEqualTo("Dimensions for the embedding has to be a long value greater than 1 for the vector embedding policy"); - } - } - - @Test(groups = {"unit"}, timeOut = TIMEOUT) - public void shouldValidateVectorEmbeddingPolicySerializationAndDeserialization() throws JsonProcessingException { - IndexingPolicy indexingPolicy = new IndexingPolicy(); - indexingPolicy.setVectorIndexes(populateVectorIndexes()); - - CosmosVectorEmbeddingPolicy cosmosVectorEmbeddingPolicy = new CosmosVectorEmbeddingPolicy(); - cosmosVectorEmbeddingPolicy.setCosmosVectorEmbeddings(populateEmbeddings()); - String vectorEmbeddingPolicyJson = getVectorEmbeddingPolicyAsString(); - String expectedVectorEmbeddingPolicyJson = simpleObjectMapper.writeValueAsString(cosmosVectorEmbeddingPolicy); - assertThat(vectorEmbeddingPolicyJson).isEqualTo(expectedVectorEmbeddingPolicyJson); - - CosmosVectorEmbeddingPolicy expectedCosmosVectorEmbeddingPolicy = simpleObjectMapper.readValue(expectedVectorEmbeddingPolicyJson, CosmosVectorEmbeddingPolicy.class); - validateVectorEmbeddingPolicy(cosmosVectorEmbeddingPolicy, expectedCosmosVectorEmbeddingPolicy); - } - - private void validateCollectionProperties(CosmosContainerProperties collectionDefinition, CosmosContainerProperties collectionProperties) { - assertThat(collectionProperties.getVectorEmbeddingPolicy()).isNotNull(); - assertThat(collectionProperties.getVectorEmbeddingPolicy().getVectorEmbeddings()).isNotNull(); - validateVectorEmbeddingPolicy(collectionProperties.getVectorEmbeddingPolicy(), - collectionDefinition.getVectorEmbeddingPolicy()); - - assertThat(collectionProperties.getIndexingPolicy().getVectorIndexes()).isNotNull(); - validateVectorIndexes(collectionDefinition.getIndexingPolicy().getVectorIndexes(), collectionProperties.getIndexingPolicy().getVectorIndexes()); - } - - private void validateVectorEmbeddingPolicy(CosmosVectorEmbeddingPolicy actual, CosmosVectorEmbeddingPolicy expected) { - List actualEmbeddings = actual.getVectorEmbeddings(); - List expectedEmbeddings = expected.getVectorEmbeddings(); - assertThat(expectedEmbeddings).hasSameSizeAs(actualEmbeddings); - for (int i = 0; i < expectedEmbeddings.size(); i++) { - assertThat(expectedEmbeddings.get(i).getPath()).isEqualTo(actualEmbeddings.get(i).getPath()); - assertThat(expectedEmbeddings.get(i).getDataType()).isEqualTo(actualEmbeddings.get(i).getDataType()); - assertThat(expectedEmbeddings.get(i).getDimensions()).isEqualTo(actualEmbeddings.get(i).getDimensions()); - assertThat(expectedEmbeddings.get(i).getDistanceFunction()).isEqualTo(actualEmbeddings.get(i).getDistanceFunction()); - } - } - - private void validateVectorIndexes(List actual, List expected) { - assertThat(expected).hasSameSizeAs(actual); - for (int i = 0; i < expected.size(); i++) { - assertThat(expected.get(i).getPath()).isEqualTo(actual.get(i).getPath()); - assertThat(expected.get(i).getType()).isEqualTo(actual.get(i).getType()); - } - } - - private List populateVectorIndexes() { - CosmosVectorIndexSpec cosmosVectorIndexSpec1 = new CosmosVectorIndexSpec(); - cosmosVectorIndexSpec1.setPath("/vector1"); - cosmosVectorIndexSpec1.setType(CosmosVectorIndexType.FLAT.toString()); - - CosmosVectorIndexSpec cosmosVectorIndexSpec2 = new CosmosVectorIndexSpec(); - cosmosVectorIndexSpec2.setPath("/vector2"); - cosmosVectorIndexSpec2.setType(CosmosVectorIndexType.QUANTIZED_FLAT.toString()); - - CosmosVectorIndexSpec cosmosVectorIndexSpec3 = new CosmosVectorIndexSpec(); - cosmosVectorIndexSpec3.setPath("/vector3"); - cosmosVectorIndexSpec3.setType(CosmosVectorIndexType.DISK_ANN.toString()); - - return Arrays.asList(cosmosVectorIndexSpec1, cosmosVectorIndexSpec2, cosmosVectorIndexSpec3); - } - - private List populateEmbeddings() { - CosmosVectorEmbedding embedding1 = new CosmosVectorEmbedding(); - embedding1.setPath("/vector1"); - embedding1.setDataType(CosmosVectorDataType.INT8); - embedding1.setDimensions(3L); - embedding1.setDistanceFunction(CosmosVectorDistanceFunction.COSINE); - - CosmosVectorEmbedding embedding2 = new CosmosVectorEmbedding(); - embedding2.setPath("/vector2"); - embedding2.setDataType(CosmosVectorDataType.FLOAT32); - embedding2.setDimensions(3L); - embedding2.setDistanceFunction(CosmosVectorDistanceFunction.DOT_PRODUCT); - - CosmosVectorEmbedding embedding3 = new CosmosVectorEmbedding(); - embedding3.setPath("/vector3"); - embedding3.setDataType(CosmosVectorDataType.UINT8); - embedding3.setDimensions(3L); - embedding3.setDistanceFunction(CosmosVectorDistanceFunction.EUCLIDEAN); - return Arrays.asList(embedding1, embedding2, embedding3); - } - - private String getVectorEmbeddingPolicyAsString() { - return "{\"vectorEmbeddings\":[" + - "{\"path\":\"/vector1\",\"dataType\":\"int8\",\"dimensions\":3,\"distanceFunction\":\"cosine\"}," + - "{\"path\":\"/vector2\",\"dataType\":\"float32\",\"dimensions\":3,\"distanceFunction\":\"dotproduct\"}," + - "{\"path\":\"/vector3\",\"dataType\":\"uint8\",\"dimensions\":3,\"distanceFunction\":\"euclidean\"}" + - "]}"; - } -} diff --git a/sdk/cosmos/azure-cosmos/CHANGELOG.md b/sdk/cosmos/azure-cosmos/CHANGELOG.md index 686ee7b6b8e2..01db4f44daa2 100644 --- a/sdk/cosmos/azure-cosmos/CHANGELOG.md +++ b/sdk/cosmos/azure-cosmos/CHANGELOG.md @@ -15,7 +15,6 @@ ### 4.59.0 (2024-04-27) #### Features Added -* Added `cosmosVectorEmbeddingPolicy` in `cosmosContainerProperties` and `vectorIndexes` in `indexPolicy` to support vector search in CosmosDB - See[39379](https://github.com/Azure/azure-sdk-for-java/pull/39379) * Added public APIs `getCustomItemSerializer` and `setCustomItemSerializer` to allow customers to specify custom payload transformations or serialization settings. - See [PR 38997](https://github.com/Azure/azure-sdk-for-java/pull/38997) and [PR 39933](https://github.com/Azure/azure-sdk-for-java/pull/39933) #### Other Changes diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Constants.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Constants.java index f789963783ed..8409d5b7ec23 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Constants.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/Constants.java @@ -120,15 +120,6 @@ public static final class Properties { public static final String SPATIAL_INDEXES = "spatialIndexes"; public static final String TYPES = "types"; - // Vector Embedding Policy - public static final String VECTOR_EMBEDDING_POLICY = "vectorEmbeddingPolicy"; - public static final String VECTOR_INDEXES = "vectorIndexes"; - public static final String VECTOR_EMBEDDINGS = "vectorEmbeddings"; - public static final String VECTOR_INDEX_TYPE = "type"; - public static final String VECTOR_DATA_TYPE = "dataType"; - public static final String VECTOR_DIMENSIONS = "dimensions"; - public static final String DISTANCE_FUNCTION = "distanceFunction"; - // Unique index. public static final String UNIQUE_KEY_POLICY = "uniqueKeyPolicy"; public static final String UNIQUE_KEYS = "uniqueKeys"; diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/CosmosQueryRequestOptionsImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/CosmosQueryRequestOptionsImpl.java index c70ded3a906f..6d7b00068393 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/CosmosQueryRequestOptionsImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/CosmosQueryRequestOptionsImpl.java @@ -204,7 +204,7 @@ public CosmosQueryRequestOptionsImpl setMaxItemCount(Integer maxItemCount) { * @return the max number of items for vector search. */ public Integer getMaxItemSizeForVectorSearch() { - return maxItemSizeForVectorSearch; + return this.maxItemSizeForVectorSearch; } /** diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/DocumentCollection.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/DocumentCollection.java index 1930f2275a61..b3d650157796 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/DocumentCollection.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/DocumentCollection.java @@ -10,7 +10,6 @@ import com.azure.cosmos.models.ClientEncryptionPolicy; import com.azure.cosmos.models.ComputedProperty; import com.azure.cosmos.models.ConflictResolutionPolicy; -import com.azure.cosmos.models.CosmosVectorEmbeddingPolicy; import com.azure.cosmos.models.IndexingPolicy; import com.azure.cosmos.models.ModelBridgeInternal; import com.azure.cosmos.models.PartitionKeyDefinition; @@ -25,8 +24,6 @@ import java.util.Collection; import java.util.Collections; -import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; - /** * Represents a document collection in the Azure Cosmos DB database service. A collection is a named logical container * for documents. @@ -43,7 +40,6 @@ public final class DocumentCollection extends Resource { private UniqueKeyPolicy uniqueKeyPolicy; private PartitionKeyDefinition partitionKeyDefinition; private ClientEncryptionPolicy clientEncryptionPolicyInternal; - private CosmosVectorEmbeddingPolicy cosmosVectorEmbeddingPolicy; /** * Constructor. @@ -414,33 +410,6 @@ public void setClientEncryptionPolicy(ClientEncryptionPolicy value) { this.set(Constants.Properties.CLIENT_ENCRYPTION_POLICY, value, CosmosItemSerializer.DEFAULT_SERIALIZER); } - /** - * Gets the Vector Embedding Policy containing paths for embeddings along with path-specific settings for the item - * used in performing vector search on the items in a collection in the Azure CosmosDB database service. - * - * @return the Vector Embedding Policy. - */ - public CosmosVectorEmbeddingPolicy getVectorEmbeddingPolicy() { - if (this.cosmosVectorEmbeddingPolicy == null) { - if (super.has(Constants.Properties.VECTOR_EMBEDDING_POLICY)) { - this.cosmosVectorEmbeddingPolicy = super.getObject(Constants.Properties.VECTOR_EMBEDDING_POLICY, - CosmosVectorEmbeddingPolicy.class); - } - } - return this.cosmosVectorEmbeddingPolicy; - } - - /** - * Sets the Vector Embedding Policy containing paths for embeddings along with path-specific settings for the item - * used in performing vector search on the items in a collection in the Azure CosmosDB database service. - * - * @param value the Vector Embedding Policy. - */ - public void setVectorEmbeddingPolicy(CosmosVectorEmbeddingPolicy value) { - checkNotNull(value, "cosmosVectorEmbeddingPolicy cannot be null"); - this.set(Constants.Properties.VECTOR_EMBEDDING_POLICY, value, CosmosItemSerializer.DEFAULT_SERIALIZER); - } - public void populatePropertyBag() { super.populatePropertyBag(); if (this.indexingPolicy == null) { diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/NonStreamingOrderByDocumentQueryExecutionContext.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/NonStreamingOrderByDocumentQueryExecutionContext.java index 89a8a3065443..2f3abb36e9d1 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/NonStreamingOrderByDocumentQueryExecutionContext.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/NonStreamingOrderByDocumentQueryExecutionContext.java @@ -29,6 +29,7 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; @@ -125,10 +126,13 @@ private void initialize( // Since the continuation token will always be null, // we don't need to handle any initialization based on continuationToken. // We can directly initialize without any consideration for continuationToken. + Map partitionKeyRangeToContinuationToken = new HashMap<>(); + for (FeedRangeEpkImpl feedRangeEpk : feedRanges) { + partitionKeyRangeToContinuationToken.put(feedRangeEpk, + null); + } super.initialize(collection, - feedRanges.stream().collect(Collectors.toMap( - feedRangeEpk -> feedRangeEpk, - feedRangeEpk -> null)), + partitionKeyRangeToContinuationToken, initialPageSize, new SqlQuerySpec(querySpec.getQueryText().replace(FormatPlaceHolder, True), querySpec.getParameters())); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/NonStreamingOrderByUtils.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/NonStreamingOrderByUtils.java index 1b4191e26413..b4ac33a1dbc2 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/NonStreamingOrderByUtils.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/NonStreamingOrderByUtils.java @@ -74,7 +74,10 @@ private PageToItemTransformer(RequestChargeTracker tracker, Map> apply(Flux.DocumentProducerFeedResponse> source) { - PriorityBlockingQueue> priorityQueue = new PriorityBlockingQueue<>(initialPageSize, consumeComparer); + // the size of the priority queue is set to size+1, because when the pq reaches the max size we add that + // item and then remove the element. If we don't do this, then when adding this element the size of the pq + // will be increased automatically by 50% and then there would be inconsistent results for later pages. + PriorityBlockingQueue> priorityQueue = new PriorityBlockingQueue<>(initialPageSize + 1, consumeComparer); return source.flatMap(documentProducerFeedResponse -> { clientSideRequestStatistics.addAll( diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/PipelinedDocumentQueryExecutionContext.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/PipelinedDocumentQueryExecutionContext.java index a6ea9fc2d5f6..82746ad412b5 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/PipelinedDocumentQueryExecutionContext.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/query/PipelinedDocumentQueryExecutionContext.java @@ -5,6 +5,7 @@ import com.azure.cosmos.CosmosItemSerializer; import com.azure.cosmos.implementation.DiagnosticsClientContext; import com.azure.cosmos.implementation.DocumentCollection; +import com.azure.cosmos.implementation.HttpConstants; import com.azure.cosmos.implementation.ImplementationBridgeHelpers; import com.azure.cosmos.implementation.Document; import com.azure.cosmos.implementation.ObjectNodeMap; @@ -56,7 +57,11 @@ private static BiFunction, Flux * For example if you want to run the query "SELECT * FROM c ORDER BY c.age asc, c.height desc", * then you need to make the order for "/age" "ascending" and the order for "/height" "descending". diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosContainerProperties.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosContainerProperties.java index 0d357da0cc37..4fae5a797a70 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosContainerProperties.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosContainerProperties.java @@ -347,28 +347,6 @@ public CosmosContainerProperties setClientEncryptionPolicy(ClientEncryptionPolic return this; } - /** - * Gets the Vector Embedding Policy containing paths for embeddings along with path-specific settings for the item - * used in performing vector search on the items in a collection in the Azure CosmosDB database service. - * - * @return the Vector Embedding Policy. - */ - public CosmosVectorEmbeddingPolicy getVectorEmbeddingPolicy() { - return this.documentCollection.getVectorEmbeddingPolicy(); - } - - /** - * Sets the Vector Embedding Policy containing paths for embeddings along with path-specific settings for the item - * used in performing vector search on the items in a collection in the Azure CosmosDB database service. - * - * @param value the Vector Embedding Policy. - * @return the CosmosContainerProperties. - */ - public CosmosContainerProperties setVectorEmbeddingPolicy(CosmosVectorEmbeddingPolicy value) { - this.documentCollection.setVectorEmbeddingPolicy(value); - return this; - } - Resource getResource() { return this.documentCollection; } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosQueryRequestOptions.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosQueryRequestOptions.java index 309fb87a8b22..f9d7d4a72531 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosQueryRequestOptions.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosQueryRequestOptions.java @@ -265,6 +265,17 @@ public Integer getMaxItemSizeForVectorSearch() { return this.actualRequestOptions.getMaxItemSizeForVectorSearch(); } + /** + * Sets the maximum item size to fetch during non-streaming order by queries. + * + * @param maxItemSizeForVectorSearch the max number of items for vector search. + * @return the CosmosQueryRequestOptions. + */ + public CosmosQueryRequestOptions setMaxItemSizeForVectorSearch(Integer maxItemSizeForVectorSearch) { + this.actualRequestOptions.setMaxItemSizeForVectorSearch(maxItemSizeForVectorSearch); + return this; + } + /** * Gets the request continuation token. * diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosVectorDataType.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosVectorDataType.java deleted file mode 100644 index 1a0d42af17a4..000000000000 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosVectorDataType.java +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.cosmos.models; - -import com.fasterxml.jackson.annotation.JsonValue; - -import java.util.Arrays; - -/** - * Data types for the embeddings in Cosmos DB database service. - */ -public enum CosmosVectorDataType { - /** - * Represents a int8 data type. - */ - INT8("int8"), - - /** - * Represents a uint8 data type. - */ - UINT8("uint8"), - - /** - * Represents a float16 data type. - */ - FLOAT16("float16"), - - /** - * Represents a float32 data type. - */ - FLOAT32("float32"); - - private final String overWireValue; - - CosmosVectorDataType(String overWireValue) { - this.overWireValue = overWireValue; - } - - @JsonValue - @Override - public String toString() { - return this.overWireValue; - } - - /** - * Method to retrieve the enum constant by its overWireValue. - * @param value the overWire value of the enum constant - * @return the matching CosmosVectorDataType - * @throws IllegalArgumentException if no matching enum constant is found - */ - public static CosmosVectorDataType fromString(String value) { - return Arrays.stream(CosmosVectorDataType.values()) - .filter(vectorDataType -> vectorDataType.toString().equalsIgnoreCase(value)) - .findFirst() - .orElseThrow(() -> new IllegalArgumentException("Invalid vector data type for the vector embedding policy.")); - } -} diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosVectorDistanceFunction.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosVectorDistanceFunction.java deleted file mode 100644 index 60efd432ad7f..000000000000 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosVectorDistanceFunction.java +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.cosmos.models; - -import com.fasterxml.jackson.annotation.JsonValue; - -import java.util.Arrays; - -/** - * Distance Function for the embeddings in the Cosmos DB database service. - */ -public enum CosmosVectorDistanceFunction { - /** - * Represents the euclidean distance function. - */ - EUCLIDEAN("euclidean"), - - /** - * Represents the cosine distance function. - */ - COSINE("cosine"), - - /** - * Represents the dot product distance function. - */ - DOT_PRODUCT("dotproduct"); - - private final String overWireValue; - - CosmosVectorDistanceFunction(String overWireValue) { - this.overWireValue = overWireValue; - } - - @JsonValue - @Override - public String toString() { - return this.overWireValue; - } - - /** - * Method to retrieve the enum constant by its overWireValue. - * @param value the overWire value of the enum constant - * @return the matching CosmosVectorDataType - * @throws IllegalArgumentException if no matching enum constant is found - */ - public static CosmosVectorDistanceFunction fromString(String value) { - return Arrays.stream(CosmosVectorDistanceFunction.values()) - .filter(vectorDistanceFunction -> vectorDistanceFunction.toString().equalsIgnoreCase(value)) - .findFirst() - .orElseThrow(() -> new IllegalArgumentException("Invalid distance function for the vector embedding policy.")); - } -} diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosVectorEmbedding.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosVectorEmbedding.java deleted file mode 100644 index 94a519ef9d38..000000000000 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosVectorEmbedding.java +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.cosmos.models; - -import com.azure.cosmos.implementation.Constants; -import com.azure.cosmos.implementation.JsonSerializable; -import com.azure.cosmos.implementation.apachecommons.lang.StringUtils; -import com.fasterxml.jackson.annotation.JsonProperty; -import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; - -/** - * Embedding settings within {@link CosmosVectorEmbeddingPolicy} - */ -public final class CosmosVectorEmbedding { - @JsonProperty(Constants.Properties.PATH) - private String path; - @JsonProperty(Constants.Properties.VECTOR_DATA_TYPE) - private String dataType; - @JsonProperty(Constants.Properties.VECTOR_DIMENSIONS) - private Long dimensions; - @JsonProperty(Constants.Properties.DISTANCE_FUNCTION) - private String distanceFunction; - private JsonSerializable jsonSerializable; - - /** - * Constructor - */ - public CosmosVectorEmbedding() { - this.jsonSerializable = new JsonSerializable(); - } - - /** - * Gets the path for the cosmosVectorEmbedding. - * - * @return path - */ - public String getPath() { - return path; - } - - /** - * Sets the path for the cosmosVectorEmbedding. - * - * @param path the path for the cosmosVectorEmbedding - * @return CosmosVectorEmbedding - */ - public CosmosVectorEmbedding setPath(String path) { - if (StringUtils.isEmpty(path)) { - throw new NullPointerException("embedding path is empty"); - } - - if (path.charAt(0) != '/' || path.lastIndexOf('/') != 0) { - throw new IllegalArgumentException(""); - } - - this.path = path; - return this; - } - - /** - * Gets the data type for the cosmosVectorEmbedding. - * - * @return dataType - */ - public CosmosVectorDataType getDataType() { - return CosmosVectorDataType.fromString(dataType); - } - - /** - * Sets the data type for the cosmosVectorEmbedding. - * - * @param dataType the data type for the cosmosVectorEmbedding - * @return CosmosVectorEmbedding - */ - public CosmosVectorEmbedding setDataType(CosmosVectorDataType dataType) { - checkNotNull(dataType, "cosmosVectorDataType cannot be null"); - this.dataType = dataType.toString(); - return this; - } - - /** - * Gets the dimensions for the cosmosVectorEmbedding. - * - * @return dimensions - */ - public Long getDimensions() { - return dimensions; - } - - /** - * Sets the dimensions for the cosmosVectorEmbedding. - * - * @param dimensions the dimensions for the cosmosVectorEmbedding - * @return CosmosVectorEmbedding - */ - public CosmosVectorEmbedding setDimensions(Long dimensions) { - checkNotNull(dimensions, "dimensions cannot be null"); - if (dimensions < 1) { - throw new IllegalArgumentException("Dimensions for the embedding has to be a long value greater than 0 " + - "for the vector embedding policy"); - } - - this.dimensions = dimensions; - return this; - } - - /** - * Gets the distanceFunction for the cosmosVectorEmbedding. - * - * @return distanceFunction - */ - public CosmosVectorDistanceFunction getDistanceFunction() { - return CosmosVectorDistanceFunction.fromString(distanceFunction); - } - - /** - * Sets the distanceFunction for the cosmosVectorEmbedding. - * - * @param distanceFunction the distanceFunction for the cosmosVectorEmbedding - * @return CosmosVectorEmbedding - */ - public CosmosVectorEmbedding setDistanceFunction(CosmosVectorDistanceFunction distanceFunction) { - checkNotNull(distanceFunction, "cosmosVectorDistanceFunction cannot be empty"); - this.distanceFunction = distanceFunction.toString(); - return this; - } -} diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosVectorEmbeddingPolicy.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosVectorEmbeddingPolicy.java deleted file mode 100644 index c54c843ebd96..000000000000 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosVectorEmbeddingPolicy.java +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.cosmos.models; - -import com.azure.cosmos.implementation.Constants; -import com.azure.cosmos.implementation.JsonSerializable; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.List; - -/** - * Vector Embedding Policy - */ -public final class CosmosVectorEmbeddingPolicy { - - private JsonSerializable jsonSerializable; - /** - * Paths for embeddings along with path-specific settings for the item. - */ - @JsonProperty(Constants.Properties.VECTOR_EMBEDDINGS) - private List cosmosVectorEmbeddings; - - /** - * Constructor - */ - public CosmosVectorEmbeddingPolicy() { - this.jsonSerializable = new JsonSerializable(); - } - - /** - * Gets the paths for embeddings along with path-specific settings for the item. - * - * @return the paths for embeddings along with path-specific settings for the item. - */ - public List getVectorEmbeddings() { - return this.cosmosVectorEmbeddings; - } - - /** - * Sets the paths for embeddings along with path-specific settings for the item. - * - * @param cosmosVectorEmbeddings paths for embeddings along with path-specific settings for the item. - */ - public void setCosmosVectorEmbeddings(List cosmosVectorEmbeddings) { - cosmosVectorEmbeddings.forEach(embedding -> { - if (embedding == null) { - throw new NullPointerException("Embedding cannot be null."); - } - }); - this.cosmosVectorEmbeddings = cosmosVectorEmbeddings; -// this.jsonSerializable.set(Constants.Properties.VECTOR_EMBEDDINGS, cosmosVectorEmbeddings); - } - -} diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosVectorIndexSpec.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosVectorIndexSpec.java deleted file mode 100644 index 13b1559810ca..000000000000 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosVectorIndexSpec.java +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.cosmos.models; - -import com.azure.cosmos.CosmosItemSerializer; -import com.azure.cosmos.implementation.Constants; -import com.azure.cosmos.implementation.JsonSerializable; - -import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; - -/** - * Vector Indexes spec for Azure CosmosDB service. - */ -public final class CosmosVectorIndexSpec { - - private JsonSerializable jsonSerializable; - private String type; - - /** - * Constructor - */ - public CosmosVectorIndexSpec() { this.jsonSerializable = new JsonSerializable(); } - - /** - * Gets path. - * - * @return the path. - */ - public String getPath() { - return this.jsonSerializable.getString(Constants.Properties.PATH); - } - - /** - * Sets path. - * - * @param path the path. - * @return the SpatialSpec. - */ - public CosmosVectorIndexSpec setPath(String path) { - this.jsonSerializable.set(Constants.Properties.PATH, path, CosmosItemSerializer.DEFAULT_SERIALIZER); - return this; - } - - /** - * Gets the vector index type for the vector index - * - * @return the vector index type - */ - public String getType() { - if (this.type == null) { - this.type = this.jsonSerializable.getString(Constants.Properties.VECTOR_INDEX_TYPE); - } - return this.type; - } - - /** - * Sets the vector index type for the vector index - * - * @param type the vector index type - * @return the VectorIndexSpec - */ - public CosmosVectorIndexSpec setType(String type) { - checkNotNull(type, "cosmosVectorIndexType cannot be null"); - this.type = type; - this.jsonSerializable.set(Constants.Properties.VECTOR_INDEX_TYPE, this.type, CosmosItemSerializer.DEFAULT_SERIALIZER); - return this; - } - - void populatePropertyBag() { - this.jsonSerializable.populatePropertyBag(); - } - - JsonSerializable getJsonSerializable() { - return this.jsonSerializable; - } -} diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosVectorIndexType.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosVectorIndexType.java deleted file mode 100644 index 679ea1f991c0..000000000000 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/CosmosVectorIndexType.java +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.cosmos.models; - -/** - * Defines the index type of vector index specification in the Azure Cosmos DB service. - */ -public enum CosmosVectorIndexType { - /** - * Represents a flat vector index type. - */ - FLAT("flat"), - - /** - * Represents a quantized flat vector index type. - */ - QUANTIZED_FLAT("quantizedFlat"), - - /** - * Represents a disk ANN vector index type. - */ - DISK_ANN("diskANN"); - - - private final String overWireValue; - - CosmosVectorIndexType(String overWireValue) { - this.overWireValue = overWireValue; - } - - @Override - public String toString() { - return this.overWireValue; - } -} diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/IndexingPolicy.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/IndexingPolicy.java index 678cea56fcc4..939fc773c7e7 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/IndexingPolicy.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/IndexingPolicy.java @@ -20,12 +20,11 @@ */ public final class IndexingPolicy { private static final String DEFAULT_PATH = "/*"; - private final JsonSerializable jsonSerializable; private List includedPaths; private List excludedPaths; private List> compositeIndexes; private List spatialIndexes; - private List vectorIndexes; + private final JsonSerializable jsonSerializable; /** * Constructor. @@ -53,7 +52,7 @@ public IndexingPolicy() { * * * @param defaultIndexOverrides comma separated set of indexes that serve as default index specifications for the - * root path. + * root path. * @throws IllegalArgumentException throws when defaultIndexOverrides is null */ IndexingPolicy(Index[] defaultIndexOverrides) { @@ -234,7 +233,7 @@ public IndexingPolicy setCompositeIndexes(List> compositeInd } /** - * Gets the spatial indexes for additional indexes. + * Sets the spatial indexes for additional indexes. * * @return the spatial indexes. */ @@ -265,55 +264,11 @@ public IndexingPolicy setSpatialIndexes(List spatialIndexes) { return this; } - /** - * Gets the vector indexes. - * - * @return the vector indexes - */ - public List getVectorIndexes() { - if (this.vectorIndexes == null) { - this.vectorIndexes = this.jsonSerializable.getList(Constants.Properties.VECTOR_INDEXES, CosmosVectorIndexSpec.class); - - if (this.vectorIndexes == null) { - this.vectorIndexes = new ArrayList(); - } - } - - return this.vectorIndexes; - } - - /** - * Sets the vector indexes. - * - * Example of the vectorIndexes: - * "vectorIndexes": [ - * { - * "path": "/vector1", - * "type": "diskANN" - * }, - * { - * "path": "/vector1", - * "type": "flat" - * }, - * { - * "path": "/vector2", - * "type": "quantizedFlat" - * }] - * - * @param vectorIndexes the vector indexes - * @return the Indexing Policy. - */ - public IndexingPolicy setVectorIndexes(List vectorIndexes) { - this.vectorIndexes = vectorIndexes; - this.jsonSerializable.set(Constants.Properties.VECTOR_INDEXES,this.vectorIndexes, CosmosItemSerializer.DEFAULT_SERIALIZER); - return this; - } - void populatePropertyBag() { this.jsonSerializable.populatePropertyBag(); // If indexing mode is not 'none' and not paths are set, set them to the defaults if (this.getIndexingMode() != IndexingMode.NONE && this.getIncludedPaths().size() == 0 - && this.getExcludedPaths().size() == 0) { + && this.getExcludedPaths().size() == 0) { IncludedPath includedPath = new IncludedPath(IndexingPolicy.DEFAULT_PATH); this.getIncludedPaths().add(includedPath); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ModelBridgeInternal.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ModelBridgeInternal.java index e814cc16681b..cb9aba599c77 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ModelBridgeInternal.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/models/ModelBridgeInternal.java @@ -435,8 +435,6 @@ public static void populatePropertyBag(T t) { ((PartitionKeyDefinition) t).populatePropertyBag(); } else if (t instanceof SpatialSpec) { ((SpatialSpec) t).populatePropertyBag(); - } else if (t instanceof CosmosVectorIndexSpec) { - ((CosmosVectorIndexSpec) t).populatePropertyBag(); } else if (t instanceof SqlParameter) { ((SqlParameter) t).populatePropertyBag(); } else if (t instanceof SqlQuerySpec) { @@ -470,8 +468,6 @@ public static JsonSerializable getJsonSerializable(T t) { return ((PartitionKeyDefinition) t).getJsonSerializable(); } else if (t instanceof SpatialSpec) { return ((SpatialSpec) t).getJsonSerializable(); - } else if (t instanceof CosmosVectorIndexSpec) { - return ((CosmosVectorIndexSpec) t).getJsonSerializable(); } else if (t instanceof SqlParameter) { return ((SqlParameter) t).getJsonSerializable(); } else if (t instanceof SqlQuerySpec) { diff --git a/sdk/keyvault/azure-security-keyvault-administration/README.md b/sdk/keyvault/azure-security-keyvault-administration/README.md index f5293070284d..6cd8fad7cdeb 100644 --- a/sdk/keyvault/azure-security-keyvault-administration/README.md +++ b/sdk/keyvault/azure-security-keyvault-administration/README.md @@ -111,9 +111,15 @@ The Key Vault Backup Client provides both synchronous and asynchronous operation > NOTE: The backing store for key backups is a blob storage container using Shared Access Signature authentication. For more details on creating a SAS token using the `BlobServiceClient`, see the [Azure Storage Blobs client README][storage_readme_sas_token]. Alternatively, it is possible to [generate a SAS token in Storage Explorer][portal_sas_token]. +### Pre-Backup Operation +A pre-backup operation represents a long-running operation that checks if it is possible to perform a full key backup. + ### Backup Operation A backup operation represents a long-running operation for a full key backup. +### Pre-Restore Operation +A pre-restore operation represents a long-running operation that checks if it is possible to perform a full key restore from a backup. + ### Restore Operation A restore operation represents a long-running operation for both a full key and selective key restore. @@ -340,20 +346,47 @@ keyVaultAccessControlAsyncClient.deleteRoleAssignment(KeyVaultRoleScope.GLOBAL, ### Examples #### Sync API The following sections provide several code snippets covering some of the most common Azure Key Vault Backup client tasks, including: +- [Pre-backup check for a Key Vault](#run-pre-backup-check-for-a-collection-of-keys) - [Backup a Key Vault](#backup-a-collection-of-keys) +- [Pre-restore check for a Key Vault](#run-pre-restore-check-for-a-collection-of-keys) - [Restore a Key Vault](#restore-a-collection-of-keys) - [Restore a key](#selectively-restore-a-key) +##### Run pre-backup check for a collection of keys +Check if an entire collection of keys can be backed up by using `beginPreBackup()`. + +```java readme-sample-beginPreBackup +String blobStorageUrl = "https://myaccount.blob.core.windows.net/myContainer"; +String sasToken = ""; + +SyncPoller preBackupPoller = + keyVaultBackupClient.beginPreBackup(blobStorageUrl, sasToken); +PollResponse pollResponse = preBackupPoller.poll(); + +System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus()); + +PollResponse finalPollResponse = preBackupPoller.waitForCompletion(); + +if (finalPollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED) { + String folderUrl = preBackupPoller.getFinalResult(); + + System.out.printf("Pre-backup check completed successfully.%n"); +} else { + KeyVaultBackupOperation operation = preBackupPoller.poll().getValue(); + + System.out.printf("Pre-backup check failed with error: %s.%n", operation.getError().getMessage()); +} +``` + ##### Backup a collection of keys Back up an entire collection of keys using `beginBackup()`. ```java readme-sample-beginBackup String blobStorageUrl = "https://myaccount.blob.core.windows.net/myContainer"; -String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D"; +String sasToken = ""; SyncPoller backupPoller = keyVaultBackupClient.beginBackup(blobStorageUrl, sasToken); - PollResponse pollResponse = backupPoller.poll(); System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus()); @@ -371,26 +404,49 @@ if (finalPollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COM } ``` +##### Run pre-restore check for a collection of keys +Check if an entire collection of keys can be restored from a backup by using `beginPreRestore()`. + +```java readme-sample-beginPreRestore +String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313"; +String sasToken = ""; + +SyncPoller preRestorePoller = + keyVaultBackupClient.beginPreRestore(folderUrl, sasToken); +PollResponse pollResponse = preRestorePoller.poll(); + +System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus()); + +PollResponse finalPollResponse = preRestorePoller.waitForCompletion(); + +if (finalPollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED) { + System.out.printf("Pre-restore check completed successfully.%n"); +} else { + KeyVaultRestoreOperation operation = preRestorePoller.poll().getValue(); + + System.out.printf("Pre-restore check failed with error: %s.%n", operation.getError().getMessage()); +} +``` + ##### Restore a collection of keys Restore an entire collection of keys from a backup using `beginRestore()`. ```java readme-sample-beginRestore String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313"; -String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D"; +String sasToken = ""; -SyncPoller backupPoller = +SyncPoller restorePoller = keyVaultBackupClient.beginRestore(folderUrl, sasToken); - -PollResponse pollResponse = backupPoller.poll(); +PollResponse pollResponse = restorePoller.poll(); System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus()); -PollResponse finalPollResponse = backupPoller.waitForCompletion(); +PollResponse finalPollResponse = restorePoller.waitForCompletion(); if (finalPollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED) { System.out.printf("Backup restored successfully.%n"); } else { - KeyVaultRestoreOperation operation = backupPoller.poll().getValue(); + KeyVaultRestoreOperation operation = restorePoller.poll().getValue(); System.out.printf("Restore failed with error: %s.%n", operation.getError().getMessage()); } @@ -401,22 +457,21 @@ Restore a specific key from a backup using `beginSelectiveRestore()`. ```java readme-sample-beginSelectiveKeyRestore String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313"; -String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D"; +String sasToken = ""; String keyName = "myKey"; -SyncPoller backupPoller = +SyncPoller restorePoller = keyVaultBackupClient.beginSelectiveKeyRestore(folderUrl, sasToken, keyName); - -PollResponse pollResponse = backupPoller.poll(); +PollResponse pollResponse = restorePoller.poll(); System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus()); -PollResponse finalPollResponse = backupPoller.waitForCompletion(); +PollResponse finalPollResponse = restorePoller.waitForCompletion(); if (finalPollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED) { System.out.printf("Key restored successfully.%n"); } else { - KeyVaultSelectiveKeyRestoreOperation operation = backupPoller.poll().getValue(); + KeyVaultSelectiveKeyRestoreOperation operation = restorePoller.poll().getValue(); System.out.printf("Key restore failed with error: %s.%n", operation.getError().getMessage()); } @@ -424,18 +479,38 @@ if (finalPollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COM #### Async API The following sections provide several code snippets covering some of the most common asynchronous Azure Key Vault Backup client tasks, including: +- [Run pre-backup check for a collection of keys asynchronously](#run-pre-backup-check-for-a-collection-of-keys-asynchronously) - [Backup a Key Vault asynchronously](#backup-a-collection-of-keys-asynchronously) +- [Run pre-restore check for a collection of keys asynchronously](#run-pre-restore-check-for-a-collection-of-keys-asynchronously) - [Restore a Key Vault asynchronously](#restore-a-collection-of-keys-asynchronously) - [Restore a key asynchronously](#selectively-restore-a-key-asynchronously) > Note : You should add `System.in.read()` or `Thread.sleep()` after the function calls in the main class/thread to allow async functions/operations to execute and finish before the main application/thread exits. +##### Run pre-backup check for a collection of keys asynchronously +Check if an entire collection of keys can be backed up by using `beginPreBackup()`. + +```java readme-sample-beginPreBackupAsync +String blobStorageUrl = "https://myaccount.blob.core.windows.net/myContainer"; +String sasToken = ""; + +keyVaultBackupAsyncClient.beginPreBackup(blobStorageUrl, sasToken) + .setPollInterval(Duration.ofSeconds(1)) // You can set a custom polling interval. + .doOnError(e -> System.out.printf("Pre-backup check failed with error: %s.%n", e.getMessage())) + .doOnNext(pollResponse -> + System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus())) + .filter(pollResponse -> pollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED) + .flatMap(AsyncPollResponse::getFinalResult) + .subscribe(folderUrl -> + System.out.printf("Pre-backup check completed successfully.%n")); +``` + ##### Backup a collection of keys asynchronously Back up an entire collection of keys using `beginBackup()`. ```java readme-sample-beginBackupAsync String blobStorageUrl = "https://myaccount.blob.core.windows.net/myContainer"; -String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D"; +String sasToken = ""; keyVaultBackupAsyncClient.beginBackup(blobStorageUrl, sasToken) .setPollInterval(Duration.ofSeconds(1)) // You can set a custom polling interval. @@ -448,12 +523,29 @@ keyVaultBackupAsyncClient.beginBackup(blobStorageUrl, sasToken) System.out.printf("Backup completed. The storage location of this backup is: %s.%n", folderUrl)); ``` +##### Run pre-restore check for a collection of keys asynchronously +Check if an entire collection of keys can be restored from a backup by using `beginPreRestore()`. + +```java readme-sample-beginPreRestoreAsync +String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313"; +String sasToken = ""; + +keyVaultBackupAsyncClient.beginPreRestore(folderUrl, sasToken) + .setPollInterval(Duration.ofSeconds(1)) // You can set a custom polling interval. + .doOnError(e -> System.out.printf("Pre-restore check failed with error: %s.%n", e.getMessage())) + .doOnNext(pollResponse -> + System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus())) + .filter(pollResponse -> pollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED) + .flatMap(AsyncPollResponse::getFinalResult) + .subscribe(unused -> System.out.printf("Pre-restore check completed successfully.%n")); +``` + ##### Restore a collection of keys asynchronously Restore an entire collection of keys from a backup using `beginRestore()`. ```java readme-sample-beginRestoreAsync String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313"; -String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D"; +String sasToken = ""; keyVaultBackupAsyncClient.beginRestore(folderUrl, sasToken) .setPollInterval(Duration.ofSeconds(1)) // You can set a custom polling interval. @@ -470,7 +562,7 @@ Restore an entire collection of keys from a backup using `beginSelectiveRestore( ```java readme-sample-beginSelectiveKeyRestoreAsync String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313"; -String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D"; +String sasToken = ""; String keyName = "myKey"; keyVaultBackupAsyncClient.beginSelectiveKeyRestore(folderUrl, sasToken, keyName) diff --git a/sdk/keyvault/azure-security-keyvault-administration/assets.json b/sdk/keyvault/azure-security-keyvault-administration/assets.json index 2edac6dd53d7..16819beda18c 100644 --- a/sdk/keyvault/azure-security-keyvault-administration/assets.json +++ b/sdk/keyvault/azure-security-keyvault-administration/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "java", "TagPrefix": "java/keyvault/azure-security-keyvault-administration", - "Tag": "java/keyvault/azure-security-keyvault-administration_95d2cbb133" + "Tag": "java/keyvault/azure-security-keyvault-administration_18fc6d4e27" } diff --git a/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/KeyVaultAdministrationServiceVersion.java b/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/KeyVaultAdministrationServiceVersion.java index 9da3c1ae7476..f816b886c8cb 100644 --- a/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/KeyVaultAdministrationServiceVersion.java +++ b/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/KeyVaultAdministrationServiceVersion.java @@ -27,7 +27,12 @@ public enum KeyVaultAdministrationServiceVersion implements ServiceVersion { /** * Service version {@code 7.5}. */ - V7_5("7.5"); + V7_5("7.5"), + + /** + * Service version {@code 7.6-preview.1}. + */ + V7_6_PREVIEW_1("7.6-preview.1"); private final String version; @@ -46,6 +51,6 @@ public String getVersion() { * @return The latest {@link KeyVaultAdministrationServiceVersion}. */ public static KeyVaultAdministrationServiceVersion getLatest() { - return V7_5; + return V7_6_PREVIEW_1; } } diff --git a/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/KeyVaultBackupAsyncClient.java b/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/KeyVaultBackupAsyncClient.java index d4ed2f1d1f92..e49ae353a98b 100644 --- a/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/KeyVaultBackupAsyncClient.java +++ b/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/KeyVaultBackupAsyncClient.java @@ -18,6 +18,8 @@ import com.azure.core.util.polling.PollingContext; import com.azure.security.keyvault.administration.implementation.KeyVaultBackupClientImpl; import com.azure.security.keyvault.administration.implementation.KeyVaultErrorCodeStrings; +import com.azure.security.keyvault.administration.implementation.models.PreBackupOperationParameters; +import com.azure.security.keyvault.administration.implementation.models.PreRestoreOperationParameters; import com.azure.security.keyvault.administration.implementation.models.RestoreOperation; import com.azure.security.keyvault.administration.implementation.models.RestoreOperationParameters; import com.azure.security.keyvault.administration.implementation.models.SASTokenParameter; @@ -89,8 +91,7 @@ * *

  * String blobStorageUrl = "https://myaccount.blob.core.windows.net/myContainer";
- * String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z"
- *     + "&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D";
+ * String sasToken = "<sas-token>";
  *
  * client.beginBackup(blobStorageUrl, sasToken)
  *     .setPollInterval(Duration.ofSeconds(1)) // You can set a custom polling interval.
@@ -120,8 +121,7 @@
  * 
  * 
  * String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313";
- * String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z"
- *     + "&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D";
+ * String sasToken = "<sas-token>";
  *
  * client.beginRestore(folderUrl, sasToken)
  *     .setPollInterval(Duration.ofSeconds(1)) // You can set a custom polling interval.
@@ -150,8 +150,7 @@
  * 
  * 
  * String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313";
- * String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z"
- *     + "&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D";
+ * String sasToken = "<sas-token>";
  * String keyName = "myKey";
  *
  * client.beginSelectiveKeyRestore(folderUrl, sasToken, keyName)
@@ -249,8 +248,7 @@ HttpPipeline getHttpPipeline() {
      * 
      * 
      * String blobStorageUrl = "https://myaccount.blob.core.windows.net/myContainer";
-     * String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z"
-     *     + "&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D";
+     * String sasToken = "<sas-token>";
      *
      * client.beginBackup(blobStorageUrl, sasToken)
      *     .setPollInterval(Duration.ofSeconds(1)) // You can set a custom polling interval.
@@ -400,6 +398,101 @@ private static Mono> processBackupOperatio
             toLongRunningOperationStatus(operationStatus.toLowerCase(Locale.US)), response.getValue()));
     }
 
+    /**
+     * Initiates a pre-backup check on the Key Vault. This operation checks if it is possible to back up the entire
+     * collection of keys from a key vault.
+     *
+     * 

Code Samples

+ *

Starts a {@link KeyVaultBackupOperation pre-backup operation}, polls for its status and waits for it to + * complete. Prints out the details of the operation's final result in case of success or prints out details of an + * error in case the operation fails.

+ * + *
+     * String blobStorageUrl = "https://myaccount.blob.core.windows.net/myContainer";
+     * String sasToken = "<sas-token>";
+     *
+     * client.beginPreBackup(blobStorageUrl, sasToken)
+     *     .setPollInterval(Duration.ofSeconds(1)) // You can set a custom polling interval.
+     *     .doOnError(e -> System.out.printf("Pre-backup check failed with error: %s.%n", e.getMessage()))
+     *     .doOnNext(pollResponse ->
+     *         System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus()))
+     *     .filter(pollResponse -> pollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED)
+     *     .flatMap(AsyncPollResponse::getFinalResult)
+     *     .subscribe(unused -> System.out.printf("Pre-backup check completed successfully.%n"));
+     * 
+ * + * + * @param blobStorageUrl The URL for the Blob Storage resource where the backup will be located. + * @param sasToken Optional Shared Access Signature (SAS) token to authorize access to the blob. If {@code null}, + * Managed Identity will be used to authenticate instead. + * + * @return A {@link PollerFlux} polling on the {@link KeyVaultBackupOperation pre-backup operation} status. + * + * @throws KeyVaultAdministrationException If the given {@code blobStorageUrl} or {@code sasToken} are invalid. + * @throws NullPointerException If the {@code blobStorageUrl} is {@code null}. + */ + @ServiceMethod(returns = ReturnType.LONG_RUNNING_OPERATION) + public PollerFlux beginPreBackup(String blobStorageUrl, String sasToken) { + if (blobStorageUrl == null) { + throw LOGGER.logExceptionAsError( + new NullPointerException( + String.format(KeyVaultErrorCodeStrings.PARAMETER_REQUIRED, "'blobStorageUrl'"))); + } + + return new PollerFlux<>(getDefaultPollingInterval(), + preBackupActivationOperation(blobStorageUrl, sasToken), + backupPollOperation(), + (pollingContext, firstResponse) -> + Mono.error(LOGGER.logExceptionAsError(new RuntimeException("Cancellation is not supported"))), + backupFetchOperation()); + } + + /** + * Initiates a pre-backup check on the Key Vault. This operation checks if it is possible to back up the entire + * collection of keys from a key vault. + * + * @param blobStorageUrl The URL for the Blob Storage resource where the backup will be located. + * @param sasToken Optional Shared Access Signature (SAS) token to authorize access to the blob. If {@code null}, + * Managed Identity will be used to authenticate instead. + * @param context Additional context that is passed through the HTTP pipeline during the service call. + * + * @return A {@link PollerFlux} polling on the {@link KeyVaultBackupOperation pre-backup operation} status. + * + * @throws KeyVaultAdministrationException If the given {@code blobStorageUrl} or {@code sasToken} are invalid. + */ + Mono> preBackupWithResponse(String blobStorageUrl, String sasToken, + Context context) { + PreBackupOperationParameters preBackupOperationParameters = new PreBackupOperationParameters() + .setStorageResourceUri(blobStorageUrl) + .setToken(sasToken) + .setUseManagedIdentity(sasToken == null); + + try { + return clientImpl.preFullBackupWithResponseAsync(vaultUrl, preBackupOperationParameters, context) + .doOnRequest(ignored -> LOGGER.verbose("Backing up at URL - {}", blobStorageUrl)) + .doOnSuccess(response -> LOGGER.verbose("Backed up at URL - {}", + response.getValue().getAzureStorageBlobContainerUri())) + .doOnError(error -> LOGGER.warning("Failed to backup at URL - {}", blobStorageUrl, error)) + .map(backupOperationResponse -> + new SimpleResponse<>(backupOperationResponse.getRequest(), backupOperationResponse.getStatusCode(), + backupOperationResponse.getHeaders(), + (KeyVaultBackupOperation) transformToLongRunningOperation(backupOperationResponse.getValue()))); + } catch (RuntimeException e) { + return monoError(LOGGER, e); + } + } + + private Function, Mono> preBackupActivationOperation(String blobStorageUrl, String sasToken) { + return (pollingContext) -> { + try { + return withContext(context -> preBackupWithResponse(blobStorageUrl, sasToken, context)) + .flatMap(backupResponse -> Mono.just(backupResponse.getValue())); + } catch (RuntimeException e) { + return monoError(LOGGER, e); + } + }; + } + /** * Initiates a full restore of the Key Vault. * @@ -409,8 +502,7 @@ private static Mono> processBackupOperatio * *
      * String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313";
-     * String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z"
-     *     + "&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D";
+     * String sasToken = "<sas-token>";
      *
      * client.beginRestore(folderUrl, sasToken)
      *     .setPollInterval(Duration.ofSeconds(1)) // You can set a custom polling interval.
@@ -554,6 +646,116 @@ static Mono> processRestoreOperationRespo
             toLongRunningOperationStatus(operationStatus.toLowerCase(Locale.US)), response.getValue()));
     }
 
+    /**
+     * Initiates a pre-restore check on the Key Vault. This operation checks if it is possible to restore an entire
+     * collection of keys from a backup.
+     *
+     * 

Code Samples

+ *

Starts a {@link KeyVaultRestoreOperation pre-restore operation}, polls for its status and waits for it to + * complete. Prints out error details in case the operation fails.

+ * + *
+     * String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313";
+     * String sasToken = "<sas-token>";
+     *
+     * client.beginPreRestore(folderUrl, sasToken)
+     *     .setPollInterval(Duration.ofSeconds(1)) // You can set a custom polling interval.
+     *     .doOnError(e -> System.out.printf("Pre-restore check failed with error: %s.%n", e.getMessage()))
+     *     .doOnNext(pollResponse ->
+     *         System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus()))
+     *     .filter(pollResponse -> pollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED)
+     *     .flatMap(AsyncPollResponse::getFinalResult)
+     *     .subscribe(unused -> System.out.printf("Pre-restore check completed successfully.%n"));
+     * 
+ * + * + * @param folderUrl The URL for the Blob Storage resource where the backup is located, including the path to + * the blob container where the backup resides. This would be the exact value that is returned as the result of a + * backup operation. An example of such a URL may look like the following: + * {@code https://contoso.blob.core.windows.net/backup/mhsm-contoso-2020090117323313}. + * @param sasToken Optional Shared Access Signature (SAS) token to authorize access to the blob. If {@code null}, + * Managed Identity will be used to authenticate instead. + * + * @return A {@link PollerFlux} polling on the {@link KeyVaultRestoreOperation restore operation} status. + * + * @throws KeyVaultAdministrationException If the given {@code folderUrl} or {@code sasToken} are invalid. + * @throws NullPointerException If the {@code folderUrl} is {@code null}. + */ + @ServiceMethod(returns = ReturnType.LONG_RUNNING_OPERATION) + public PollerFlux beginPreRestore(String folderUrl, + String sasToken) { + if (folderUrl == null) { + throw LOGGER.logExceptionAsError( + new NullPointerException(String.format(KeyVaultErrorCodeStrings.PARAMETER_REQUIRED, "'folderUrl'"))); + } + + return new PollerFlux<>(getDefaultPollingInterval(), + preRestoreActivationOperation(folderUrl, sasToken), + restorePollOperation(), + (pollingContext, firstResponse) -> + Mono.error(LOGGER.logExceptionAsError(new RuntimeException("Cancellation is not supported"))), + (pollingContext) -> Mono.just(new KeyVaultRestoreResult())); + } + + /** + * Initiates a pre-restore check on the Key Vault. This operation checks if it is possible to restore an entire + * collection of keys from a backup. + * + * @param folderUrl The URL for the Blob Storage resource where the backup is located, including the path to + * the blob container where the backup resides. This would be the exact value that is returned as the result of a + * backup operation. An example of such a URL may look like the following: + * {@code https://contoso.blob.core.windows.net/backup/mhsm-contoso-2020090117323313}. + * @param sasToken Optional Shared Access Signature (SAS) token to authorize access to the blob. If {@code null}, + * Managed Identity will be used to authenticate instead. + * @param context Additional context that is passed through the HTTP pipeline during the service call. + * + * @return A {@link PollerFlux} polling on the {@link KeyVaultRestoreOperation backup operation} status. + * + * @throws KeyVaultAdministrationException If the given {@code folderUrl} or {@code sasToken} are invalid. + */ + Mono> preRestoreWithResponse(String folderUrl, String sasToken, + Context context) { + String[] segments = folderUrl.split("/"); + String folderName = segments[segments.length - 1]; + String containerUrl = folderUrl.substring(0, folderUrl.length() - folderName.length()); + + SASTokenParameter sasTokenParameter = new SASTokenParameter(containerUrl) + .setToken(sasToken) + .setUseManagedIdentity(sasToken == null); + + PreRestoreOperationParameters preRestoreOperationParameters = + new PreRestoreOperationParameters() + .setFolderToRestore(folderName) + .setSasTokenParameters(sasTokenParameter); + + try { + return clientImpl.preFullRestoreOperationWithResponseAsync(vaultUrl, preRestoreOperationParameters, context) + .doOnRequest(ignored -> LOGGER.verbose("Restoring from location - {}", folderUrl)) + .doOnSuccess(response -> LOGGER.verbose("Restored from location - {}", folderUrl)) + .doOnError(error -> + LOGGER.warning("Failed to restore from location - {}", folderUrl, error)) + .map(restoreOperationResponse -> + new SimpleResponse<>(restoreOperationResponse.getRequest(), + restoreOperationResponse.getStatusCode(), + restoreOperationResponse.getHeaders(), + (KeyVaultRestoreOperation) transformToLongRunningOperation( + restoreOperationResponse.getValue()))); + } catch (RuntimeException e) { + return monoError(LOGGER, e); + } + } + + private Function, Mono> preRestoreActivationOperation(String folderUrl, String sasToken) { + return (pollingContext) -> { + try { + return withContext(context -> preRestoreWithResponse(folderUrl, sasToken, context)) + .flatMap(restoreResponse -> Mono.just(restoreResponse.getValue())); + } catch (RuntimeException e) { + return monoError(LOGGER, e); + } + }; + } + /** * Restores all versions of a given key using the supplied SAS token pointing to a previously stored Azure Blob * storage backup folder. @@ -564,8 +766,7 @@ static Mono> processRestoreOperationRespo * *
      * String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313";
-     * String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z"
-     *     + "&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D";
+     * String sasToken = "<sas-token>";
      * String keyName = "myKey";
      *
      * client.beginSelectiveKeyRestore(folderUrl, sasToken, keyName)
diff --git a/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/KeyVaultBackupClient.java b/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/KeyVaultBackupClient.java
index 3dafe20bf84a..52bb3f35d5a8 100644
--- a/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/KeyVaultBackupClient.java
+++ b/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/KeyVaultBackupClient.java
@@ -22,6 +22,10 @@
 import com.azure.security.keyvault.administration.implementation.models.FullBackupHeaders;
 import com.azure.security.keyvault.administration.implementation.models.FullBackupOperation;
 import com.azure.security.keyvault.administration.implementation.models.FullRestoreOperationHeaders;
+import com.azure.security.keyvault.administration.implementation.models.PreBackupOperationParameters;
+import com.azure.security.keyvault.administration.implementation.models.PreFullBackupHeaders;
+import com.azure.security.keyvault.administration.implementation.models.PreFullRestoreOperationHeaders;
+import com.azure.security.keyvault.administration.implementation.models.PreRestoreOperationParameters;
 import com.azure.security.keyvault.administration.implementation.models.RestoreOperation;
 import com.azure.security.keyvault.administration.implementation.models.RestoreOperationParameters;
 import com.azure.security.keyvault.administration.implementation.models.SASTokenParameter;
@@ -92,11 +96,9 @@
  * 
  * 
  * String blobStorageUrl = "https://myaccount.blob.core.windows.net/myContainer";
- * String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z"
- *     + "&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D";
+ * String sasToken = "<sas-token>";
  *
  * SyncPoller<KeyVaultBackupOperation, String> backupPoller = client.beginBackup(blobStorageUrl, sasToken);
- *
  * PollResponse<KeyVaultBackupOperation> pollResponse = backupPoller.poll();
  *
  * System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus());
@@ -131,22 +133,20 @@
  * 
  * 
  * String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313";
- * String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z"
- *     + "&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D";
+ * String sasToken = "<sas-token>";
  *
- * SyncPoller<KeyVaultRestoreOperation, KeyVaultRestoreResult> backupPoller =
+ * SyncPoller<KeyVaultRestoreOperation, KeyVaultRestoreResult> restorePoller =
  *     client.beginRestore(folderUrl, sasToken);
- *
- * PollResponse<KeyVaultRestoreOperation> pollResponse = backupPoller.poll();
+ * PollResponse<KeyVaultRestoreOperation> pollResponse = restorePoller.poll();
  *
  * System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus());
  *
- * PollResponse<KeyVaultRestoreOperation> finalPollResponse = backupPoller.waitForCompletion();
+ * PollResponse<KeyVaultRestoreOperation> finalPollResponse = restorePoller.waitForCompletion();
  *
  * if (finalPollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED) {
  *     System.out.printf("Backup restored successfully.%n");
  * } else {
- *     KeyVaultRestoreOperation operation = backupPoller.poll().getValue();
+ *     KeyVaultRestoreOperation operation = restorePoller.poll().getValue();
  *
  *     System.out.printf("Restore failed with error: %s.%n", operation.getError().getMessage());
  * }
@@ -169,23 +169,21 @@
  * 
  * 
  * String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313";
- * String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z"
- *     + "&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D";
+ * String sasToken = "<sas-token>";
  * String keyName = "myKey";
  *
- * SyncPoller<KeyVaultSelectiveKeyRestoreOperation, KeyVaultSelectiveKeyRestoreResult> backupPoller =
+ * SyncPoller<KeyVaultSelectiveKeyRestoreOperation, KeyVaultSelectiveKeyRestoreResult> restorePoller =
  *     client.beginSelectiveKeyRestore(folderUrl, sasToken, keyName);
- *
- * PollResponse<KeyVaultSelectiveKeyRestoreOperation> pollResponse = backupPoller.poll();
+ * PollResponse<KeyVaultSelectiveKeyRestoreOperation> pollResponse = restorePoller.poll();
  *
  * System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus());
  *
- * PollResponse<KeyVaultSelectiveKeyRestoreOperation> finalPollResponse = backupPoller.waitForCompletion();
+ * PollResponse<KeyVaultSelectiveKeyRestoreOperation> finalPollResponse = restorePoller.waitForCompletion();
  *
  * if (finalPollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED) {
  *     System.out.printf("Key restored successfully.%n");
  * } else {
- *     KeyVaultSelectiveKeyRestoreOperation operation = backupPoller.poll().getValue();
+ *     KeyVaultSelectiveKeyRestoreOperation operation = restorePoller.poll().getValue();
  *
  *     System.out.printf("Key restore failed with error: %s.%n", operation.getError().getMessage());
  * }
@@ -271,11 +269,9 @@ public String getVaultUrl() {
      * 
      * 
      * String blobStorageUrl = "https://myaccount.blob.core.windows.net/myContainer";
-     * String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z"
-     *     + "&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D";
+     * String sasToken = "<sas-token>";
      *
      * SyncPoller<KeyVaultBackupOperation, String> backupPoller = client.beginBackup(blobStorageUrl, sasToken);
-     *
      * PollResponse<KeyVaultBackupOperation> pollResponse = backupPoller.poll();
      *
      * System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus());
@@ -414,6 +410,112 @@ private static PollResponse processBackupOperationRespo
             toLongRunningOperationStatus(operationStatus.toLowerCase(Locale.US)), response.getValue());
     }
 
+    /**
+     * Initiates a pre-backup check on the Key Vault. This operation checks if it is possible to back up the entire
+     * collection of keys from a key vault.
+     *
+     * 

Code Samples

+ *

Starts a {@link KeyVaultBackupOperation pre-backup operation}, polls for its status and waits for it to + * complete. Prints out the details of the operation's final result in case of success or prints out error details + * in case the operation fails.

+ * + *
+     * String blobStorageUrl = "https://myaccount.blob.core.windows.net/myContainer";
+     * String sasToken = "<sas-token>";
+     *
+     * SyncPoller<KeyVaultBackupOperation, String> preBackupPoller = client.beginPreBackup(blobStorageUrl, sasToken);
+     * PollResponse<KeyVaultBackupOperation> pollResponse = preBackupPoller.poll();
+     *
+     * System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus());
+     *
+     * PollResponse<KeyVaultBackupOperation> finalPollResponse = preBackupPoller.waitForCompletion();
+     *
+     * if (finalPollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED) {
+     *     System.out.printf("Pre-backup check completed successfully.%n");
+     * } else {
+     *     KeyVaultBackupOperation operation = preBackupPoller.poll().getValue();
+     *
+     *     System.out.printf("Pre-backup check failed with error: %s.%n", operation.getError().getMessage());
+     * }
+     * 
+ * + * + * @param blobStorageUrl The URL for the Blob Storage resource where the backup will be located. + * @param sasToken Optional Shared Access Signature (SAS) token to authorize access to the blob. If {@code null}, + * Managed Identity will be used to authenticate instead. + * + * @return A {@link SyncPoller} polling on the {@link KeyVaultBackupOperation pre-backup operation} status. + * + * @throws KeyVaultAdministrationException If the given {@code blobStorageUrl} or {@code sasToken} are invalid. + * @throws NullPointerException If the {@code blobStorageUrl} is {@code null}. + */ + @ServiceMethod(returns = ReturnType.LONG_RUNNING_OPERATION) + public SyncPoller beginPreBackup(String blobStorageUrl, String sasToken) { + if (blobStorageUrl == null) { + throw LOGGER.logExceptionAsError( + new NullPointerException( + String.format(KeyVaultErrorCodeStrings.PARAMETER_REQUIRED, "'blobStorageUrl'"))); + } + + Context context = Context.NONE; + + return SyncPoller.createPoller( + getDefaultPollingInterval(), + cxt -> + new PollResponse<>(LongRunningOperationStatus.NOT_STARTED, + preBackupActivationOperation(blobStorageUrl, sasToken, context) + .apply(cxt)), + backupPollOperation(context), + (pollingContext, firstResponse) -> { + throw LOGGER.logExceptionAsError(new RuntimeException("Cancellation is not supported")); + }, + backupFetchOperation()); + } + + private Function, KeyVaultBackupOperation> preBackupActivationOperation( + String blobStorageUrl, String sasToken, Context context) { + + return (pollingContext) -> { + try { + return preBackupWithResponse(blobStorageUrl, sasToken, context).getValue(); + } catch (RuntimeException e) { + throw LOGGER.logExceptionAsError(e); + } + }; + } + + /** + * Initiates a pre-backup check on the Key Vault. This operation checks if it is possible to back up the entire + * collection of keys from a key vault. + * + * @param blobStorageUrl The URL for the Blob Storage resource where the backup will be located. + * @param sasToken Optional Shared Access Signature (SAS) token to authorize access to the blob. If {@code null}, + * Managed Identity will be used to authenticate instead. + * @param context Additional context that is passed through the HTTP pipeline during the service call. + * + * @return A {@link Response} containing the {@link KeyVaultBackupOperation pre-backup operation} status. + * + * @throws KeyVaultAdministrationException If the given {@code blobStorageUrl} or {@code sasToken} are invalid. + */ + Response preBackupWithResponse(String blobStorageUrl, String sasToken, Context context) { + PreBackupOperationParameters preBackupOperationParameters = new PreBackupOperationParameters() + .setStorageResourceUri(blobStorageUrl) + .setToken(sasToken) + .setUseManagedIdentity(sasToken == null); + context = enableSyncRestProxy(context); + + try { + ResponseBase backupOperationResponse = + clientImpl.preFullBackupWithResponse(vaultUrl, preBackupOperationParameters, context); + + return new SimpleResponse<>(backupOperationResponse.getRequest(), backupOperationResponse.getStatusCode(), + backupOperationResponse.getHeaders(), + (KeyVaultBackupOperation) transformToLongRunningOperation(backupOperationResponse.getValue())); + } catch (RuntimeException e) { + throw LOGGER.logExceptionAsError(e); + } + } + /** * Initiates a full restore of the Key Vault. * @@ -423,11 +525,9 @@ private static PollResponse processBackupOperationRespo * *
      * String blobStorageUrl = "https://myaccount.blob.core.windows.net/myContainer";
-     * String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z"
-     *     + "&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D";
+     * String sasToken = "<sas-token>";
      *
      * SyncPoller<KeyVaultBackupOperation, String> backupPoller = client.beginBackup(blobStorageUrl, sasToken);
-     *
      * PollResponse<KeyVaultBackupOperation> pollResponse = backupPoller.poll();
      *
      * System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus());
@@ -569,6 +669,121 @@ private static PollResponse processRestoreOperationRes
             toLongRunningOperationStatus(operationStatus.toLowerCase(Locale.US)), response.getValue());
     }
 
+    /**
+     * Initiates a pre-restore check on the Key Vault. This operation checks if it is possible to restore an entire
+     * collection of keys from a backup.
+     *
+     * 

Code Samples

+ *

Starts a {@link KeyVaultRestoreOperation pre-restore operation}, polls for its status and waits for it to + * complete. Prints out error details in case the operation fails.

+ * + *
+     * String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313";
+     * String sasToken = "<sas-token>";
+     *
+     * SyncPoller<KeyVaultRestoreOperation, KeyVaultRestoreResult> preRestorePoller =
+     *     client.beginPreRestore(folderUrl, sasToken);
+     * PollResponse<KeyVaultRestoreOperation> pollResponse = preRestorePoller.poll();
+     *
+     * System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus());
+     *
+     * PollResponse<KeyVaultRestoreOperation> finalPollResponse = preRestorePoller.waitForCompletion();
+     *
+     * if (finalPollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED) {
+     *     System.out.printf("Pre-restore check completed successfully.%n");
+     * } else {
+     *     KeyVaultRestoreOperation operation = preRestorePoller.poll().getValue();
+     *
+     *     System.out.printf("Pre-restore check failed with error: %s.%n", operation.getError().getMessage());
+     * }
+     * 
+ * + * + * @param folderUrl The URL for the Blob Storage resource where the backup is located, including the path to + * the blob container where the backup resides. This would be the exact value that is returned as the result of a + * backup operation. An example of such a URL may look like the following: + * {@code https://contoso.blob.core.windows.net/backup/mhsm-contoso-2020090117323313}. + * @param sasToken Optional Shared Access Signature (SAS) token to authorize access to the blob. If {@code null}, + * Managed Identity will be used to authenticate instead. + * + * @return A {@link SyncPoller} to poll on the {@link KeyVaultRestoreOperation restore operation} status. + * + * @throws KeyVaultAdministrationException If the given {@code folderUrl} or {@code sasToken} are invalid. + * @throws NullPointerException If the {@code folderUrl} is {@code null}. + */ + @ServiceMethod(returns = ReturnType.LONG_RUNNING_OPERATION) + public SyncPoller beginPreRestore(String folderUrl, String sasToken) { + if (folderUrl == null) { + throw LOGGER.logExceptionAsError( + new NullPointerException(String.format(KeyVaultErrorCodeStrings.PARAMETER_REQUIRED, "'folderUrl'"))); + } + + Context context = Context.NONE; + + return SyncPoller.createPoller(getDefaultPollingInterval(), + cxt -> + new PollResponse<>(LongRunningOperationStatus.NOT_STARTED, + preRestoreActivationOperation(folderUrl, sasToken, context) + .apply(cxt)), + restorePollOperation(context), + (pollingContext, firstResponse) -> { + throw LOGGER.logExceptionAsError(new RuntimeException("Cancellation is not supported")); + }, + (pollingContext) -> new KeyVaultRestoreResult()); + } + + /** + * Initiates a pre-restore check on the Key Vault. This operation checks if it is possible to restore an entire + * collection of keys from a backup. + * + * @param folderUrl The URL for the Blob Storage resource where the backup is located, including the path to + * the blob container where the backup resides. This would be the exact value that is returned as the result of a + * backup operation. An example of such a URL may look like the following: + * {@code https://contoso.blob.core.windows.net/backup/mhsm-contoso-2020090117323313}. + * @param sasToken Optional Shared Access Signature (SAS) token to authorize access to the blob. If {@code null}, + * Managed Identity will be used to authenticate instead. + * @param context Additional context that is passed through the HTTP pipeline during the service call. + * + * @return A {@link Response} containing the {@link KeyVaultRestoreOperation backup operation} status. + * + * @throws KeyVaultAdministrationException If the given {@code folderUrl} or {@code sasToken} are invalid. + */ + Response preRestoreWithResponse(String folderUrl, String sasToken, Context context) { + String[] segments = folderUrl.split("/"); + String folderName = segments[segments.length - 1]; + String containerUrl = folderUrl.substring(0, folderUrl.length() - folderName.length()); + + SASTokenParameter sasTokenParameter = new SASTokenParameter(containerUrl) + .setToken(sasToken) + .setUseManagedIdentity(sasToken == null); + PreRestoreOperationParameters restoreOperationParameters = + new PreRestoreOperationParameters() + .setFolderToRestore(folderName) + .setSasTokenParameters(sasTokenParameter); + context = enableSyncRestProxy(context); + + try { + ResponseBase restoreOperationResponse = + clientImpl.preFullRestoreOperationWithResponse(vaultUrl, restoreOperationParameters, context); + return new SimpleResponse<>(restoreOperationResponse.getRequest(), + restoreOperationResponse.getStatusCode(), + restoreOperationResponse.getHeaders(), + (KeyVaultRestoreOperation) transformToLongRunningOperation(restoreOperationResponse.getValue())); + } catch (RuntimeException e) { + throw LOGGER.logExceptionAsError(e); + } + } + + private Function, KeyVaultRestoreOperation> preRestoreActivationOperation(String folderUrl, String sasToken, Context context) { + return (pollingContext) -> { + try { + return preRestoreWithResponse(folderUrl, sasToken, context).getValue(); + } catch (RuntimeException e) { + throw LOGGER.logExceptionAsError(e); + } + }; + } + /** * Restores all versions of a given key using the supplied SAS token pointing to a previously stored Azure Blob * storage backup folder. @@ -579,23 +794,21 @@ private static PollResponse processRestoreOperationRes * *
      * String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313";
-     * String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z"
-     *     + "&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D";
+     * String sasToken = "<sas-token>";
      * String keyName = "myKey";
      *
-     * SyncPoller<KeyVaultSelectiveKeyRestoreOperation, KeyVaultSelectiveKeyRestoreResult> backupPoller =
+     * SyncPoller<KeyVaultSelectiveKeyRestoreOperation, KeyVaultSelectiveKeyRestoreResult> restorePoller =
      *     client.beginSelectiveKeyRestore(folderUrl, sasToken, keyName);
-     *
-     * PollResponse<KeyVaultSelectiveKeyRestoreOperation> pollResponse = backupPoller.poll();
+     * PollResponse<KeyVaultSelectiveKeyRestoreOperation> pollResponse = restorePoller.poll();
      *
      * System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus());
      *
-     * PollResponse<KeyVaultSelectiveKeyRestoreOperation> finalPollResponse = backupPoller.waitForCompletion();
+     * PollResponse<KeyVaultSelectiveKeyRestoreOperation> finalPollResponse = restorePoller.waitForCompletion();
      *
      * if (finalPollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED) {
      *     System.out.printf("Key restored successfully.%n");
      * } else {
-     *     KeyVaultSelectiveKeyRestoreOperation operation = backupPoller.poll().getValue();
+     *     KeyVaultSelectiveKeyRestoreOperation operation = restorePoller.poll().getValue();
      *
      *     System.out.printf("Key restore failed with error: %s.%n", operation.getError().getMessage());
      * }
diff --git a/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/implementation/KeyVaultBackupClientImpl.java b/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/implementation/KeyVaultBackupClientImpl.java
index 4cf02ee63d5f..88a7c6f61f0d 100644
--- a/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/implementation/KeyVaultBackupClientImpl.java
+++ b/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/implementation/KeyVaultBackupClientImpl.java
@@ -33,6 +33,10 @@
 import com.azure.security.keyvault.administration.implementation.models.FullBackupOperation;
 import com.azure.security.keyvault.administration.implementation.models.FullRestoreOperationHeaders;
 import com.azure.security.keyvault.administration.implementation.models.KeyVaultErrorException;
+import com.azure.security.keyvault.administration.implementation.models.PreBackupOperationParameters;
+import com.azure.security.keyvault.administration.implementation.models.PreFullBackupHeaders;
+import com.azure.security.keyvault.administration.implementation.models.PreFullRestoreOperationHeaders;
+import com.azure.security.keyvault.administration.implementation.models.PreRestoreOperationParameters;
 import com.azure.security.keyvault.administration.implementation.models.RestoreOperation;
 import com.azure.security.keyvault.administration.implementation.models.RestoreOperationParameters;
 import com.azure.security.keyvault.administration.implementation.models.SASTokenParameter;
@@ -57,7 +61,7 @@ public final class KeyVaultBackupClientImpl {
 
     /**
      * Gets Api Version.
-     * 
+     *
      * @return the apiVersion value.
      */
     public String getApiVersion() {
@@ -71,7 +75,7 @@ public String getApiVersion() {
 
     /**
      * Gets The HTTP pipeline to send requests through.
-     * 
+     *
      * @return the httpPipeline value.
      */
     public HttpPipeline getHttpPipeline() {
@@ -85,7 +89,7 @@ public HttpPipeline getHttpPipeline() {
 
     /**
      * Gets The serializer to serialize an object into a string.
-     * 
+     *
      * @return the serializerAdapter value.
      */
     public SerializerAdapter getSerializerAdapter() {
@@ -94,7 +98,7 @@ public SerializerAdapter getSerializerAdapter() {
 
     /**
      * Initializes an instance of KeyVaultBackupClient client.
-     * 
+     *
      * @param apiVersion Api Version.
      */
     public KeyVaultBackupClientImpl(String apiVersion) {
@@ -104,7 +108,7 @@ public KeyVaultBackupClientImpl(String apiVersion) {
 
     /**
      * Initializes an instance of KeyVaultBackupClient client.
-     * 
+     *
      * @param httpPipeline The HTTP pipeline to send requests through.
      * @param apiVersion Api Version.
      */
@@ -114,7 +118,7 @@ public KeyVaultBackupClientImpl(HttpPipeline httpPipeline, String apiVersion) {
 
     /**
      * Initializes an instance of KeyVaultBackupClient client.
-     * 
+     *
      * @param httpPipeline The HTTP pipeline to send requests through.
      * @param serializerAdapter The serializer to serialize an object into a string.
      * @param apiVersion Api Version.
@@ -150,6 +154,22 @@ ResponseBase fullBackupSync(
             @BodyParam("application/json") SASTokenParameter azureStorageBlobContainerUri,
             @HeaderParam("Accept") String accept, Context context);
 
+        @Post("/prebackup")
+        @ExpectedResponses({ 202 })
+        @UnexpectedResponseExceptionType(KeyVaultErrorException.class)
+        Mono> preFullBackup(
+            @HostParam("vaultBaseUrl") String vaultBaseUrl, @QueryParam("api-version") String apiVersion,
+            @BodyParam("application/json") PreBackupOperationParameters preBackupOperationParameters,
+            @HeaderParam("Accept") String accept, Context context);
+
+        @Post("/prebackup")
+        @ExpectedResponses({ 202 })
+        @UnexpectedResponseExceptionType(KeyVaultErrorException.class)
+        ResponseBase preFullBackupSync(
+            @HostParam("vaultBaseUrl") String vaultBaseUrl, @QueryParam("api-version") String apiVersion,
+            @BodyParam("application/json") PreBackupOperationParameters preBackupOperationParameters,
+            @HeaderParam("Accept") String accept, Context context);
+
         @Get("/backup/{jobId}/pending")
         @ExpectedResponses({ 200 })
         @UnexpectedResponseExceptionType(KeyVaultErrorException.class)
@@ -164,6 +184,22 @@ Response fullBackupStatusSync(@HostParam("vaultBaseUrl") St
             @PathParam("jobId") String jobId, @QueryParam("api-version") String apiVersion,
             @HeaderParam("Accept") String accept, Context context);
 
+        @Put("/prerestore")
+        @ExpectedResponses({ 202 })
+        @UnexpectedResponseExceptionType(KeyVaultErrorException.class)
+        Mono> preFullRestoreOperation(
+            @HostParam("vaultBaseUrl") String vaultBaseUrl, @QueryParam("api-version") String apiVersion,
+            @BodyParam("application/json") PreRestoreOperationParameters preRestoreOperationParameters,
+            @HeaderParam("Accept") String accept, Context context);
+
+        @Put("/prerestore")
+        @ExpectedResponses({ 202 })
+        @UnexpectedResponseExceptionType(KeyVaultErrorException.class)
+        ResponseBase preFullRestoreOperationSync(
+            @HostParam("vaultBaseUrl") String vaultBaseUrl, @QueryParam("api-version") String apiVersion,
+            @BodyParam("application/json") PreRestoreOperationParameters preRestoreOperationParameters,
+            @HeaderParam("Accept") String accept, Context context);
+
         @Put("/restore")
         @ExpectedResponses({ 202 })
         @UnexpectedResponseExceptionType(KeyVaultErrorException.class)
@@ -215,7 +251,7 @@ Response restoreStatusSync(@HostParam("vaultBaseUrl") String v
 
     /**
      * Creates a full backup using a user-provided SAS token to an Azure blob storage container.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param azureStorageBlobContainerUri Azure blob shared access signature token pointing to a valid Azure blob
      * container where full backup needs to be stored. This token needs to be valid for at least next 24 hours from the
@@ -235,7 +271,7 @@ public Mono> fullBackupWith
 
     /**
      * Creates a full backup using a user-provided SAS token to an Azure blob storage container.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param azureStorageBlobContainerUri Azure blob shared access signature token pointing to a valid Azure blob
      * container where full backup needs to be stored. This token needs to be valid for at least next 24 hours from the
@@ -255,7 +291,7 @@ public Mono> fullBackupWith
 
     /**
      * Creates a full backup using a user-provided SAS token to an Azure blob storage container.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param azureStorageBlobContainerUri Azure blob shared access signature token pointing to a valid Azure blob
      * container where full backup needs to be stored. This token needs to be valid for at least next 24 hours from the
@@ -274,7 +310,7 @@ public Mono fullBackupAsync(String vaultBaseUrl,
 
     /**
      * Creates a full backup using a user-provided SAS token to an Azure blob storage container.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param azureStorageBlobContainerUri Azure blob shared access signature token pointing to a valid Azure blob
      * container where full backup needs to be stored. This token needs to be valid for at least next 24 hours from the
@@ -294,7 +330,7 @@ public Mono fullBackupAsync(String vaultBaseUrl,
 
     /**
      * Creates a full backup using a user-provided SAS token to an Azure blob storage container.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param azureStorageBlobContainerUri Azure blob shared access signature token pointing to a valid Azure blob
      * container where full backup needs to be stored. This token needs to be valid for at least next 24 hours from the
@@ -315,7 +351,7 @@ public ResponseBase fullBackupWithRespon
 
     /**
      * Creates a full backup using a user-provided SAS token to an Azure blob storage container.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param azureStorageBlobContainerUri Azure blob shared access signature token pointing to a valid Azure blob
      * container where full backup needs to be stored. This token needs to be valid for at least next 24 hours from the
@@ -330,9 +366,115 @@ public FullBackupOperation fullBackup(String vaultBaseUrl, SASTokenParameter azu
         return fullBackupWithResponse(vaultBaseUrl, azureStorageBlobContainerUri, Context.NONE).getValue();
     }
 
+    /**
+     * Pre-backup operation for checking whether the customer can perform a full backup operation.
+     *
+     * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+     * @param preBackupOperationParameters Optional parameters to validate prior to performing a full backup operation.
+     * @throws IllegalArgumentException thrown if parameters fail the validation.
+     * @throws KeyVaultErrorException thrown if the request is rejected by server.
+     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent.
+     * @return full backup operation along with {@link ResponseBase} on successful completion of {@link Mono}.
+     */
+    @ServiceMethod(returns = ReturnType.SINGLE)
+    public Mono>
+        preFullBackupWithResponseAsync(String vaultBaseUrl, PreBackupOperationParameters preBackupOperationParameters) {
+        final String accept = "application/json";
+        return FluxUtil.withContext(context -> service.preFullBackup(vaultBaseUrl, this.getApiVersion(),
+            preBackupOperationParameters, accept, context));
+    }
+
+    /**
+     * Pre-backup operation for checking whether the customer can perform a full backup operation.
+     *
+     * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+     * @param preBackupOperationParameters Optional parameters to validate prior to performing a full backup operation.
+     * @param context The context to associate with this operation.
+     * @throws IllegalArgumentException thrown if parameters fail the validation.
+     * @throws KeyVaultErrorException thrown if the request is rejected by server.
+     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent.
+     * @return full backup operation along with {@link ResponseBase} on successful completion of {@link Mono}.
+     */
+    @ServiceMethod(returns = ReturnType.SINGLE)
+    public Mono> preFullBackupWithResponseAsync(
+        String vaultBaseUrl, PreBackupOperationParameters preBackupOperationParameters, Context context) {
+        final String accept = "application/json";
+        return service.preFullBackup(vaultBaseUrl, this.getApiVersion(), preBackupOperationParameters, accept, context);
+    }
+
+    /**
+     * Pre-backup operation for checking whether the customer can perform a full backup operation.
+     *
+     * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+     * @param preBackupOperationParameters Optional parameters to validate prior to performing a full backup operation.
+     * @throws IllegalArgumentException thrown if parameters fail the validation.
+     * @throws KeyVaultErrorException thrown if the request is rejected by server.
+     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent.
+     * @return full backup operation on successful completion of {@link Mono}.
+     */
+    @ServiceMethod(returns = ReturnType.SINGLE)
+    public Mono preFullBackupAsync(String vaultBaseUrl,
+        PreBackupOperationParameters preBackupOperationParameters) {
+        return preFullBackupWithResponseAsync(vaultBaseUrl, preBackupOperationParameters)
+            .flatMap(res -> Mono.justOrEmpty(res.getValue()));
+    }
+
+    /**
+     * Pre-backup operation for checking whether the customer can perform a full backup operation.
+     *
+     * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+     * @param preBackupOperationParameters Optional parameters to validate prior to performing a full backup operation.
+     * @param context The context to associate with this operation.
+     * @throws IllegalArgumentException thrown if parameters fail the validation.
+     * @throws KeyVaultErrorException thrown if the request is rejected by server.
+     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent.
+     * @return full backup operation on successful completion of {@link Mono}.
+     */
+    @ServiceMethod(returns = ReturnType.SINGLE)
+    public Mono preFullBackupAsync(String vaultBaseUrl,
+        PreBackupOperationParameters preBackupOperationParameters, Context context) {
+        return preFullBackupWithResponseAsync(vaultBaseUrl, preBackupOperationParameters, context)
+            .flatMap(res -> Mono.justOrEmpty(res.getValue()));
+    }
+
+    /**
+     * Pre-backup operation for checking whether the customer can perform a full backup operation.
+     *
+     * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+     * @param preBackupOperationParameters Optional parameters to validate prior to performing a full backup operation.
+     * @param context The context to associate with this operation.
+     * @throws IllegalArgumentException thrown if parameters fail the validation.
+     * @throws KeyVaultErrorException thrown if the request is rejected by server.
+     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent.
+     * @return full backup operation along with {@link ResponseBase}.
+     */
+    @ServiceMethod(returns = ReturnType.SINGLE)
+    public ResponseBase preFullBackupWithResponse(String vaultBaseUrl,
+        PreBackupOperationParameters preBackupOperationParameters, Context context) {
+        final String accept = "application/json";
+        return service.preFullBackupSync(vaultBaseUrl, this.getApiVersion(), preBackupOperationParameters, accept,
+            context);
+    }
+
+    /**
+     * Pre-backup operation for checking whether the customer can perform a full backup operation.
+     *
+     * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+     * @param preBackupOperationParameters Optional parameters to validate prior to performing a full backup operation.
+     * @throws IllegalArgumentException thrown if parameters fail the validation.
+     * @throws KeyVaultErrorException thrown if the request is rejected by server.
+     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent.
+     * @return full backup operation.
+     */
+    @ServiceMethod(returns = ReturnType.SINGLE)
+    public FullBackupOperation preFullBackup(String vaultBaseUrl,
+        PreBackupOperationParameters preBackupOperationParameters) {
+        return preFullBackupWithResponse(vaultBaseUrl, preBackupOperationParameters, Context.NONE).getValue();
+    }
+
     /**
      * Returns the status of full backup operation.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param jobId The id returned as part of the backup request.
      * @throws IllegalArgumentException thrown if parameters fail the validation.
@@ -349,7 +491,7 @@ public Mono> fullBackupStatusWithResponseAsync(Str
 
     /**
      * Returns the status of full backup operation.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param jobId The id returned as part of the backup request.
      * @param context The context to associate with this operation.
@@ -367,7 +509,7 @@ public Mono> fullBackupStatusWithResponseAsync(Str
 
     /**
      * Returns the status of full backup operation.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param jobId The id returned as part of the backup request.
      * @throws IllegalArgumentException thrown if parameters fail the validation.
@@ -382,7 +524,7 @@ public Mono fullBackupStatusAsync(String vaultBaseUrl, Stri
 
     /**
      * Returns the status of full backup operation.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param jobId The id returned as part of the backup request.
      * @param context The context to associate with this operation.
@@ -399,7 +541,7 @@ public Mono fullBackupStatusAsync(String vaultBaseUrl, Stri
 
     /**
      * Returns the status of full backup operation.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param jobId The id returned as part of the backup request.
      * @param context The context to associate with this operation.
@@ -417,7 +559,7 @@ public Response fullBackupStatusWithResponse(String vaultBa
 
     /**
      * Returns the status of full backup operation.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param jobId The id returned as part of the backup request.
      * @throws IllegalArgumentException thrown if parameters fail the validation.
@@ -430,9 +572,125 @@ public FullBackupOperation fullBackupStatus(String vaultBaseUrl, String jobId) {
         return fullBackupStatusWithResponse(vaultBaseUrl, jobId, Context.NONE).getValue();
     }
 
+    /**
+     * Pre-restore operation for checking whether the customer can perform a full restore operation.
+     *
+     * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+     * @param preRestoreOperationParameters Optional pre restore parameters to validate prior to performing a full
+     * restore operation.
+     * @throws IllegalArgumentException thrown if parameters fail the validation.
+     * @throws KeyVaultErrorException thrown if the request is rejected by server.
+     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent.
+     * @return restore operation along with {@link ResponseBase} on successful completion of {@link Mono}.
+     */
+    @ServiceMethod(returns = ReturnType.SINGLE)
+    public Mono>
+        preFullRestoreOperationWithResponseAsync(String vaultBaseUrl,
+            PreRestoreOperationParameters preRestoreOperationParameters) {
+        final String accept = "application/json";
+        return FluxUtil.withContext(context -> service.preFullRestoreOperation(vaultBaseUrl, this.getApiVersion(),
+            preRestoreOperationParameters, accept, context));
+    }
+
+    /**
+     * Pre-restore operation for checking whether the customer can perform a full restore operation.
+     *
+     * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+     * @param preRestoreOperationParameters Optional pre restore parameters to validate prior to performing a full
+     * restore operation.
+     * @param context The context to associate with this operation.
+     * @throws IllegalArgumentException thrown if parameters fail the validation.
+     * @throws KeyVaultErrorException thrown if the request is rejected by server.
+     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent.
+     * @return restore operation along with {@link ResponseBase} on successful completion of {@link Mono}.
+     */
+    @ServiceMethod(returns = ReturnType.SINGLE)
+    public Mono>
+        preFullRestoreOperationWithResponseAsync(String vaultBaseUrl,
+            PreRestoreOperationParameters preRestoreOperationParameters, Context context) {
+        final String accept = "application/json";
+        return service.preFullRestoreOperation(vaultBaseUrl, this.getApiVersion(), preRestoreOperationParameters,
+            accept, context);
+    }
+
+    /**
+     * Pre-restore operation for checking whether the customer can perform a full restore operation.
+     *
+     * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+     * @param preRestoreOperationParameters Optional pre restore parameters to validate prior to performing a full
+     * restore operation.
+     * @throws IllegalArgumentException thrown if parameters fail the validation.
+     * @throws KeyVaultErrorException thrown if the request is rejected by server.
+     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent.
+     * @return restore operation on successful completion of {@link Mono}.
+     */
+    @ServiceMethod(returns = ReturnType.SINGLE)
+    public Mono preFullRestoreOperationAsync(String vaultBaseUrl,
+        PreRestoreOperationParameters preRestoreOperationParameters) {
+        return preFullRestoreOperationWithResponseAsync(vaultBaseUrl, preRestoreOperationParameters)
+            .flatMap(res -> Mono.justOrEmpty(res.getValue()));
+    }
+
+    /**
+     * Pre-restore operation for checking whether the customer can perform a full restore operation.
+     *
+     * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+     * @param preRestoreOperationParameters Optional pre restore parameters to validate prior to performing a full
+     * restore operation.
+     * @param context The context to associate with this operation.
+     * @throws IllegalArgumentException thrown if parameters fail the validation.
+     * @throws KeyVaultErrorException thrown if the request is rejected by server.
+     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent.
+     * @return restore operation on successful completion of {@link Mono}.
+     */
+    @ServiceMethod(returns = ReturnType.SINGLE)
+    public Mono preFullRestoreOperationAsync(String vaultBaseUrl,
+        PreRestoreOperationParameters preRestoreOperationParameters, Context context) {
+        return preFullRestoreOperationWithResponseAsync(vaultBaseUrl, preRestoreOperationParameters, context)
+            .flatMap(res -> Mono.justOrEmpty(res.getValue()));
+    }
+
+    /**
+     * Pre-restore operation for checking whether the customer can perform a full restore operation.
+     *
+     * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+     * @param preRestoreOperationParameters Optional pre restore parameters to validate prior to performing a full
+     * restore operation.
+     * @param context The context to associate with this operation.
+     * @throws IllegalArgumentException thrown if parameters fail the validation.
+     * @throws KeyVaultErrorException thrown if the request is rejected by server.
+     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent.
+     * @return restore operation along with {@link ResponseBase}.
+     */
+    @ServiceMethod(returns = ReturnType.SINGLE)
+    public ResponseBase preFullRestoreOperationWithResponse(
+        String vaultBaseUrl, PreRestoreOperationParameters preRestoreOperationParameters, Context context) {
+        final String accept = "application/json";
+        return service.preFullRestoreOperationSync(vaultBaseUrl, this.getApiVersion(), preRestoreOperationParameters,
+            accept, context);
+    }
+
+    /**
+     * Pre-restore operation for checking whether the customer can perform a full restore operation.
+     *
+     * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+     * @param preRestoreOperationParameters Optional pre restore parameters to validate prior to performing a full
+     * restore operation.
+     * @throws IllegalArgumentException thrown if parameters fail the validation.
+     * @throws KeyVaultErrorException thrown if the request is rejected by server.
+     * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent.
+     * @return restore operation.
+     */
+    @ServiceMethod(returns = ReturnType.SINGLE)
+    public RestoreOperation preFullRestoreOperation(String vaultBaseUrl,
+        PreRestoreOperationParameters preRestoreOperationParameters) {
+        return preFullRestoreOperationWithResponse(vaultBaseUrl, preRestoreOperationParameters, Context.NONE)
+            .getValue();
+    }
+
     /**
      * Restores all key materials using the SAS token pointing to a previously stored Azure Blob storage backup folder.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param restoreBlobDetails The Azure blob SAS token pointing to a folder where the previous successful full backup
      * was stored.
@@ -451,7 +709,7 @@ public FullBackupOperation fullBackupStatus(String vaultBaseUrl, String jobId) {
 
     /**
      * Restores all key materials using the SAS token pointing to a previously stored Azure Blob storage backup folder.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param restoreBlobDetails The Azure blob SAS token pointing to a folder where the previous successful full backup
      * was stored.
@@ -470,7 +728,7 @@ public Mono> fullRes
 
     /**
      * Restores all key materials using the SAS token pointing to a previously stored Azure Blob storage backup folder.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param restoreBlobDetails The Azure blob SAS token pointing to a folder where the previous successful full backup
      * was stored.
@@ -488,7 +746,7 @@ public Mono fullRestoreOperationAsync(String vaultBaseUrl,
 
     /**
      * Restores all key materials using the SAS token pointing to a previously stored Azure Blob storage backup folder.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param restoreBlobDetails The Azure blob SAS token pointing to a folder where the previous successful full backup
      * was stored.
@@ -507,7 +765,7 @@ public Mono fullRestoreOperationAsync(String vaultBaseUrl,
 
     /**
      * Restores all key materials using the SAS token pointing to a previously stored Azure Blob storage backup folder.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param restoreBlobDetails The Azure blob SAS token pointing to a folder where the previous successful full backup
      * was stored.
@@ -527,7 +785,7 @@ public ResponseBase fullRestoreOp
 
     /**
      * Restores all key materials using the SAS token pointing to a previously stored Azure Blob storage backup folder.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param restoreBlobDetails The Azure blob SAS token pointing to a folder where the previous successful full backup
      * was stored.
@@ -543,7 +801,7 @@ public RestoreOperation fullRestoreOperation(String vaultBaseUrl, RestoreOperati
 
     /**
      * Returns the status of restore operation.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param jobId The Job Id returned part of the restore operation.
      * @throws IllegalArgumentException thrown if parameters fail the validation.
@@ -560,7 +818,7 @@ public Mono> restoreStatusWithResponseAsync(String va
 
     /**
      * Returns the status of restore operation.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param jobId The Job Id returned part of the restore operation.
      * @param context The context to associate with this operation.
@@ -578,7 +836,7 @@ public Mono> restoreStatusWithResponseAsync(String va
 
     /**
      * Returns the status of restore operation.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param jobId The Job Id returned part of the restore operation.
      * @throws IllegalArgumentException thrown if parameters fail the validation.
@@ -593,7 +851,7 @@ public Mono restoreStatusAsync(String vaultBaseUrl, String job
 
     /**
      * Returns the status of restore operation.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param jobId The Job Id returned part of the restore operation.
      * @param context The context to associate with this operation.
@@ -610,7 +868,7 @@ public Mono restoreStatusAsync(String vaultBaseUrl, String job
 
     /**
      * Returns the status of restore operation.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param jobId The Job Id returned part of the restore operation.
      * @param context The context to associate with this operation.
@@ -627,7 +885,7 @@ public Response restoreStatusWithResponse(String vaultBaseUrl,
 
     /**
      * Returns the status of restore operation.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param jobId The Job Id returned part of the restore operation.
      * @throws IllegalArgumentException thrown if parameters fail the validation.
@@ -643,7 +901,7 @@ public RestoreOperation restoreStatus(String vaultBaseUrl, String jobId) {
     /**
      * Restores all key versions of a given key using user supplied SAS token pointing to a previously stored Azure Blob
      * storage backup folder.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param keyName The name of the key to be restored from the user supplied backup.
      * @param restoreBlobDetails The Azure blob SAS token pointing to a folder where the previous successful full backup
@@ -665,7 +923,7 @@ public RestoreOperation restoreStatus(String vaultBaseUrl, String jobId) {
     /**
      * Restores all key versions of a given key using user supplied SAS token pointing to a previously stored Azure Blob
      * storage backup folder.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param keyName The name of the key to be restored from the user supplied backup.
      * @param restoreBlobDetails The Azure blob SAS token pointing to a folder where the previous successful full backup
@@ -688,7 +946,7 @@ public RestoreOperation restoreStatus(String vaultBaseUrl, String jobId) {
     /**
      * Restores all key versions of a given key using user supplied SAS token pointing to a previously stored Azure Blob
      * storage backup folder.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param keyName The name of the key to be restored from the user supplied backup.
      * @param restoreBlobDetails The Azure blob SAS token pointing to a folder where the previous successful full backup
@@ -708,7 +966,7 @@ public Mono selectiveKeyRestoreOperationAsync(Stri
     /**
      * Restores all key versions of a given key using user supplied SAS token pointing to a previously stored Azure Blob
      * storage backup folder.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param keyName The name of the key to be restored from the user supplied backup.
      * @param restoreBlobDetails The Azure blob SAS token pointing to a folder where the previous successful full backup
@@ -729,7 +987,7 @@ public Mono selectiveKeyRestoreOperationAsync(Stri
     /**
      * Restores all key versions of a given key using user supplied SAS token pointing to a previously stored Azure Blob
      * storage backup folder.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param keyName The name of the key to be restored from the user supplied backup.
      * @param restoreBlobDetails The Azure blob SAS token pointing to a folder where the previous successful full backup
@@ -752,7 +1010,7 @@ public Mono selectiveKeyRestoreOperationAsync(Stri
     /**
      * Restores all key versions of a given key using user supplied SAS token pointing to a previously stored Azure Blob
      * storage backup folder.
-     * 
+     *
      * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
      * @param keyName The name of the key to be restored from the user supplied backup.
      * @param restoreBlobDetails The Azure blob SAS token pointing to a folder where the previous successful full backup
diff --git a/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/implementation/models/PreBackupOperationParameters.java b/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/implementation/models/PreBackupOperationParameters.java
new file mode 100644
index 000000000000..c8a6be3a6278
--- /dev/null
+++ b/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/implementation/models/PreBackupOperationParameters.java
@@ -0,0 +1,144 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+// Code generated by Microsoft (R) AutoRest Code Generator.
+
+package com.azure.security.keyvault.administration.implementation.models;
+
+import com.azure.core.annotation.Fluent;
+import com.azure.json.JsonReader;
+import com.azure.json.JsonSerializable;
+import com.azure.json.JsonToken;
+import com.azure.json.JsonWriter;
+import java.io.IOException;
+
+/**
+ * The PreBackupOperationParameters model.
+ */
+@Fluent
+public final class PreBackupOperationParameters implements JsonSerializable {
+    /*
+     * Azure Blob storage container Uri
+     */
+    private String storageResourceUri;
+
+    /*
+     * The SAS token pointing to an Azure Blob storage container
+     */
+    private String token;
+
+    /*
+     * Indicates which authentication method should be used. If set to true, Managed HSM will use the configured
+     * user-assigned managed identity to authenticate with Azure Storage. Otherwise, a SAS token has to be specified.
+     */
+    private Boolean useManagedIdentity;
+
+    /**
+     * Creates an instance of PreBackupOperationParameters class.
+     */
+    public PreBackupOperationParameters() {
+    }
+
+    /**
+     * Get the storageResourceUri property: Azure Blob storage container Uri.
+     *
+     * @return the storageResourceUri value.
+     */
+    public String getStorageResourceUri() {
+        return this.storageResourceUri;
+    }
+
+    /**
+     * Set the storageResourceUri property: Azure Blob storage container Uri.
+     *
+     * @param storageResourceUri the storageResourceUri value to set.
+     * @return the PreBackupOperationParameters object itself.
+     */
+    public PreBackupOperationParameters setStorageResourceUri(String storageResourceUri) {
+        this.storageResourceUri = storageResourceUri;
+        return this;
+    }
+
+    /**
+     * Get the token property: The SAS token pointing to an Azure Blob storage container.
+     *
+     * @return the token value.
+     */
+    public String getToken() {
+        return this.token;
+    }
+
+    /**
+     * Set the token property: The SAS token pointing to an Azure Blob storage container.
+     *
+     * @param token the token value to set.
+     * @return the PreBackupOperationParameters object itself.
+     */
+    public PreBackupOperationParameters setToken(String token) {
+        this.token = token;
+        return this;
+    }
+
+    /**
+     * Get the useManagedIdentity property: Indicates which authentication method should be used. If set to true,
+     * Managed HSM will use the configured user-assigned managed identity to authenticate with Azure Storage.
+     * Otherwise, a SAS token has to be specified.
+     *
+     * @return the useManagedIdentity value.
+     */
+    public Boolean isUseManagedIdentity() {
+        return this.useManagedIdentity;
+    }
+
+    /**
+     * Set the useManagedIdentity property: Indicates which authentication method should be used. If set to true,
+     * Managed HSM will use the configured user-assigned managed identity to authenticate with Azure Storage.
+     * Otherwise, a SAS token has to be specified.
+     *
+     * @param useManagedIdentity the useManagedIdentity value to set.
+     * @return the PreBackupOperationParameters object itself.
+     */
+    public PreBackupOperationParameters setUseManagedIdentity(Boolean useManagedIdentity) {
+        this.useManagedIdentity = useManagedIdentity;
+        return this;
+    }
+
+    @Override
+    public JsonWriter toJson(JsonWriter jsonWriter) throws IOException {
+        jsonWriter.writeStartObject();
+        jsonWriter.writeStringField("storageResourceUri", this.storageResourceUri);
+        jsonWriter.writeStringField("token", this.token);
+        jsonWriter.writeBooleanField("useManagedIdentity", this.useManagedIdentity);
+        return jsonWriter.writeEndObject();
+    }
+
+    /**
+     * Reads an instance of PreBackupOperationParameters from the JsonReader.
+     *
+     * @param jsonReader The JsonReader being read.
+     * @return An instance of PreBackupOperationParameters if the JsonReader was pointing to an instance of it, or null
+     * if it was pointing to JSON null.
+     * @throws IOException If an error occurs while reading the PreBackupOperationParameters.
+     */
+    public static PreBackupOperationParameters fromJson(JsonReader jsonReader) throws IOException {
+        return jsonReader.readObject(reader -> {
+            PreBackupOperationParameters deserializedPreBackupOperationParameters = new PreBackupOperationParameters();
+            while (reader.nextToken() != JsonToken.END_OBJECT) {
+                String fieldName = reader.getFieldName();
+                reader.nextToken();
+
+                if ("storageResourceUri".equals(fieldName)) {
+                    deserializedPreBackupOperationParameters.storageResourceUri = reader.getString();
+                } else if ("token".equals(fieldName)) {
+                    deserializedPreBackupOperationParameters.token = reader.getString();
+                } else if ("useManagedIdentity".equals(fieldName)) {
+                    deserializedPreBackupOperationParameters.useManagedIdentity
+                        = reader.getNullable(JsonReader::getBoolean);
+                } else {
+                    reader.skipChildren();
+                }
+            }
+
+            return deserializedPreBackupOperationParameters;
+        });
+    }
+}
diff --git a/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/implementation/models/PreFullBackupHeaders.java b/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/implementation/models/PreFullBackupHeaders.java
new file mode 100644
index 000000000000..9a2f0a0902ba
--- /dev/null
+++ b/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/implementation/models/PreFullBackupHeaders.java
@@ -0,0 +1,81 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+// Code generated by Microsoft (R) AutoRest Code Generator.
+
+package com.azure.security.keyvault.administration.implementation.models;
+
+import com.azure.core.annotation.Fluent;
+import com.azure.core.http.HttpHeaderName;
+import com.azure.core.http.HttpHeaders;
+
+/**
+ * The PreFullBackupHeaders model.
+ */
+@Fluent
+public final class PreFullBackupHeaders {
+    /*
+     * The Retry-After property.
+     */
+    private Long retryAfter;
+
+    /*
+     * The Azure-AsyncOperation property.
+     */
+    private String azureAsyncOperation;
+
+    private static final HttpHeaderName AZURE_ASYNC_OPERATION = HttpHeaderName.fromString("Azure-AsyncOperation");
+
+    // HttpHeaders containing the raw property values.
+    /**
+     * Creates an instance of PreFullBackupHeaders class.
+     *
+     * @param rawHeaders The raw HttpHeaders that will be used to create the property values.
+     */
+    public PreFullBackupHeaders(HttpHeaders rawHeaders) {
+        String retryAfter = rawHeaders.getValue(HttpHeaderName.RETRY_AFTER);
+        if (retryAfter != null) {
+            this.retryAfter = Long.parseLong(retryAfter);
+        }
+        this.azureAsyncOperation = rawHeaders.getValue(AZURE_ASYNC_OPERATION);
+    }
+
+    /**
+     * Get the retryAfter property: The Retry-After property.
+     *
+     * @return the retryAfter value.
+     */
+    public Long getRetryAfter() {
+        return this.retryAfter;
+    }
+
+    /**
+     * Set the retryAfter property: The Retry-After property.
+     *
+     * @param retryAfter the retryAfter value to set.
+     * @return the PreFullBackupHeaders object itself.
+     */
+    public PreFullBackupHeaders setRetryAfter(Long retryAfter) {
+        this.retryAfter = retryAfter;
+        return this;
+    }
+
+    /**
+     * Get the azureAsyncOperation property: The Azure-AsyncOperation property.
+     *
+     * @return the azureAsyncOperation value.
+     */
+    public String getAzureAsyncOperation() {
+        return this.azureAsyncOperation;
+    }
+
+    /**
+     * Set the azureAsyncOperation property: The Azure-AsyncOperation property.
+     *
+     * @param azureAsyncOperation the azureAsyncOperation value to set.
+     * @return the PreFullBackupHeaders object itself.
+     */
+    public PreFullBackupHeaders setAzureAsyncOperation(String azureAsyncOperation) {
+        this.azureAsyncOperation = azureAsyncOperation;
+        return this;
+    }
+}
diff --git a/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/implementation/models/PreFullRestoreOperationHeaders.java b/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/implementation/models/PreFullRestoreOperationHeaders.java
new file mode 100644
index 000000000000..4a44da9e1280
--- /dev/null
+++ b/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/implementation/models/PreFullRestoreOperationHeaders.java
@@ -0,0 +1,81 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+// Code generated by Microsoft (R) AutoRest Code Generator.
+
+package com.azure.security.keyvault.administration.implementation.models;
+
+import com.azure.core.annotation.Fluent;
+import com.azure.core.http.HttpHeaderName;
+import com.azure.core.http.HttpHeaders;
+
+/**
+ * The PreFullRestoreOperationHeaders model.
+ */
+@Fluent
+public final class PreFullRestoreOperationHeaders {
+    /*
+     * The Retry-After property.
+     */
+    private Long retryAfter;
+
+    /*
+     * The Azure-AsyncOperation property.
+     */
+    private String azureAsyncOperation;
+
+    private static final HttpHeaderName AZURE_ASYNC_OPERATION = HttpHeaderName.fromString("Azure-AsyncOperation");
+
+    // HttpHeaders containing the raw property values.
+    /**
+     * Creates an instance of PreFullRestoreOperationHeaders class.
+     *
+     * @param rawHeaders The raw HttpHeaders that will be used to create the property values.
+     */
+    public PreFullRestoreOperationHeaders(HttpHeaders rawHeaders) {
+        String retryAfter = rawHeaders.getValue(HttpHeaderName.RETRY_AFTER);
+        if (retryAfter != null) {
+            this.retryAfter = Long.parseLong(retryAfter);
+        }
+        this.azureAsyncOperation = rawHeaders.getValue(AZURE_ASYNC_OPERATION);
+    }
+
+    /**
+     * Get the retryAfter property: The Retry-After property.
+     *
+     * @return the retryAfter value.
+     */
+    public Long getRetryAfter() {
+        return this.retryAfter;
+    }
+
+    /**
+     * Set the retryAfter property: The Retry-After property.
+     *
+     * @param retryAfter the retryAfter value to set.
+     * @return the PreFullRestoreOperationHeaders object itself.
+     */
+    public PreFullRestoreOperationHeaders setRetryAfter(Long retryAfter) {
+        this.retryAfter = retryAfter;
+        return this;
+    }
+
+    /**
+     * Get the azureAsyncOperation property: The Azure-AsyncOperation property.
+     *
+     * @return the azureAsyncOperation value.
+     */
+    public String getAzureAsyncOperation() {
+        return this.azureAsyncOperation;
+    }
+
+    /**
+     * Set the azureAsyncOperation property: The Azure-AsyncOperation property.
+     *
+     * @param azureAsyncOperation the azureAsyncOperation value to set.
+     * @return the PreFullRestoreOperationHeaders object itself.
+     */
+    public PreFullRestoreOperationHeaders setAzureAsyncOperation(String azureAsyncOperation) {
+        this.azureAsyncOperation = azureAsyncOperation;
+        return this;
+    }
+}
diff --git a/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/implementation/models/PreRestoreOperationParameters.java b/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/implementation/models/PreRestoreOperationParameters.java
new file mode 100644
index 000000000000..a720ab06700d
--- /dev/null
+++ b/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/implementation/models/PreRestoreOperationParameters.java
@@ -0,0 +1,113 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+// Code generated by Microsoft (R) AutoRest Code Generator.
+
+package com.azure.security.keyvault.administration.implementation.models;
+
+import com.azure.core.annotation.Fluent;
+import com.azure.json.JsonReader;
+import com.azure.json.JsonSerializable;
+import com.azure.json.JsonToken;
+import com.azure.json.JsonWriter;
+import java.io.IOException;
+
+/**
+ * The PreRestoreOperationParameters model.
+ */
+@Fluent
+public final class PreRestoreOperationParameters implements JsonSerializable {
+    /*
+     * The sasTokenParameters property.
+     */
+    private SASTokenParameter sasTokenParameters;
+
+    /*
+     * The Folder name of the blob where the previous successful full backup was stored
+     */
+    private String folderToRestore;
+
+    /**
+     * Creates an instance of PreRestoreOperationParameters class.
+     */
+    public PreRestoreOperationParameters() {
+    }
+
+    /**
+     * Get the sasTokenParameters property: The sasTokenParameters property.
+     *
+     * @return the sasTokenParameters value.
+     */
+    public SASTokenParameter getSasTokenParameters() {
+        return this.sasTokenParameters;
+    }
+
+    /**
+     * Set the sasTokenParameters property: The sasTokenParameters property.
+     *
+     * @param sasTokenParameters the sasTokenParameters value to set.
+     * @return the PreRestoreOperationParameters object itself.
+     */
+    public PreRestoreOperationParameters setSasTokenParameters(SASTokenParameter sasTokenParameters) {
+        this.sasTokenParameters = sasTokenParameters;
+        return this;
+    }
+
+    /**
+     * Get the folderToRestore property: The Folder name of the blob where the previous successful full backup was
+     * stored.
+     *
+     * @return the folderToRestore value.
+     */
+    public String getFolderToRestore() {
+        return this.folderToRestore;
+    }
+
+    /**
+     * Set the folderToRestore property: The Folder name of the blob where the previous successful full backup was
+     * stored.
+     *
+     * @param folderToRestore the folderToRestore value to set.
+     * @return the PreRestoreOperationParameters object itself.
+     */
+    public PreRestoreOperationParameters setFolderToRestore(String folderToRestore) {
+        this.folderToRestore = folderToRestore;
+        return this;
+    }
+
+    @Override
+    public JsonWriter toJson(JsonWriter jsonWriter) throws IOException {
+        jsonWriter.writeStartObject();
+        jsonWriter.writeJsonField("sasTokenParameters", this.sasTokenParameters);
+        jsonWriter.writeStringField("folderToRestore", this.folderToRestore);
+        return jsonWriter.writeEndObject();
+    }
+
+    /**
+     * Reads an instance of PreRestoreOperationParameters from the JsonReader.
+     *
+     * @param jsonReader The JsonReader being read.
+     * @return An instance of PreRestoreOperationParameters if the JsonReader was pointing to an instance of it, or null
+     * if it was pointing to JSON null.
+     * @throws IOException If an error occurs while reading the PreRestoreOperationParameters.
+     */
+    public static PreRestoreOperationParameters fromJson(JsonReader jsonReader) throws IOException {
+        return jsonReader.readObject(reader -> {
+            PreRestoreOperationParameters deserializedPreRestoreOperationParameters
+                = new PreRestoreOperationParameters();
+            while (reader.nextToken() != JsonToken.END_OBJECT) {
+                String fieldName = reader.getFieldName();
+                reader.nextToken();
+
+                if ("sasTokenParameters".equals(fieldName)) {
+                    deserializedPreRestoreOperationParameters.sasTokenParameters = SASTokenParameter.fromJson(reader);
+                } else if ("folderToRestore".equals(fieldName)) {
+                    deserializedPreRestoreOperationParameters.folderToRestore = reader.getString();
+                } else {
+                    reader.skipChildren();
+                }
+            }
+
+            return deserializedPreRestoreOperationParameters;
+        });
+    }
+}
diff --git a/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/package-info.java b/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/package-info.java
index 1132a91286a5..b753f047dcb9 100644
--- a/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/package-info.java
+++ b/sdk/keyvault/azure-security-keyvault-administration/src/main/java/com/azure/security/keyvault/administration/package-info.java
@@ -312,6 +312,45 @@
  * com.azure.security.keyvault.administration.KeyVaultAccessControlAsyncClient}. 
*
* + *

Run Pre-Backup Check for a Collection of Keys

+ * + * The {@link com.azure.security.keyvault.administration.KeyVaultBackupClient} can be used to check if it is possible to + * back up the entire collection of keys from a key vault. + * + *

+ * Code Sample: + * + *

+ * The following code sample demonstrates how to synchronously check if it is possible to back up an entire collection + * of keys, using the + * {@link com.azure.security.keyvault.administration.KeyVaultBackupClient#beginPreBackup(String, String)} API. + * + *

+ * String blobStorageUrl = "https://myaccount.blob.core.windows.net/myContainer";
+ * String sasToken = "<sas-token>";
+ *
+ * SyncPoller<KeyVaultBackupOperation, String> preBackupPoller = client.beginPreBackup(blobStorageUrl, sasToken);
+ * PollResponse<KeyVaultBackupOperation> pollResponse = preBackupPoller.poll();
+ *
+ * System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus());
+ *
+ * PollResponse<KeyVaultBackupOperation> finalPollResponse = preBackupPoller.waitForCompletion();
+ *
+ * if (finalPollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED) {
+ *     System.out.printf("Pre-backup check completed successfully.%n");
+ * } else {
+ *     KeyVaultBackupOperation operation = preBackupPoller.poll().getValue();
+ *
+ *     System.out.printf("Pre-backup check failed with error: %s.%n", operation.getError().getMessage());
+ * }
+ * 
+ * + * + *

+ * Note: For the asynchronous sample, refer to {@link + * com.azure.security.keyvault.administration.KeyVaultBackupAsyncClient}.
+ *


+ * *

Back Up a Collection of Keys

* * The {@link com.azure.security.keyvault.administration.KeyVaultBackupClient} can be used to back up the entire @@ -326,11 +365,9 @@ * *
  * String blobStorageUrl = "https://myaccount.blob.core.windows.net/myContainer";
- * String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z"
- *     + "&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D";
+ * String sasToken = "<sas-token>";
  *
  * SyncPoller<KeyVaultBackupOperation, String> backupPoller = client.beginBackup(blobStorageUrl, sasToken);
- *
  * PollResponse<KeyVaultBackupOperation> pollResponse = backupPoller.poll();
  *
  * System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus());
@@ -354,6 +391,46 @@
  * com.azure.security.keyvault.administration.KeyVaultBackupAsyncClient}. 
*
* + *

Run Pre-Restore Check for a Collection of Keys

+ * + * The {@link com.azure.security.keyvault.administration.KeyVaultBackupClient} can be used to check if it is possible to + * restore an entire collection of keys from a backup. + * + *

+ * Code Sample: + * + *

+ * The following code sample demonstrates how to synchronously check if it is possible to restore an entire collection + * of keys from a backup, using the + * {@link com.azure.security.keyvault.administration.KeyVaultBackupClient#beginPreRestore(String, String)} API. + * + *

+ * String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313";
+ * String sasToken = "<sas-token>";
+ *
+ * SyncPoller<KeyVaultRestoreOperation, KeyVaultRestoreResult> preRestorePoller =
+ *     client.beginPreRestore(folderUrl, sasToken);
+ * PollResponse<KeyVaultRestoreOperation> pollResponse = preRestorePoller.poll();
+ *
+ * System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus());
+ *
+ * PollResponse<KeyVaultRestoreOperation> finalPollResponse = preRestorePoller.waitForCompletion();
+ *
+ * if (finalPollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED) {
+ *     System.out.printf("Pre-restore check completed successfully.%n");
+ * } else {
+ *     KeyVaultRestoreOperation operation = preRestorePoller.poll().getValue();
+ *
+ *     System.out.printf("Pre-restore check failed with error: %s.%n", operation.getError().getMessage());
+ * }
+ * 
+ * + * + *

+ * Note: For the asynchronous sample, refer to {@link + * com.azure.security.keyvault.administration.KeyVaultBackupAsyncClient}.
+ *


+ * *

Restore a Collection of Keys

* * The {@link com.azure.security.keyvault.administration.KeyVaultBackupClient} can be used to restore an entire @@ -368,22 +445,20 @@ * *
  * String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313";
- * String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z"
- *     + "&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D";
+ * String sasToken = "<sas-token>";
  *
- * SyncPoller<KeyVaultRestoreOperation, KeyVaultRestoreResult> backupPoller =
+ * SyncPoller<KeyVaultRestoreOperation, KeyVaultRestoreResult> restorePoller =
  *     client.beginRestore(folderUrl, sasToken);
- *
- * PollResponse<KeyVaultRestoreOperation> pollResponse = backupPoller.poll();
+ * PollResponse<KeyVaultRestoreOperation> pollResponse = restorePoller.poll();
  *
  * System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus());
  *
- * PollResponse<KeyVaultRestoreOperation> finalPollResponse = backupPoller.waitForCompletion();
+ * PollResponse<KeyVaultRestoreOperation> finalPollResponse = restorePoller.waitForCompletion();
  *
  * if (finalPollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED) {
  *     System.out.printf("Backup restored successfully.%n");
  * } else {
- *     KeyVaultRestoreOperation operation = backupPoller.poll().getValue();
+ *     KeyVaultRestoreOperation operation = restorePoller.poll().getValue();
  *
  *     System.out.printf("Restore failed with error: %s.%n", operation.getError().getMessage());
  * }
diff --git a/sdk/keyvault/azure-security-keyvault-administration/src/samples/java/com/azure/security/keyvault/administration/ReadmeSamples.java b/sdk/keyvault/azure-security-keyvault-administration/src/samples/java/com/azure/security/keyvault/administration/ReadmeSamples.java
index 7fa3c2c0dad7..f7d0108edc7a 100644
--- a/sdk/keyvault/azure-security-keyvault-administration/src/samples/java/com/azure/security/keyvault/administration/ReadmeSamples.java
+++ b/sdk/keyvault/azure-security-keyvault-administration/src/samples/java/com/azure/security/keyvault/administration/ReadmeSamples.java
@@ -293,17 +293,44 @@ public void createBackupClient() {
         // END: readme-sample-createBackupClient
     }
 
+    /**
+     * Code sample for starting a {@link KeyVaultBackupOperation pre-backup check}.
+     */
+    public void beginPreBackup() {
+        // BEGIN: readme-sample-beginPreBackup
+        String blobStorageUrl = "https://myaccount.blob.core.windows.net/myContainer";
+        String sasToken = "";
+
+        SyncPoller preBackupPoller =
+            keyVaultBackupClient.beginPreBackup(blobStorageUrl, sasToken);
+        PollResponse pollResponse = preBackupPoller.poll();
+
+        System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus());
+
+        PollResponse finalPollResponse = preBackupPoller.waitForCompletion();
+
+        if (finalPollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED) {
+            String folderUrl = preBackupPoller.getFinalResult();
+
+            System.out.printf("Pre-backup check completed successfully.%n");
+        } else {
+            KeyVaultBackupOperation operation = preBackupPoller.poll().getValue();
+
+            System.out.printf("Pre-backup check failed with error: %s.%n", operation.getError().getMessage());
+        }
+        // END: readme-sample-beginPreBackup
+    }
+
     /**
      * Code sample for starting a {@link KeyVaultBackupOperation backup operation}.
      */
     public void beginBackup() {
         // BEGIN: readme-sample-beginBackup
         String blobStorageUrl = "https://myaccount.blob.core.windows.net/myContainer";
-        String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D";
+        String sasToken = "";
 
         SyncPoller backupPoller =
             keyVaultBackupClient.beginBackup(blobStorageUrl, sasToken);
-
         PollResponse pollResponse = backupPoller.poll();
 
         System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus());
@@ -322,27 +349,52 @@ public void beginBackup() {
         // END: readme-sample-beginBackup
     }
 
+    /**
+     * Code sample for starting a {@link KeyVaultRestoreOperation pre-restore check}.
+     */
+    public void beginPreRestore() {
+        // BEGIN: readme-sample-beginPreRestore
+        String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313";
+        String sasToken = "";
+
+        SyncPoller preRestorePoller =
+            keyVaultBackupClient.beginPreRestore(folderUrl, sasToken);
+        PollResponse pollResponse = preRestorePoller.poll();
+
+        System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus());
+
+        PollResponse finalPollResponse = preRestorePoller.waitForCompletion();
+
+        if (finalPollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED) {
+            System.out.printf("Pre-restore check completed successfully.%n");
+        } else {
+            KeyVaultRestoreOperation operation = preRestorePoller.poll().getValue();
+
+            System.out.printf("Pre-restore check failed with error: %s.%n", operation.getError().getMessage());
+        }
+        // END: readme-sample-beginPreRestore
+    }
+
     /**
      * Code sample for starting a {@link KeyVaultRestoreOperation restore operation}.
      */
     public void beginRestore() {
         // BEGIN: readme-sample-beginRestore
         String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313";
-        String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D";
+        String sasToken = "";
 
-        SyncPoller backupPoller =
+        SyncPoller restorePoller =
             keyVaultBackupClient.beginRestore(folderUrl, sasToken);
-
-        PollResponse pollResponse = backupPoller.poll();
+        PollResponse pollResponse = restorePoller.poll();
 
         System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus());
 
-        PollResponse finalPollResponse = backupPoller.waitForCompletion();
+        PollResponse finalPollResponse = restorePoller.waitForCompletion();
 
         if (finalPollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED) {
             System.out.printf("Backup restored successfully.%n");
         } else {
-            KeyVaultRestoreOperation operation = backupPoller.poll().getValue();
+            KeyVaultRestoreOperation operation = restorePoller.poll().getValue();
 
             System.out.printf("Restore failed with error: %s.%n", operation.getError().getMessage());
         }
@@ -355,35 +407,54 @@ public void beginRestore() {
     public void beginSelectiveKeyRestore() {
         // BEGIN: readme-sample-beginSelectiveKeyRestore
         String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313";
-        String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D";
+        String sasToken = "";
         String keyName = "myKey";
 
-        SyncPoller backupPoller =
+        SyncPoller restorePoller =
             keyVaultBackupClient.beginSelectiveKeyRestore(folderUrl, sasToken, keyName);
-
-        PollResponse pollResponse = backupPoller.poll();
+        PollResponse pollResponse = restorePoller.poll();
 
         System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus());
 
-        PollResponse finalPollResponse = backupPoller.waitForCompletion();
+        PollResponse finalPollResponse = restorePoller.waitForCompletion();
 
         if (finalPollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED) {
             System.out.printf("Key restored successfully.%n");
         } else {
-            KeyVaultSelectiveKeyRestoreOperation operation = backupPoller.poll().getValue();
+            KeyVaultSelectiveKeyRestoreOperation operation = restorePoller.poll().getValue();
 
             System.out.printf("Key restore failed with error: %s.%n", operation.getError().getMessage());
         }
         // END: readme-sample-beginSelectiveKeyRestore
     }
 
+    /**
+     * Code sample for starting a {@link KeyVaultBackupOperation pre-backup check} asynchronously.
+     */
+    public void beginPreBackupAsync() {
+        // BEGIN: readme-sample-beginPreBackupAsync
+        String blobStorageUrl = "https://myaccount.blob.core.windows.net/myContainer";
+        String sasToken = "";
+
+        keyVaultBackupAsyncClient.beginPreBackup(blobStorageUrl, sasToken)
+            .setPollInterval(Duration.ofSeconds(1)) // You can set a custom polling interval.
+            .doOnError(e -> System.out.printf("Pre-backup check failed with error: %s.%n", e.getMessage()))
+            .doOnNext(pollResponse ->
+                System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus()))
+            .filter(pollResponse -> pollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED)
+            .flatMap(AsyncPollResponse::getFinalResult)
+            .subscribe(folderUrl ->
+                System.out.printf("Pre-backup check completed successfully.%n"));
+        // END: readme-sample-beginPreBackupAsync
+    }
+
     /**
      * Code sample for starting a {@link KeyVaultBackupOperation backup operation} asynchronously.
      */
     public void beginBackupAsync() {
         // BEGIN: readme-sample-beginBackupAsync
         String blobStorageUrl = "https://myaccount.blob.core.windows.net/myContainer";
-        String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D";
+        String sasToken = "";
 
         keyVaultBackupAsyncClient.beginBackup(blobStorageUrl, sasToken)
             .setPollInterval(Duration.ofSeconds(1)) // You can set a custom polling interval.
@@ -397,13 +468,32 @@ public void beginBackupAsync() {
         // END: readme-sample-beginBackupAsync
     }
 
+    /**
+     * Code sample for starting a {@link KeyVaultRestoreOperation pre-restore check} asynchronously.
+     */
+    public void beginPreRestoreAsync() {
+        // BEGIN: readme-sample-beginPreRestoreAsync
+        String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313";
+        String sasToken = "";
+
+        keyVaultBackupAsyncClient.beginPreRestore(folderUrl, sasToken)
+            .setPollInterval(Duration.ofSeconds(1)) // You can set a custom polling interval.
+            .doOnError(e -> System.out.printf("Pre-restore check failed with error: %s.%n", e.getMessage()))
+            .doOnNext(pollResponse ->
+                System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus()))
+            .filter(pollResponse -> pollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED)
+            .flatMap(AsyncPollResponse::getFinalResult)
+            .subscribe(unused -> System.out.printf("Pre-restore check completed successfully.%n"));
+        // END: readme-sample-beginPreRestoreAsync
+    }
+
     /**
      * Code sample for starting a {@link KeyVaultRestoreOperation restore operation} asynchronously.
      */
     public void beginRestoreAsync() {
         // BEGIN: readme-sample-beginRestoreAsync
         String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313";
-        String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D";
+        String sasToken = "";
 
         keyVaultBackupAsyncClient.beginRestore(folderUrl, sasToken)
             .setPollInterval(Duration.ofSeconds(1)) // You can set a custom polling interval.
@@ -423,7 +513,7 @@ public void beginRestoreAsync() {
     public void beginSelectiveKeyRestoreAsync() {
         // BEGIN: readme-sample-beginSelectiveKeyRestoreAsync
         String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313";
-        String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D";
+        String sasToken = "";
         String keyName = "myKey";
 
         keyVaultBackupAsyncClient.beginSelectiveKeyRestore(folderUrl, sasToken, keyName)
diff --git a/sdk/keyvault/azure-security-keyvault-administration/src/samples/java/com/azure/security/keyvault/administration/codesnippets/KeyVaultBackupAsyncClientJavaDocCodeSnippets.java b/sdk/keyvault/azure-security-keyvault-administration/src/samples/java/com/azure/security/keyvault/administration/codesnippets/KeyVaultBackupAsyncClientJavaDocCodeSnippets.java
index 57e9b916a1c0..158569649064 100644
--- a/sdk/keyvault/azure-security-keyvault-administration/src/samples/java/com/azure/security/keyvault/administration/codesnippets/KeyVaultBackupAsyncClientJavaDocCodeSnippets.java
+++ b/sdk/keyvault/azure-security-keyvault-administration/src/samples/java/com/azure/security/keyvault/administration/codesnippets/KeyVaultBackupAsyncClientJavaDocCodeSnippets.java
@@ -50,6 +50,27 @@ public KeyVaultBackupAsyncClient createAsyncClientWithHttpClient() {
         return keyVaultBackupAsyncClient;
     }
 
+    /**
+     * Generates code samples for using {@link KeyVaultBackupAsyncClient#beginPreBackup(String, String)}.
+     */
+    public void beginPreBackup() {
+        KeyVaultBackupAsyncClient client = createAsyncClient();
+
+        // BEGIN: com.azure.security.keyvault.administration.KeyVaultBackupAsyncClient.beginPreBackup#String-String
+        String blobStorageUrl = "https://myaccount.blob.core.windows.net/myContainer";
+        String sasToken = "";
+
+        client.beginPreBackup(blobStorageUrl, sasToken)
+            .setPollInterval(Duration.ofSeconds(1)) // You can set a custom polling interval.
+            .doOnError(e -> System.out.printf("Pre-backup check failed with error: %s.%n", e.getMessage()))
+            .doOnNext(pollResponse ->
+                System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus()))
+            .filter(pollResponse -> pollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED)
+            .flatMap(AsyncPollResponse::getFinalResult)
+            .subscribe(unused -> System.out.printf("Pre-backup check completed successfully.%n"));
+        // END: com.azure.security.keyvault.administration.KeyVaultBackupAsyncClient.beginPreBackup#String-String
+    }
+
     /**
      * Generates code samples for using {@link KeyVaultBackupAsyncClient#beginBackup(String, String)}.
      */
@@ -58,8 +79,7 @@ public void beginBackup() {
 
         // BEGIN: com.azure.security.keyvault.administration.KeyVaultBackupAsyncClient.beginBackup#String-String
         String blobStorageUrl = "https://myaccount.blob.core.windows.net/myContainer";
-        String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z"
-            + "&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D";
+        String sasToken = "";
 
         client.beginBackup(blobStorageUrl, sasToken)
             .setPollInterval(Duration.ofSeconds(1)) // You can set a custom polling interval.
@@ -73,6 +93,27 @@ public void beginBackup() {
         // END: com.azure.security.keyvault.administration.KeyVaultBackupAsyncClient.beginBackup#String-String
     }
 
+    /**
+     * Generates code samples for using {@link KeyVaultBackupAsyncClient#beginPreRestore(String, String)}.
+     */
+    public void beginPreRestore() {
+        KeyVaultBackupAsyncClient client = createAsyncClient();
+
+        // BEGIN: com.azure.security.keyvault.administration.KeyVaultBackupAsyncClient.beginPreRestore#String-String
+        String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313";
+        String sasToken = "";
+
+        client.beginPreRestore(folderUrl, sasToken)
+            .setPollInterval(Duration.ofSeconds(1)) // You can set a custom polling interval.
+            .doOnError(e -> System.out.printf("Pre-restore check failed with error: %s.%n", e.getMessage()))
+            .doOnNext(pollResponse ->
+                System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus()))
+            .filter(pollResponse -> pollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED)
+            .flatMap(AsyncPollResponse::getFinalResult)
+            .subscribe(unused -> System.out.printf("Pre-restore check completed successfully.%n"));
+        // END: com.azure.security.keyvault.administration.KeyVaultBackupAsyncClient.beginPreRestore#String-String
+    }
+
     /**
      * Generates code samples for using {@link KeyVaultBackupAsyncClient#beginRestore(String, String)}.
      */
@@ -81,8 +122,7 @@ public void beginRestore() {
 
         // BEGIN: com.azure.security.keyvault.administration.KeyVaultBackupAsyncClient.beginRestore#String-String
         String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313";
-        String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z"
-            + "&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D";
+        String sasToken = "";
 
         client.beginRestore(folderUrl, sasToken)
             .setPollInterval(Duration.ofSeconds(1)) // You can set a custom polling interval.
@@ -104,8 +144,7 @@ public void beginSelectiveKeyRestore() {
 
         // BEGIN: com.azure.security.keyvault.administration.KeyVaultBackupAsyncClient.beginSelectiveKeyRestore#String-String-String
         String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313";
-        String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z"
-            + "&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D";
+        String sasToken = "";
         String keyName = "myKey";
 
         client.beginSelectiveKeyRestore(folderUrl, sasToken, keyName)
diff --git a/sdk/keyvault/azure-security-keyvault-administration/src/samples/java/com/azure/security/keyvault/administration/codesnippets/KeyVaultBackupClientJavaDocCodeSnippets.java b/sdk/keyvault/azure-security-keyvault-administration/src/samples/java/com/azure/security/keyvault/administration/codesnippets/KeyVaultBackupClientJavaDocCodeSnippets.java
index a0a0b8f1dab8..1c0788b0b3c2 100644
--- a/sdk/keyvault/azure-security-keyvault-administration/src/samples/java/com/azure/security/keyvault/administration/codesnippets/KeyVaultBackupClientJavaDocCodeSnippets.java
+++ b/sdk/keyvault/azure-security-keyvault-administration/src/samples/java/com/azure/security/keyvault/administration/codesnippets/KeyVaultBackupClientJavaDocCodeSnippets.java
@@ -34,6 +34,33 @@ public KeyVaultBackupClient createClient() {
         return keyVaultBackupClient;
     }
 
+    /**
+     * Generates code samples for using {@link KeyVaultBackupClient#beginPreBackup(String, String)}.
+     */
+    public void beginPreBackup() {
+        KeyVaultBackupClient client = createClient();
+
+        // BEGIN: com.azure.security.keyvault.administration.KeyVaultBackupClient.beginPreBackup#String-String
+        String blobStorageUrl = "https://myaccount.blob.core.windows.net/myContainer";
+        String sasToken = "";
+
+        SyncPoller preBackupPoller = client.beginPreBackup(blobStorageUrl, sasToken);
+        PollResponse pollResponse = preBackupPoller.poll();
+
+        System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus());
+
+        PollResponse finalPollResponse = preBackupPoller.waitForCompletion();
+
+        if (finalPollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED) {
+            System.out.printf("Pre-backup check completed successfully.%n");
+        } else {
+            KeyVaultBackupOperation operation = preBackupPoller.poll().getValue();
+
+            System.out.printf("Pre-backup check failed with error: %s.%n", operation.getError().getMessage());
+        }
+        // END: com.azure.security.keyvault.administration.KeyVaultBackupClient.beginPreBackup#String-String
+    }
+
     /**
      * Generates code samples for using {@link KeyVaultBackupClient#beginBackup(String, String)}.
      */
@@ -42,11 +69,9 @@ public void beginBackup() {
 
         // BEGIN: com.azure.security.keyvault.administration.KeyVaultBackupClient.beginBackup#String-String
         String blobStorageUrl = "https://myaccount.blob.core.windows.net/myContainer";
-        String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z"
-            + "&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D";
+        String sasToken = "";
 
         SyncPoller backupPoller = client.beginBackup(blobStorageUrl, sasToken);
-
         PollResponse pollResponse = backupPoller.poll();
 
         System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus());
@@ -65,6 +90,34 @@ public void beginBackup() {
         // END: com.azure.security.keyvault.administration.KeyVaultBackupClient.beginBackup#String-String
     }
 
+    /**
+     * Generates code samples for using {@link KeyVaultBackupClient#beginPreRestore(String, String)}.
+     */
+    public void beginPreRestore() {
+        KeyVaultBackupClient client = createClient();
+
+        // BEGIN: com.azure.security.keyvault.administration.KeyVaultBackupClient.beginPreRestore#String-String
+        String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313";
+        String sasToken = "";
+
+        SyncPoller preRestorePoller =
+            client.beginPreRestore(folderUrl, sasToken);
+        PollResponse pollResponse = preRestorePoller.poll();
+
+        System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus());
+
+        PollResponse finalPollResponse = preRestorePoller.waitForCompletion();
+
+        if (finalPollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED) {
+            System.out.printf("Pre-restore check completed successfully.%n");
+        } else {
+            KeyVaultRestoreOperation operation = preRestorePoller.poll().getValue();
+
+            System.out.printf("Pre-restore check failed with error: %s.%n", operation.getError().getMessage());
+        }
+        // END: com.azure.security.keyvault.administration.KeyVaultBackupClient.beginPreRestore#String-String
+    }
+
     /**
      * Generates code samples for using {@link KeyVaultBackupClient#beginRestore(String, String)}.
      */
@@ -73,22 +126,20 @@ public void beginRestore() {
 
         // BEGIN: com.azure.security.keyvault.administration.KeyVaultBackupClient.beginRestore#String-String
         String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313";
-        String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z"
-            + "&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D";
+        String sasToken = "";
 
-        SyncPoller backupPoller =
+        SyncPoller restorePoller =
             client.beginRestore(folderUrl, sasToken);
-
-        PollResponse pollResponse = backupPoller.poll();
+        PollResponse pollResponse = restorePoller.poll();
 
         System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus());
 
-        PollResponse finalPollResponse = backupPoller.waitForCompletion();
+        PollResponse finalPollResponse = restorePoller.waitForCompletion();
 
         if (finalPollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED) {
             System.out.printf("Backup restored successfully.%n");
         } else {
-            KeyVaultRestoreOperation operation = backupPoller.poll().getValue();
+            KeyVaultRestoreOperation operation = restorePoller.poll().getValue();
 
             System.out.printf("Restore failed with error: %s.%n", operation.getError().getMessage());
         }
@@ -103,23 +154,21 @@ public void beginSelectiveKeyRestore() {
 
         // BEGIN: com.azure.security.keyvault.administration.KeyVaultBackupClient.beginSelectiveKeyRestore#String-String-String
         String folderUrl = "https://myaccount.blob.core.windows.net/myContainer/mhsm-myaccount-2020090117323313";
-        String sasToken = "sv=2020-02-10&ss=b&srt=o&sp=rwdlactfx&se=2021-06-17T07:13:07Z&st=2021-06-16T23:13:07Z"
-            + "&spr=https&sig=n5V6fnlkViEF9b7ij%2FttTHNwO2BdFIHKHppRxGAyJdc%3D";
+        String sasToken = "";
         String keyName = "myKey";
 
-        SyncPoller backupPoller =
+        SyncPoller restorePoller =
             client.beginSelectiveKeyRestore(folderUrl, sasToken, keyName);
-
-        PollResponse pollResponse = backupPoller.poll();
+        PollResponse pollResponse = restorePoller.poll();
 
         System.out.printf("The current status of the operation is: %s.%n", pollResponse.getStatus());
 
-        PollResponse finalPollResponse = backupPoller.waitForCompletion();
+        PollResponse finalPollResponse = restorePoller.waitForCompletion();
 
         if (finalPollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED) {
             System.out.printf("Key restored successfully.%n");
         } else {
-            KeyVaultSelectiveKeyRestoreOperation operation = backupPoller.poll().getValue();
+            KeyVaultSelectiveKeyRestoreOperation operation = restorePoller.poll().getValue();
 
             System.out.printf("Key restore failed with error: %s.%n", operation.getError().getMessage());
         }
diff --git a/sdk/keyvault/azure-security-keyvault-administration/src/test/java/com/azure/security/keyvault/administration/KeyVaultAccessControlClientTestBase.java b/sdk/keyvault/azure-security-keyvault-administration/src/test/java/com/azure/security/keyvault/administration/KeyVaultAccessControlClientTestBase.java
index 1912b0a0d083..bcddfaf61d1e 100644
--- a/sdk/keyvault/azure-security-keyvault-administration/src/test/java/com/azure/security/keyvault/administration/KeyVaultAccessControlClientTestBase.java
+++ b/sdk/keyvault/azure-security-keyvault-administration/src/test/java/com/azure/security/keyvault/administration/KeyVaultAccessControlClientTestBase.java
@@ -23,7 +23,7 @@ public abstract class KeyVaultAccessControlClientTestBase extends KeyVaultAdmini
     private static final ClientLogger LOGGER = new ClientLogger(KeyVaultAccessControlClientTestBase.class);
 
     protected final String servicePrincipalId =
-        Configuration.getGlobalConfiguration().get("CLIENT_OBJECTID", "3a107ba6-6cc0-40cf-9fed-22b612269c92");
+        Configuration.getGlobalConfiguration().get("CLIENT_OBJECTID", "f84ae8f9-c979-4750-a2fe-b350a00bebff");
 
     KeyVaultAccessControlClientBuilder getClientBuilder(HttpClient httpClient, boolean forCleanup) {
         return new KeyVaultAccessControlClientBuilder()
diff --git a/sdk/keyvault/azure-security-keyvault-administration/src/test/java/com/azure/security/keyvault/administration/KeyVaultBackupAsyncClientTest.java b/sdk/keyvault/azure-security-keyvault-administration/src/test/java/com/azure/security/keyvault/administration/KeyVaultBackupAsyncClientTest.java
index 6c3be6ed35a8..1e8baaddd810 100644
--- a/sdk/keyvault/azure-security-keyvault-administration/src/test/java/com/azure/security/keyvault/administration/KeyVaultBackupAsyncClientTest.java
+++ b/sdk/keyvault/azure-security-keyvault-administration/src/test/java/com/azure/security/keyvault/administration/KeyVaultBackupAsyncClientTest.java
@@ -5,24 +5,20 @@
 import com.azure.core.http.HttpClient;
 import com.azure.core.test.http.AssertingHttpClientBuilder;
 import com.azure.core.util.polling.AsyncPollResponse;
-import com.azure.core.util.polling.LongRunningOperationStatus;
-import com.azure.security.keyvault.administration.models.KeyVaultBackupOperation;
-import com.azure.security.keyvault.administration.models.KeyVaultRestoreOperation;
-import com.azure.security.keyvault.administration.models.KeyVaultRestoreResult;
-import com.azure.security.keyvault.administration.models.KeyVaultSelectiveKeyRestoreOperation;
-import com.azure.security.keyvault.administration.models.KeyVaultSelectiveKeyRestoreResult;
-import com.azure.security.keyvault.keys.KeyAsyncClient;
+import com.azure.security.keyvault.keys.KeyClient;
 import com.azure.security.keyvault.keys.KeyClientBuilder;
-import com.azure.security.keyvault.keys.KeyServiceVersion;
 import com.azure.security.keyvault.keys.models.CreateRsaKeyOptions;
 import com.azure.security.keyvault.keys.models.KeyVaultKey;
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.MethodSource;
+import reactor.test.StepVerifier;
 
 import java.time.OffsetDateTime;
 import java.time.ZoneOffset;
 
 import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 public class KeyVaultBackupAsyncClientTest extends KeyVaultBackupClientTestBase {
@@ -49,13 +45,34 @@ private HttpClient buildAsyncAssertingClient(HttpClient httpClient) {
     public void beginBackup(HttpClient httpClient) {
         getAsyncClient(httpClient, false);
 
-        AsyncPollResponse backupPollResponse =
-            setPlaybackPollerFluxPollInterval(asyncClient.beginBackup(blobStorageUrl, sasToken)).blockLast();
+        StepVerifier.create(setPlaybackPollerFluxPollInterval(asyncClient.beginBackup(blobStorageUrl, sasToken))
+                .last()
+                .flatMap(AsyncPollResponse::getFinalResult))
+            .assertNext(backupBlobUri -> {
+                assertNotNull(backupBlobUri);
+                assertTrue(backupBlobUri.startsWith(blobStorageUrl));
+            })
+            .verifyComplete();
+    }
+
+    /**
+     * Tests that a Key Vault or MHSM can be pre-backed up.
+     */
+    @SuppressWarnings("ConstantConditions")
+    @ParameterizedTest(name = DISPLAY_NAME)
+    @MethodSource("com.azure.security.keyvault.administration.KeyVaultAdministrationClientTestBase#createHttpClients")
+    public void beginPreBackup(HttpClient httpClient) {
+        getAsyncClient(httpClient, false);
 
-        String backupBlobUri = backupPollResponse.getFinalResult().block();
+        StepVerifier.create(setPlaybackPollerFluxPollInterval(asyncClient.beginPreBackup(blobStorageUrl, sasToken))
+                .last()
+                .flatMap(AsyncPollResponse::getFinalResult)
+                .mapNotNull(backupBlobUri -> {
+                    assertNull(backupBlobUri);
 
-        assertNotNull(backupBlobUri);
-        assertTrue(backupBlobUri.startsWith(blobStorageUrl));
+                    return backupBlobUri;
+                }))
+            .verifyComplete();
     }
 
     /**
@@ -67,26 +84,49 @@ public void beginBackup(HttpClient httpClient) {
     public void beginRestore(HttpClient httpClient) {
         getAsyncClient(httpClient, false);
 
-        // Create a backup
-        AsyncPollResponse backupPollResponse =
-            setPlaybackPollerFluxPollInterval(asyncClient.beginBackup(blobStorageUrl, sasToken))
-                .takeUntil(asyncPollResponse ->
-                    asyncPollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED)
-                .blockLast();
+        StepVerifier.create(setPlaybackPollerFluxPollInterval(asyncClient.beginBackup(blobStorageUrl, sasToken))
+                .last()
+                .flatMap(AsyncPollResponse::getFinalResult)
+                .map(backupBlobUri -> {
+                    assertNotNull(backupBlobUri);
+                    assertTrue(backupBlobUri.startsWith(blobStorageUrl));
+
+                    return backupBlobUri;
+                })
+                .map(backupBlobUri -> asyncClient.beginRestore(backupBlobUri, sasToken)
+                    .last()
+                    .map(AsyncPollResponse::getValue)))
+            .assertNext(Assertions::assertNotNull)
+            .verifyComplete();
 
-        KeyVaultBackupOperation backupOperation = backupPollResponse.getValue();
-        assertNotNull(backupOperation);
+        // For some reason, the service might still think a restore operation is running even after returning a success
+        // signal. This gives it some time to "clear" the operation.
+        sleepIfRunningAgainstService(30000);
+    }
 
-        // Restore the backup
-        String backupFolderUrl = backupOperation.getAzureStorageBlobContainerUrl();
-        AsyncPollResponse restorePollResponse =
-            setPlaybackPollerFluxPollInterval(asyncClient.beginRestore(backupFolderUrl, sasToken))
-                .takeUntil(asyncPollResponse ->
-                    asyncPollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED)
-                .blockLast();
+    /**
+     * Tests that a Key Vault can be pre-restored from a backup.
+     */
+    @SuppressWarnings("ConstantConditions")
+    @ParameterizedTest(name = DISPLAY_NAME)
+    @MethodSource("com.azure.security.keyvault.administration.KeyVaultAdministrationClientTestBase#createHttpClients")
+    public void beginPreRestore(HttpClient httpClient) {
+        getAsyncClient(httpClient, false);
 
-        KeyVaultRestoreOperation restoreOperation = restorePollResponse.getValue();
-        assertNotNull(restoreOperation);
+        StepVerifier.create(setPlaybackPollerFluxPollInterval(asyncClient.beginBackup(blobStorageUrl, sasToken))
+                .last()
+                .flatMap(AsyncPollResponse::getFinalResult)
+                .map(backupBlobUri -> {
+                    assertNotNull(backupBlobUri);
+                    assertTrue(backupBlobUri.startsWith(blobStorageUrl));
+
+                    return backupBlobUri;
+                })
+                .map(backupBlobUri -> asyncClient.beginPreRestore(backupBlobUri, sasToken)
+                    .last()
+                    .map(AsyncPollResponse::getValue)))
+            .assertNext(Assertions::assertNotNull)
+            .verifyComplete();
 
         // For some reason, the service might still think a restore operation is running even after returning a success
         // signal. This gives it some time to "clear" the operation.
@@ -100,42 +140,35 @@ public void beginRestore(HttpClient httpClient) {
     @ParameterizedTest(name = DISPLAY_NAME)
     @MethodSource("com.azure.security.keyvault.administration.KeyVaultAdministrationClientTestBase#createHttpClients")
     public void beginSelectiveKeyRestore(HttpClient httpClient) {
-        KeyAsyncClient keyClient = new KeyClientBuilder()
+        KeyClient keyClient = new KeyClientBuilder()
             .vaultUrl(getEndpoint())
-            .serviceVersion(KeyServiceVersion.V7_2)
             .pipeline(getPipeline(httpClient, false))
-            .buildAsyncClient();
+            .buildClient();
 
         String keyName = testResourceNamer.randomName("backupKey", 20);
         CreateRsaKeyOptions rsaKeyOptions = new CreateRsaKeyOptions(keyName)
             .setExpiresOn(OffsetDateTime.of(2050, 1, 30, 0, 0, 0, 0, ZoneOffset.UTC))
             .setNotBefore(OffsetDateTime.of(2000, 1, 30, 12, 59, 59, 0, ZoneOffset.UTC));
 
-        KeyVaultKey createdKey = keyClient.createRsaKey(rsaKeyOptions).block();
+        KeyVaultKey createdKey = keyClient.createRsaKey(rsaKeyOptions);
 
         getAsyncClient(httpClient, false);
 
-        // Create a backup
-        AsyncPollResponse backupPollResponse =
-            setPlaybackPollerFluxPollInterval(asyncClient.beginBackup(blobStorageUrl, sasToken))
-                .takeUntil(asyncPollResponse ->
-                    asyncPollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED)
-                .blockLast();
-
-        KeyVaultBackupOperation backupOperation = backupPollResponse.getValue();
-        assertNotNull(backupOperation);
-
-        // Restore the backup
-        String backupFolderUrl = backupOperation.getAzureStorageBlobContainerUrl();
-        AsyncPollResponse restorePollResponse =
-            setPlaybackPollerFluxPollInterval(asyncClient.beginSelectiveKeyRestore(createdKey.getName(),
-                backupFolderUrl, sasToken))
-                .takeUntil(asyncPollResponse ->
-                    asyncPollResponse.getStatus() == LongRunningOperationStatus.SUCCESSFULLY_COMPLETED)
-                .blockLast();
-
-        KeyVaultSelectiveKeyRestoreOperation restoreOperation = restorePollResponse.getValue();
-        assertNotNull(restoreOperation);
+        StepVerifier.create(setPlaybackPollerFluxPollInterval(asyncClient.beginBackup(blobStorageUrl, sasToken))
+                .last()
+                .flatMap(AsyncPollResponse::getFinalResult)
+                .map(backupBlobUri -> {
+                    assertNotNull(backupBlobUri);
+                    assertTrue(backupBlobUri.startsWith(blobStorageUrl));
+
+                    return backupBlobUri;
+                })
+                .map(backupBlobUri ->
+                    asyncClient.beginSelectiveKeyRestore(createdKey.getName(), backupBlobUri, sasToken)
+                        .last()
+                        .map(AsyncPollResponse::getValue)))
+            .assertNext(Assertions::assertNotNull)
+            .verifyComplete();
 
         // For some reason, the service might still think a restore operation is running even after returning a success
         // signal. This gives it some time to "clear" the operation.
diff --git a/sdk/keyvault/azure-security-keyvault-administration/src/test/java/com/azure/security/keyvault/administration/KeyVaultBackupClientTest.java b/sdk/keyvault/azure-security-keyvault-administration/src/test/java/com/azure/security/keyvault/administration/KeyVaultBackupClientTest.java
index 62b4d8e7cf2c..362e36ff1299 100644
--- a/sdk/keyvault/azure-security-keyvault-administration/src/test/java/com/azure/security/keyvault/administration/KeyVaultBackupClientTest.java
+++ b/sdk/keyvault/azure-security-keyvault-administration/src/test/java/com/azure/security/keyvault/administration/KeyVaultBackupClientTest.java
@@ -14,7 +14,6 @@
 import com.azure.security.keyvault.administration.models.KeyVaultSelectiveKeyRestoreResult;
 import com.azure.security.keyvault.keys.KeyClient;
 import com.azure.security.keyvault.keys.KeyClientBuilder;
-import com.azure.security.keyvault.keys.KeyServiceVersion;
 import com.azure.security.keyvault.keys.models.CreateRsaKeyOptions;
 import com.azure.security.keyvault.keys.models.KeyVaultKey;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -25,6 +24,7 @@
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 public class KeyVaultBackupClientTest extends KeyVaultBackupClientTestBase {
@@ -52,8 +52,9 @@ public void beginBackup(HttpClient httpClient) {
 
         SyncPoller backupPoller =
             setPlaybackSyncPollerPollInterval(client.beginBackup(blobStorageUrl, sasToken));
+        PollResponse pollResponse = backupPoller.waitForCompletion();
 
-        backupPoller.waitForCompletion();
+        assertEquals(LongRunningOperationStatus.SUCCESSFULLY_COMPLETED, pollResponse.getStatus());
 
         String backupBlobUri = backupPoller.getFinalResult();
 
@@ -61,6 +62,25 @@ public void beginBackup(HttpClient httpClient) {
         assertTrue(backupBlobUri.startsWith(blobStorageUrl));
     }
 
+    /**
+     * Tests that a Key Vault can be pre-backed up.
+     */
+    @ParameterizedTest(name = DISPLAY_NAME)
+    @MethodSource("com.azure.security.keyvault.administration.KeyVaultAdministrationClientTestBase#createHttpClients")
+    public void beginPreBackup(HttpClient httpClient) {
+        getClient(httpClient, false);
+
+        SyncPoller backupPoller =
+            setPlaybackSyncPollerPollInterval(client.beginPreBackup(blobStorageUrl, sasToken));
+        PollResponse pollResponse = backupPoller.waitForCompletion();
+
+        assertEquals(LongRunningOperationStatus.SUCCESSFULLY_COMPLETED, pollResponse.getStatus());
+
+        String backupBlobUri = backupPoller.getFinalResult();
+
+        assertNull(backupBlobUri);
+    }
+
     /**
      * Tests that a Key Vault can be restored from a backup.
      */
@@ -72,8 +92,9 @@ public void beginRestore(HttpClient httpClient) {
         // Create a backup
         SyncPoller backupPoller =
             setPlaybackSyncPollerPollInterval(client.beginBackup(blobStorageUrl, sasToken));
+        PollResponse pollResponse = backupPoller.waitForCompletion();
 
-        backupPoller.waitForCompletion();
+        assertEquals(LongRunningOperationStatus.SUCCESSFULLY_COMPLETED, pollResponse.getStatus());
 
         // Restore the backup
         String backupFolderUrl = backupPoller.getFinalResult();
@@ -91,6 +112,34 @@ public void beginRestore(HttpClient httpClient) {
         sleepIfRunningAgainstService(30000);
     }
 
+    /**
+     * Tests that a Key Vault can be pre-restored from a backup.
+     */
+    @ParameterizedTest(name = DISPLAY_NAME)
+    @MethodSource("com.azure.security.keyvault.administration.KeyVaultAdministrationClientTestBase#createHttpClients")
+    public void beginPreRestore(HttpClient httpClient) {
+        getClient(httpClient, false);
+
+        // Create a backup
+        SyncPoller backupPoller =
+            setPlaybackSyncPollerPollInterval(client.beginBackup(blobStorageUrl, sasToken));
+        PollResponse backupPollResponse = backupPoller.waitForCompletion();
+
+        assertEquals(LongRunningOperationStatus.SUCCESSFULLY_COMPLETED, backupPollResponse.getStatus());
+
+        // Restore the backup
+        String backupFolderUrl = backupPoller.getFinalResult();
+        SyncPoller restorePoller =
+            setPlaybackSyncPollerPollInterval(client.beginPreRestore(backupFolderUrl, sasToken));
+        PollResponse restorePollResponse = restorePoller.waitForCompletion();
+
+        assertEquals(LongRunningOperationStatus.SUCCESSFULLY_COMPLETED, restorePollResponse.getStatus());
+
+        // For some reason, the service might still think a restore operation is running even after returning a success
+        // signal. This gives it some time to "clear" the operation.
+        sleepIfRunningAgainstService(30000);
+    }
+
     /**
      * Tests that a key can be restored from a backup.
      */
@@ -99,7 +148,6 @@ public void beginRestore(HttpClient httpClient) {
     public void beginSelectiveKeyRestore(HttpClient httpClient) {
         KeyClient keyClient = new KeyClientBuilder()
             .vaultUrl(getEndpoint())
-            .serviceVersion(KeyServiceVersion.V7_2)
             .pipeline(getPipeline(httpClient, false))
             .buildClient();
 
@@ -115,20 +163,19 @@ public void beginSelectiveKeyRestore(HttpClient httpClient) {
         // Create a backup
         SyncPoller backupPoller =
             setPlaybackSyncPollerPollInterval(client.beginBackup(blobStorageUrl, sasToken));
+        PollResponse backupPollResponse = backupPoller.waitForCompletion();
 
-        backupPoller.waitForCompletion();
+        assertEquals(LongRunningOperationStatus.SUCCESSFULLY_COMPLETED, backupPollResponse.getStatus());
 
         // Restore one key from said backup
         String backupFolderUrl = backupPoller.getFinalResult();
         SyncPoller selectiveKeyRestorePoller =
             setPlaybackSyncPollerPollInterval(client.beginSelectiveKeyRestore(createdKey.getName(), backupFolderUrl,
                 sasToken));
+        PollResponse restorePollResponse =
+            selectiveKeyRestorePoller.waitForCompletion();
 
-        selectiveKeyRestorePoller.waitForCompletion();
-
-        PollResponse response = selectiveKeyRestorePoller.poll();
-
-        assertEquals(LongRunningOperationStatus.SUCCESSFULLY_COMPLETED, response.getStatus());
+        assertEquals(LongRunningOperationStatus.SUCCESSFULLY_COMPLETED, restorePollResponse.getStatus());
 
         // For some reason, the service might still think a restore operation is running even after returning a success
         // signal. This gives it some time to "clear" the operation.
diff --git a/sdk/keyvault/azure-security-keyvault-administration/src/test/java/com/azure/security/keyvault/administration/KeyVaultBackupClientTestBase.java b/sdk/keyvault/azure-security-keyvault-administration/src/test/java/com/azure/security/keyvault/administration/KeyVaultBackupClientTestBase.java
index 0b5c5110844b..37adff2fc63a 100644
--- a/sdk/keyvault/azure-security-keyvault-administration/src/test/java/com/azure/security/keyvault/administration/KeyVaultBackupClientTestBase.java
+++ b/sdk/keyvault/azure-security-keyvault-administration/src/test/java/com/azure/security/keyvault/administration/KeyVaultBackupClientTestBase.java
@@ -19,7 +19,7 @@
 public abstract class KeyVaultBackupClientTestBase extends KeyVaultAdministrationClientTestBase {
     protected final String blobStorageUrl = IS_MANAGED_HSM_DEPLOYED
         ? getStorageEndpoint() + Configuration.getGlobalConfiguration().get("BLOB_CONTAINER_NAME")
-        : "https://ta70c2fe596f0a0dfprim.blob.core.windows.net/backup";
+        : "https://tb5d8675f0aa83a18prim.blob.core.windows.net/backup";
     protected final String sasToken = IS_MANAGED_HSM_DEPLOYED ? generateSasToken() : "REDACTED";
 
     KeyVaultBackupClientBuilder getClientBuilder(HttpClient httpClient, boolean forCleanup) {
@@ -31,9 +31,15 @@ KeyVaultBackupClientBuilder getClientBuilder(HttpClient httpClient, boolean forC
     @Test
     public abstract void beginBackup(HttpClient httpClient);
 
+    @Test
+    public abstract void beginPreBackup(HttpClient httpClient);
+
     @Test
     public abstract void beginRestore(HttpClient httpClient);
 
+    @Test
+    public abstract void beginPreRestore(HttpClient httpClient);
+
     @Test
     public abstract void beginSelectiveKeyRestore(HttpClient httpClient);
 
diff --git a/sdk/keyvault/azure-security-keyvault-administration/swagger/autorest.md b/sdk/keyvault/azure-security-keyvault-administration/swagger/autorest.md
index 39e47f91030e..7d1eeb09dfb6 100644
--- a/sdk/keyvault/azure-security-keyvault-administration/swagger/autorest.md
+++ b/sdk/keyvault/azure-security-keyvault-administration/swagger/autorest.md
@@ -65,7 +65,7 @@ partial-update: true
 These settings apply only when `--tag=rbac` is specified on the command line.
 
 ``` yaml $(tag) == 'rbac'
-input-file: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/a2f6f742d088dcc712e67cb2745d8271eaa370ff/specification/keyvault/data-plane/Microsoft.KeyVault/preview/7.5-preview.1/rbac.json
+input-file: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/8af9817c15d688c941cda106758045b5deb9a069/specification/keyvault/data-plane/Microsoft.KeyVault/preview/7.6-preview.1/rbac.json
 title: KeyVaultAccessControlClient
 custom-types: KeyVaultDataAction,KeyVaultRoleDefinitionType,KeyVaultRoleScope,KeyVaultRoleType
 customization-class: src/main/java/RbacCustomizations.java
@@ -87,7 +87,7 @@ directive:
 These settings apply only when `--tag=backuprestore` is specified on the command line.
 
 ``` yaml $(tag) == 'backuprestore'
-input-file: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/a2f6f742d088dcc712e67cb2745d8271eaa370ff/specification/keyvault/data-plane/Microsoft.KeyVault/preview/7.5-preview.1/backuprestore.json
+input-file: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/8af9817c15d688c941cda106758045b5deb9a069/specification/keyvault/data-plane/Microsoft.KeyVault/preview/7.6-preview.1/backuprestore.json
 title: KeyVaultBackupClient
 customization-class: src/main/java/BackupRestoreCustomizations.java
 ```
@@ -96,7 +96,7 @@ customization-class: src/main/java/BackupRestoreCustomizations.java
 These settings apply only when `--tag=settings` is specified on the command line.
 
 ``` yaml $(tag) == 'settings'
-input-file: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/a2f6f742d088dcc712e67cb2745d8271eaa370ff/specification/keyvault/data-plane/Microsoft.KeyVault/preview/7.5-preview.1/settings.json
+input-file: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/8af9817c15d688c941cda106758045b5deb9a069/specification/keyvault/data-plane/Microsoft.KeyVault/preview/7.6-preview.1/settings.json
 title: KeyVaultSettingsClient
 custom-types: KeyVaultSettingType
 customization-class: src/main/java/SettingsCustomizations.java
diff --git a/sdk/keyvault/azure-security-keyvault-certificates/assets.json b/sdk/keyvault/azure-security-keyvault-certificates/assets.json
index 22243c30c53e..7235a61b39fc 100644
--- a/sdk/keyvault/azure-security-keyvault-certificates/assets.json
+++ b/sdk/keyvault/azure-security-keyvault-certificates/assets.json
@@ -2,5 +2,5 @@
   "AssetsRepo": "Azure/azure-sdk-assets",
   "AssetsRepoPrefixPath": "java",
   "TagPrefix": "java/keyvault/azure-security-keyvault-certificates",
-  "Tag": "java/keyvault/azure-security-keyvault-certificates_2816fc1705"
+  "Tag": "java/keyvault/azure-security-keyvault-certificates_e018897fab"
 }
diff --git a/sdk/keyvault/azure-security-keyvault-certificates/src/main/java/com/azure/security/keyvault/certificates/CertificateServiceVersion.java b/sdk/keyvault/azure-security-keyvault-certificates/src/main/java/com/azure/security/keyvault/certificates/CertificateServiceVersion.java
index 461be4837c41..c9be34b86aa7 100644
--- a/sdk/keyvault/azure-security-keyvault-certificates/src/main/java/com/azure/security/keyvault/certificates/CertificateServiceVersion.java
+++ b/sdk/keyvault/azure-security-keyvault-certificates/src/main/java/com/azure/security/keyvault/certificates/CertificateServiceVersion.java
@@ -37,7 +37,12 @@ public enum CertificateServiceVersion implements ServiceVersion {
     /**
      * Service version {@code 7.5}.
      */
-    V7_5("7.5");
+    V7_5("7.5"),
+
+    /**
+     * Service version {@code 7.6-preview.1}.
+     */
+    V7_6_PREVIEW_1("7.6-preview.1");
 
     private final String version;
 
@@ -59,6 +64,6 @@ public String getVersion() {
      * @return the latest {@link CertificateServiceVersion}
      */
     public static CertificateServiceVersion getLatest() {
-        return V7_5;
+        return V7_6_PREVIEW_1;
     }
 }
diff --git a/sdk/keyvault/azure-security-keyvault-certificates/src/test/java/com/azure/security/keyvault/certificates/CertificateAsyncClientTest.java b/sdk/keyvault/azure-security-keyvault-certificates/src/test/java/com/azure/security/keyvault/certificates/CertificateAsyncClientTest.java
index 94612cd2c6bc..926609d0bbd9 100644
--- a/sdk/keyvault/azure-security-keyvault-certificates/src/test/java/com/azure/security/keyvault/certificates/CertificateAsyncClientTest.java
+++ b/sdk/keyvault/azure-security-keyvault-certificates/src/test/java/com/azure/security/keyvault/certificates/CertificateAsyncClientTest.java
@@ -873,7 +873,7 @@ public void importCertificate(HttpClient httpClient, CertificateServiceVersion s
         importCertificateRunner((importCertificateOptions) ->
             StepVerifier.create(certificateAsyncClient.importCertificate(importCertificateOptions))
                 .assertNext(importedCertificate -> {
-                    assertTrue("db1497bc2c82b365c5c7c73f611513ee117790a9"
+                    assertTrue("73b4319cdf38e0797084535d9c02fd04d4b2b2e6"
                         .equalsIgnoreCase(importedCertificate.getProperties().getX509ThumbprintAsString()));
                     assertEquals(importCertificateOptions.isEnabled(), importedCertificate.getProperties().isEnabled());
 
@@ -881,8 +881,10 @@ public void importCertificate(HttpClient httpClient, CertificateServiceVersion s
                     X509Certificate x509Certificate = assertDoesNotThrow(
                         () -> loadCerToX509Certificate(importedCertificate.getCer()));
 
-                    assertEquals("CN=KeyVaultTest", x509Certificate.getSubjectX500Principal().getName());
-                    assertEquals("CN=KeyVaultTest", x509Certificate.getIssuerX500Principal().getName());
+                    assertTrue(x509Certificate.getSubjectX500Principal().getName()
+                        .contains("CN=Test,OU=Test,O=Contoso,L=Redmond,ST=WA,C=US"));
+                    assertTrue(x509Certificate.getIssuerX500Principal().getName()
+                        .contains("CN=Test,OU=Test,O=Contoso,L=Redmond,ST=WA,C=US"));
                 })
                 .verifyComplete());
     }
diff --git a/sdk/keyvault/azure-security-keyvault-certificates/src/test/java/com/azure/security/keyvault/certificates/CertificateClientTest.java b/sdk/keyvault/azure-security-keyvault-certificates/src/test/java/com/azure/security/keyvault/certificates/CertificateClientTest.java
index 393a22f5e03f..c727d4e7bbeb 100644
--- a/sdk/keyvault/azure-security-keyvault-certificates/src/test/java/com/azure/security/keyvault/certificates/CertificateClientTest.java
+++ b/sdk/keyvault/azure-security-keyvault-certificates/src/test/java/com/azure/security/keyvault/certificates/CertificateClientTest.java
@@ -865,7 +865,7 @@ public void importCertificate(HttpClient httpClient, CertificateServiceVersion s
             KeyVaultCertificateWithPolicy importedCertificate =
                 certificateClient.importCertificate(importCertificateOptions);
 
-            assertTrue("db1497bc2c82b365c5c7c73f611513ee117790a9"
+            assertTrue("73b4319cdf38e0797084535d9c02fd04d4b2b2e6"
                 .equalsIgnoreCase(importedCertificate.getProperties().getX509ThumbprintAsString()));
             assertEquals(importCertificateOptions.isEnabled(), importedCertificate.getProperties().isEnabled());
 
@@ -873,8 +873,10 @@ public void importCertificate(HttpClient httpClient, CertificateServiceVersion s
             X509Certificate x509Certificate = assertDoesNotThrow(
                 () -> loadCerToX509Certificate(importedCertificate.getCer()));
 
-            assertEquals("CN=KeyVaultTest", x509Certificate.getSubjectX500Principal().getName());
-            assertEquals("CN=KeyVaultTest", x509Certificate.getIssuerX500Principal().getName());
+            assertTrue(x509Certificate.getSubjectX500Principal().getName()
+                .contains("CN=Test,OU=Test,O=Contoso,L=Redmond,ST=WA,C=US"));
+            assertTrue(x509Certificate.getIssuerX500Principal().getName()
+                .contains("CN=Test,OU=Test,O=Contoso,L=Redmond,ST=WA,C=US"));
         });
     }
 
diff --git a/sdk/keyvault/azure-security-keyvault-certificates/src/test/java/com/azure/security/keyvault/certificates/FakeCredentialsForTests.java b/sdk/keyvault/azure-security-keyvault-certificates/src/test/java/com/azure/security/keyvault/certificates/FakeCredentialsForTests.java
index 67557bb45c07..d51e8d7c971e 100644
--- a/sdk/keyvault/azure-security-keyvault-certificates/src/test/java/com/azure/security/keyvault/certificates/FakeCredentialsForTests.java
+++ b/sdk/keyvault/azure-security-keyvault-certificates/src/test/java/com/azure/security/keyvault/certificates/FakeCredentialsForTests.java
@@ -11,56 +11,63 @@ public class FakeCredentialsForTests {
      * Fake certificate content
      */
     public static final String FAKE_CERTIFICATE =
-        "MIIJUQIBAzCCCRcGCSqGSIb3DQEHAaCCCQgEggkEMIIJADCCA7cGCSqGSIb3DQEH"
-        + "BqCCA6gwggOkAgEAMIIDnQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIONsr"
-        + "wr1FhuICAggAgIIDcBQWaArZgVr5K8+zccadOCGIC+WzlAx2V88HT6fQcujZItr3"
-        + "koiHi7+sdTe3mQncnxqZoNGgx4s6Xh+QIIFdHSAo4EL9uGoFKiprKMHAmiCj9Pcm"
-        + "M6stTFYMnzmlAiVLCNogPEobi2pfcQIVbDaVUHdm4EczlBGKyMTZSTkXmxI7Ax9V"
-        + "YXucniBpxJ3d0bTHchvHCjqHCLTDCnqyPXTqQH0JpHSYdcq9pxydtoNNgT7NDrKM"
-        + "0QtxIvI29+ZlSLZMxB3Mf4qOhn6bmyBakUypK1S8N0b2YPLTjp5+Zmb8W24+1bVm"
-        + "gV2p10SFjbt8CacDl3dmRUkwu6C8Cl3QIpgwbMoP8hnJppyaFvIqar9roNNS3seG"
-        + "8RDn/Q4DCYWJ6JhA6Z+gDL3BncwE2q9rekkOwo1MwERNhBEtINrXztKogdA/as1o"
-        + "O443ZbM/qm5pX9ZPh4Hv8Hzgl0aqlxubsUcEr8SIDNEJ3u91/gDdmHWgabnLZif8"
-        + "A7e2TMCqTiCM2nRr3soNUvOqnLHoexAKqsQAvi36VVmdAH1085Q+ISpVseCe3Piq"
-        + "PhLsqyfF2Yox+NkI/nOwtg0XhO+mdoAkes03ojctqFXB2ygo/iRH2ng16zGnWes0"
-        + "nSp3rcOaoqcE1c85+/QQZZrzVspdnnNhYWWr1IiwyiOctOAovpmU9oDacY+1u9dO"
-        + "pnVRr5ibwR1NSlIVl1KPNsYmQoP9hig8lULeVGLQTWEQc8qb55t/Y/RpgNFEs3pi"
-        + "Hmd12R9NZMBcrZp3bbSzdS51OicQ6PKRXKESHVMbbsLiR8M62Dxg9ysH0kVEdxjw"
-        + "LfdlqAPby/+/L2t62WKkoHq37GtqtVDYAELBsP9tq3AF+ucUB1Gj8vvwEAedJ2Zl"
-        + "Q2f9xVTHXr0Ah3JkYsMpAuK0HZzMTVc0ZKXrfocbtvwr4aVwc3zOP+pz1AhqZpkD"
-        + "fr23NVkAmV63aIBOr1TSNPCnn7PMlr4rfZ2vzwBKCrfnc+O44IsWNg1N4ZBAKjnh"
-        + "ZZjhgxRYC5en7PKVPHAla2R8299RJy7tuiR6qo58UZNdsIJXBbjhytLroZHvdF3r"
-        + "mSTxgYli5h9xKAw9c6eqmrmGNRD1dY9bmkgFNwF6C8Yi4RdCZ3C6LNFHhgxMwbXi"
-        + "Xl5Mfa7E4ZSOWIeH8I79knxDPDMm4sTRSncbyn8wggVBBgkqhkiG9w0BBwGgggUy"
-        + "BIIFLjCCBSowggUmBgsqhkiG9w0BDAoBAqCCBO4wggTqMBwGCiqGSIb3DQEMAQMw"
-        + "DgQI4fPTwJwGln0CAggABIIEyE1waejpdCUGBbzwCZhdul9adyBO8futpEZKKlcc"
-        + "RnP2iQ82N7P2CE7cXEch8OrC3+qyvyGfqVzNpjOWT1v+uMrqT67enK00/eU/OWxk"
-        + "2edizJXUr+usLjojPh1Yu822Ffax3qiZ87Svm9staSNebek6q/2W24KnaDNvqPPT"
-        + "vGA4prwpwdn98NHGQou5WQiSsh+VkT49duZxO6/+TWK8I27FnoyCgiKEjr6vvY6a"
-        + "x4E3ect4Kz0MZsLKNYd6/BqBRw2UnrKg0yoIYHvP/j/DT8q++cafs9ZSS2eO4ZlC"
-        + "5DAshQdXUD6O7fJF+rI5Ao36keWlkz8DKi0kWL32Rzvk56vVbVGIkrGveZ19E5WR"
-        + "3kqkFNddO+zZs6tJJeO8Rghylp43mgyivpkzPQ6By9aekn+VgQ5Oqze7gUX74CD0"
-        + "onjf5Q5eaOl6ZGdcVlKOXbf/r8libAq7GvGICm1Rfa79/Q1IqvvKFmxd/WZfa1iJ"
-        + "OwZwaV53ALhlDejdTU1YS7ZHorFTJGfn4LtHoVkRpZsMnA+ygMZ0+vTTgnGS1GZz"
-        + "g7OACuXWla1Dh2yv/UYKpdnhgyAGgCcIIguiRSD/JWxZxiT9sb/t+bN7NLRYpXak"
-        + "rYTOi1lHoqCGfZTlzMyZPmo/DfZTdhGXVUYA6puvi+Qv22ub9N01riv2TN9noOkB"
-        + "RH67I48dXRrzJi7m2CYG6v8pQmvW4Tg3feIrOF99hHU/YJfOWvQgjiQoyJFlyq8L"
-        + "1wwhG4eXQH4bP97ilJHFDWjTzKzbYrhKZadd7SJ2hT6R3NPH9AYyMdsoPaWu9RIE"
-        + "g2niz0niFXwUnNQib/deL7PDyFwndsRtp3P405oF4tzMU1Q4mD2IwObM7g4+syFW"
-        + "c+2Cy29o0buJrb4jIsIjjUYNB/mzoU7iKXwQ0qhPTHyUbP4XM5jaiEuS48u4hRbh"
-        + "k9C5Ti6fvrbeVqN/rcXPvS0h+HCf4Gc8LCXTBME0a1SSnQR10q66GRnuQa2hM+/b"
-        + "AxQUTXNYs/p4Np8aGIR6EkXXR0cbcoMHp3+d6h9B8tqlmvTYAFYvlkImeyJaNOpH"
-        + "J9E+AbNEugEm1s+GgfQT5XKCThmpg0uNyKFAkjvkXjoS5K4dJwQPtYfM2SYyLjTO"
-        + "dEmsjPKR7NcBIR3hx35PIpyHxdqAnb25GakB7GHX1/HJsZCf+NLuUsWkyP6pNy6w"
-        + "o9l9BOSSDnUPEV5D/J1h/GZ/hOHcf9WDv06KefKAy77UpnTKSSlHr/PzkfNbtjFf"
-        + "6xKPQRWA1WVd3FW2BETdABteX0QcYSZjVRjirWZUOxu2VKv9I4G0PGMjmo6UxCMG"
-        + "xFV1qulKn+kPAInoNbgbY2ZaF5q1FAoMQ4nAPG6W79J0xgEkuCiH6F7F7TEHldCO"
-        + "ulHWfJja7K27zW2T4ZnQbcpKmHpCns7bAt0198CrYyHfNP4Yyx0uiXBI+Z9hlHvO"
-        + "kcs0l5RDV1EWR3jOih7zLr43MPwJ12sXwEMCOjUHYxs0jTZcgmti+wBPs8xuWayh"
-        + "J/9pD1DfFxf6lFOCi1op5zPc7U3NNMbU3gXgSolsrMjm0dJH0rfu4+C0cym62EBo"
-        + "IGdvyABqS9N96YUu1OreBcCYiTP5Qajn87J8i9zj3aa5lFGJYCS6s8EBeDElMCMG"
-        + "CSqGSIb3DQEJFTEWBBTbFJe8LIKzZcXHxz9hFRPuEXeQqTAxMCEwCQYFKw4DAhoF"
-        + "AAQUI7HzgLxeU0ExCw7mUkJyWmnUlckECNF1gKFeLQMGAgIIAA==";
+        "MIIKjwIBAzCCCkUGCSqGSIb3DQEHAaCCCjYEggoyMIIKLjCCBJoGCSqGSIb3DQEH"
+        + "BqCCBIswggSHAgEAMIIEgAYJKoZIhvcNAQcBMF8GCSqGSIb3DQEFDTBSMDEGCSqG"
+        + "SIb3DQEFDDAkBBD6J7VlngzbeYpxVxb5zbUjAgIIADAMBggqhkiG9w0CCQUAMB0G"
+        + "CWCGSAFlAwQBKgQQFq79Veolktn9WBVZ2b+yn4CCBBDmBdB0C7F9Lac/Kv5pjH4b"
+        + "RFX1HEygcQVBJQpCKq5WuR2ahBZolTfo6mlhWrB0Y/pdNe5QBERrw5PX9hghny19"
+        + "S0m9jmwYb2VwTigIGJAqR6Ruik3MJ1Ya57dYNXgpr3smhgYNe66Jk8sHbFiwlSU7"
+        + "Hsq69+1EZwwKBHerGfpMux4vWAWAIHorJgZxrXAuce+mSxDxkASe+Ud/bqq0no3q"
+        + "qsad60l2SgTElwpBCrMkac8bUHwOg6jOJltPRSfWjfSiqVt/14OIS5HQwUaA6ZyP"
+        + "sD3poTAaDu35d3Xou7f7oZlN5AeCNnoD/uQlA5d/nXEyCC/UXbXj9O+vDXKfaS7Y"
+        + "naUqKSOcqxCj9NRsLAJWuE06oOFxrZJu+UbcANZAUqLW6GD8D7kTgoZmakE6QxT0"
+        + "Q1tOtEV2/pxhAHKj3V8IiWQ2NdodigO52UcGIt8Q4awbydy6RPFMppsi8WBTXDtP"
+        + "bui8V4AJvtrm5jRGdW7mzJvkqeUVR/IeQ/7L5hpcr1hg1EVs43ax29VF6VmMiVKa"
+        + "Y3Itiqs49fet6Qburgf11AyrP9RuipJD5hQd1YmlIvpySLkxc2/PMGEsdgC4BTIz"
+        + "I0MszHaQPvsgKxGTdf6keV4yZSWUyEOAyFCmuynfOCwSya6Cbm74YAXXj4IdA1dY"
+        + "6kOgNgfTM8Tr3KmaBSNbenwAXXPVHIJacqIMRTUIQ/+be0dwsgJ5FJi0/5poYrDj"
+        + "XLyXT25OOTFZVAzGwVcm5hlFNQUULV7bAaJOH2ZtK3uoTHuH83FCfRSRqeOqEhZJ"
+        + "Z0DF2yEG2yuEHOT2OqcIYuRnl1HbGdYFgbwoa9UTMOYG8HkEgzKFTXoqmKOC38zu"
+        + "W+1pKLn+uiTkeyCOjAq99Mwve2fFDdQHXcSmv24ZFsiHSctzDQe9xJUBtRtm38+d"
+        + "GkniMuusmxBIhgMqPeG1g7tqS7OrX+r9wZieBqL3aaabXAXQbuQZ3tFyZDzWfA5w"
+        + "lWY0mc7rmqau70XTV90eGxUtT4IYeLuTbjVsPBYahsupEbujrkeo4kS8cp6AyIhl"
+        + "WLzcXYzwAnIcbQJkw6nb/JyCrz9/mASpQmKpX4syj+4wcFATwDDt4KjblAendcJw"
+        + "bguM4isaPCxP48hg4Tj0CLLSRNtMfXIjKltJWkhjXzQLEzcCTeWLAUzzm9mNyDOZ"
+        + "EVso2Y1jN6Xqdm6D1bRuHp0TsKlHdkyBwBCkFPph+fCgKrASmbgSzX8bilqzOU/r"
+        + "8Ql+ot6br42IPIm6Cwn6sCwdiS0chx0mr52n3Fef7Aurluu6x/xnNT+wLoURXHNe"
+        + "FqN0nKZBgKWRQIUKAkpK+02tN0TFtUWbHjJ0EAsNwAaSoTwqXNgEmb8JPR1BRCod"
+        + "kYfAnHlnvBy83IMiXMz0lDCCBYwGCSqGSIb3DQEHAaCCBX0EggV5MIIFdTCCBXEG"
+        + "CyqGSIb3DQEMCgECoIIFOTCCBTUwXwYJKoZIhvcNAQUNMFIwMQYJKoZIhvcNAQUM"
+        + "MCQEEEaqp++BjdYKmeKmJMqBDE0CAggAMAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUD"
+        + "BAEqBBB8PJ1Qo62GUuy2gDROrqH8BIIE0Byd3Rzee8m9fS7xEV6Z5QM86PEOyziF"
+        + "nzWe8WRrbTN62u9JPAfYvXeeCRdr8QKkvw8mJXUUNHYmwo56ExR/JSJu/vQIl7FN"
+        + "jtGzwQHQtUTNcZuAsiFrZvYq4vAI0wnwmtW/ApQCylbERyZp8DRx3fT90QTAGz9s"
+        + "T9RreOeN8qUj0UY6/8eD3vZJ2sG+QpHK5cv1H++ZhbfgZgR8aaupu6xXKQdTHg7P"
+        + "ors42O7Q40Sk/LvWVHfA2tYPr5QfeB1tyjhSnwx1wExlWb01XvRq1IkP8K4SD4Ss"
+        + "7Smo7SmWprzjIFcpTWXI0MS2sFIzJICxih3eUoWvRYWZk0J8H1qVq4yDke0q9ah7"
+        + "FdCOt2Ah7JPscb+ahGjQjNNWsfC3INSNLABxB3b3RlJLCY9D/hG5a2auDaF/0tXX"
+        + "UhrRfUZhW70Cc345I4hdrX9xze4kSdF5h9Uzzv2OzzFcojM/7CYG3ya2pyMn1CQH"
+        + "B/SY2XqweINrqVRWiBEhD1r/SJ1Sq2uvMp6WmctKKOh6JNErFabxd/GybrcYlhZO"
+        + "a6SnH23xpMonPzAzW43p8C41GDIizUMFvbxvkPFWBbsSJuUUoGvR6sHvKGOLs72Z"
+        + "D0ruInfTeZxD15NX8zd+pZDEyFWVH0sxZjOXouJr3RM28UvLu9uuIoz7+1/p3rns"
+        + "NX7tBV7zDspe5Tsb3t49vtO5wxdGAIAEK+5MrbvuP1w2T6aQYwF5DSzckDeZREGn"
+        + "GjEyTnzFRn/1FTKgfPkBUa8AIl1CbYYNebusVZSoB19+gDCH3oyzF4+Qr5mKpkEF"
+        + "LFbV4Sxvbk8vxNthubcuMXP+QGJA5o6jNfpvM8mGcZR8tO8J7Kq+pKv8AdtkRHuj"
+        + "HVuenB5sdgKR5hJB7cOqQBush+6i+yA4dFWbt1vblABGCueJYw7/czhQx4iO6JEx"
+        + "P2TZaFq7+SuvIdEOB7uMwnPIQFv1ukBcx8eiWspK0qsKeIpqDVwaypJLgqKEOL9U"
+        + "0YRXxeH1XjxBWGipvRhmo4C8NYt9Lwt1FUh9nEwjmXSapaA0zUO2pLpzy3rdIGW9"
+        + "gdRfKvNie0w8jwuvgzMY9t3u04MHyKQ2h1NIOXrOfZk/dOrgpUpRqG1bPhS/El1s"
+        + "cwZglmVX6PU4fItXFkQpR+WxQpVncOlS/e4ac3RYXAq/ch84vQ+vXRaWruNB9nSy"
+        + "y1d/bwJWtF1I0ZWE+nExyWdlUBp89dIrYSFw/cfwark615ROE1akA7wU68Y5K7HO"
+        + "99t4V9NwleGhfQ2mf94QjkfVyszYsrCBqSWhrGYTQ6JoTKquR0Xz6vZnMmUvaUK1"
+        + "Ddv96lmfWBSIJ/urWMSRL75jIH5bYNnx5gAyorXqEKJAtt1yGftZYUXaOOfHvXJc"
+        + "FOlXIGAF9EtmaPnefC9HSTmnrNSJEB9u+hiaXBzVkI2oJG/GM6aLOTdYyMDC8fXw"
+        + "30h0j+cp4IhoYythftmQZ1rz9oVZOZgIQJjViYwPHY2gOE/BZ+bBKjtdZ4cDYOHS"
+        + "9g3DrtexeLpjmWSqITa+x/KV8KWmE0FMcsDauKNVILFs607F9hqd+4azfqhtpT8Q"
+        + "0u84RgoVrmFIajhaNl5+06KVGCRAkmwQkxYHiY8SkuPTo4dh0/9AycqMODL5Zjh6"
+        + "a6MHpGSGG+WXMSUwIwYJKoZIhvcNAQkVMRYEFHO0MZzfOOB5cIRTXZwC/QTUsrLm"
+        + "MEEwMTANBglghkgBZQMEAgEFAAQguefMRfuN/2S1v8baZNWXyR/9lVxdKylJSNnO"
+        + "ULN2mZ4ECN9bsOpidibOAgIIAA==";
 
     public static final String FAKE_PEM_CERTIFICATE =
         "-----BEGIN CERTIFICATE-----\n"
diff --git a/sdk/keyvault/azure-security-keyvault-certificates/swagger/autorest.md b/sdk/keyvault/azure-security-keyvault-certificates/swagger/autorest.md
index 535eb0f0d9fd..077bab94790b 100644
--- a/sdk/keyvault/azure-security-keyvault-certificates/swagger/autorest.md
+++ b/sdk/keyvault/azure-security-keyvault-certificates/swagger/autorest.md
@@ -34,7 +34,7 @@ autorest
 use: '@autorest/java@4.1.22'
 output-folder: ../
 java: true
-input-file: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/a2f6f742d088dcc712e67cb2745d8271eaa370ff/specification/keyvault/data-plane/Microsoft.KeyVault/preview/7.5-preview.1/certificates.json
+input-file: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/8af9817c15d688c941cda106758045b5deb9a069/specification/keyvault/data-plane/Microsoft.KeyVault/preview/7.6-preview.1/certificates.json
 title: CertificateClient
 namespace: com.azure.security.keyvault.certificates
 models-subpackage: implementation.models
diff --git a/sdk/keyvault/azure-security-keyvault-keys/assets.json b/sdk/keyvault/azure-security-keyvault-keys/assets.json
index f14b27d364ed..31f6f88f48d3 100644
--- a/sdk/keyvault/azure-security-keyvault-keys/assets.json
+++ b/sdk/keyvault/azure-security-keyvault-keys/assets.json
@@ -2,5 +2,5 @@
   "AssetsRepo": "Azure/azure-sdk-assets",
   "AssetsRepoPrefixPath": "java",
   "TagPrefix": "java/keyvault/azure-security-keyvault-keys",
-  "Tag": "java/keyvault/azure-security-keyvault-keys_72fb58ae91"
+  "Tag": "java/keyvault/azure-security-keyvault-keys_d9bef0f806"
 }
diff --git a/sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyServiceVersion.java b/sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyServiceVersion.java
index 500375096e3a..c335fdc6e383 100644
--- a/sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyServiceVersion.java
+++ b/sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyServiceVersion.java
@@ -37,7 +37,12 @@ public enum KeyServiceVersion implements ServiceVersion {
     /**
      * Service version {@code 7.5}.
      */
-    V7_5("7.5");
+    V7_5("7.5"),
+
+    /**
+     * Service version {@code 7.6-preview.1}.
+     */
+    V7_6_PREVIEW_1("7.6-preview.1");
 
     private final String version;
 
@@ -59,6 +64,6 @@ public String getVersion() {
      * @return the latest {@link KeyServiceVersion}
      */
     public static KeyServiceVersion getLatest() {
-        return V7_5;
+        return V7_6_PREVIEW_1;
     }
 }
diff --git a/sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/cryptography/CryptographyServiceVersion.java b/sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/cryptography/CryptographyServiceVersion.java
index c3694a542c5a..728b1b316463 100644
--- a/sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/cryptography/CryptographyServiceVersion.java
+++ b/sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/cryptography/CryptographyServiceVersion.java
@@ -37,7 +37,12 @@ public enum CryptographyServiceVersion implements ServiceVersion {
     /**
      * Service version {@code 7.5}.
      */
-    V7_5("7.5");
+    V7_5("7.5"),
+
+    /**
+     * Service version {@code 7.6-preview.1}.
+     */
+    V7_6_PREVIEW_1("7.6-preview.1");
 
     private final String version;
 
@@ -59,6 +64,6 @@ public String getVersion() {
      * @return the latest {@link CryptographyServiceVersion}
      */
     public static CryptographyServiceVersion getLatest() {
-        return V7_5;
+        return V7_6_PREVIEW_1;
     }
 }
diff --git a/sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/implementation/models/LifetimeActionsType.java b/sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/implementation/models/LifetimeActionsType.java
index e7465db72a32..da0e6509c80e 100644
--- a/sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/implementation/models/LifetimeActionsType.java
+++ b/sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/implementation/models/LifetimeActionsType.java
@@ -17,7 +17,7 @@
 @Fluent
 public final class LifetimeActionsType implements JsonSerializable {
     /*
-     * The type of the action.
+     * The type of the action. The value should be compared case-insensitively.
      */
     private KeyRotationPolicyAction type;
 
@@ -25,7 +25,7 @@ public final class LifetimeActionsType implements JsonSerializable {
                     assertKeyEquals(keyToCreate, createdKey);
-                    assertEquals("0", createdKey.getProperties().getHsmPlatform());
+
+                    if (!isHsmEnabled) {
+                        assertEquals("0", createdKey.getProperties().getHsmPlatform());
+                    }
                 })
                 .verifyComplete());
     }
@@ -213,14 +216,20 @@ public void getKey(HttpClient httpClient, KeyServiceVersion serviceVersion) {
             StepVerifier.create(keyAsyncClient.createKey(keyToSetAndGet))
                 .assertNext(createdKey -> {
                     assertKeyEquals(keyToSetAndGet, createdKey);
-                    assertEquals("0", createdKey.getProperties().getHsmPlatform());
+
+                    if (!isHsmEnabled) {
+                        assertEquals("0", createdKey.getProperties().getHsmPlatform());
+                    }
                 })
                 .verifyComplete();
 
             StepVerifier.create(keyAsyncClient.getKey(keyToSetAndGet.getName()))
                 .assertNext(retrievedKey -> {
                     assertKeyEquals(keyToSetAndGet, retrievedKey);
-                    assertEquals("0", retrievedKey.getProperties().getHsmPlatform());
+
+                    if (!isHsmEnabled) {
+                        assertEquals("0", retrievedKey.getProperties().getHsmPlatform());
+                    }
                 })
                 .verifyComplete();
         });
diff --git a/sdk/keyvault/azure-security-keyvault-keys/src/test/java/com/azure/security/keyvault/keys/KeyClientTest.java b/sdk/keyvault/azure-security-keyvault-keys/src/test/java/com/azure/security/keyvault/keys/KeyClientTest.java
index ae77209705b3..fb8b4c69e83e 100644
--- a/sdk/keyvault/azure-security-keyvault-keys/src/test/java/com/azure/security/keyvault/keys/KeyClientTest.java
+++ b/sdk/keyvault/azure-security-keyvault-keys/src/test/java/com/azure/security/keyvault/keys/KeyClientTest.java
@@ -74,7 +74,10 @@ public void createKey(HttpClient httpClient, KeyServiceVersion serviceVersion) {
             KeyVaultKey createdKey = keyClient.createKey(keyToCreate);
 
             assertKeyEquals(keyToCreate, createdKey);
-            assertEquals("0", createdKey.getProperties().getHsmPlatform());
+
+            if (!isHsmEnabled) {
+                assertEquals("0", createdKey.getProperties().getHsmPlatform());
+            }
         });
     }
 
@@ -196,7 +199,10 @@ public void getKey(HttpClient httpClient, KeyServiceVersion serviceVersion) {
             KeyVaultKey retrievedKey = keyClient.getKey(keyToSetAndGet.getName());
 
             assertKeyEquals(keyToSetAndGet, retrievedKey);
-            assertEquals("0", retrievedKey.getProperties().getHsmPlatform());
+
+            if (!isHsmEnabled) {
+                assertEquals("0", retrievedKey.getProperties().getHsmPlatform());
+            }
         });
     }
 
diff --git a/sdk/keyvault/azure-security-keyvault-keys/swagger/autorest.md b/sdk/keyvault/azure-security-keyvault-keys/swagger/autorest.md
index 14e6cfb2b298..798832d19a67 100644
--- a/sdk/keyvault/azure-security-keyvault-keys/swagger/autorest.md
+++ b/sdk/keyvault/azure-security-keyvault-keys/swagger/autorest.md
@@ -33,7 +33,7 @@ autorest
 use: '@autorest/java@4.1.22'
 output-folder: ../
 java: true
-input-file: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/551275acb80e1f8b39036b79dfc35a8f63b601a7/specification/keyvault/data-plane/Microsoft.KeyVault/stable/7.4/keys.json
+input-file: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/8af9817c15d688c941cda106758045b5deb9a069/specification/keyvault/data-plane/Microsoft.KeyVault/preview/7.6-preview.1/keys.json
 title: KeyClient
 namespace: com.azure.security.keyvault.keys
 models-subpackage: implementation.models
diff --git a/sdk/keyvault/azure-security-keyvault-secrets/assets.json b/sdk/keyvault/azure-security-keyvault-secrets/assets.json
index 7acd1df9cf28..2363851274cf 100644
--- a/sdk/keyvault/azure-security-keyvault-secrets/assets.json
+++ b/sdk/keyvault/azure-security-keyvault-secrets/assets.json
@@ -2,5 +2,5 @@
   "AssetsRepo": "Azure/azure-sdk-assets",
   "AssetsRepoPrefixPath": "java",
   "TagPrefix": "java/keyvault/azure-security-keyvault-secrets",
-  "Tag": "java/keyvault/azure-security-keyvault-secrets_28e407b475"
+  "Tag": "java/keyvault/azure-security-keyvault-secrets_5c7c80d234"
 }
diff --git a/sdk/keyvault/azure-security-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/SecretServiceVersion.java b/sdk/keyvault/azure-security-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/SecretServiceVersion.java
index 15f47b6b8e98..8ddee9cb149b 100644
--- a/sdk/keyvault/azure-security-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/SecretServiceVersion.java
+++ b/sdk/keyvault/azure-security-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/SecretServiceVersion.java
@@ -37,7 +37,12 @@ public enum SecretServiceVersion implements ServiceVersion {
     /**
      * Service version {@code 7.5}.
      */
-    V7_5("7.5");
+    V7_5("7.5"),
+
+    /**
+     * Service version {@code 7.6-preview.1}.
+     */
+    V7_6_PREVIEW_1("7.6-preview.1");
 
     private final String version;
 
@@ -59,6 +64,6 @@ public String getVersion() {
      * @return the latest {@link SecretServiceVersion}
      */
     public static SecretServiceVersion getLatest() {
-        return V7_5;
+        return V7_6_PREVIEW_1;
     }
 }
diff --git a/sdk/keyvault/azure-security-keyvault-secrets/swagger/autorest.md b/sdk/keyvault/azure-security-keyvault-secrets/swagger/autorest.md
index 9a355aa4e714..8f4eefa758dc 100644
--- a/sdk/keyvault/azure-security-keyvault-secrets/swagger/autorest.md
+++ b/sdk/keyvault/azure-security-keyvault-secrets/swagger/autorest.md
@@ -33,7 +33,7 @@ autorest
 use: '@autorest/java@4.1.22'
 output-folder: ../
 java: true
-input-file: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/a2f6f742d088dcc712e67cb2745d8271eaa370ff/specification/keyvault/data-plane/Microsoft.KeyVault/preview/7.5-preview.1/secrets.json
+input-file: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/8af9817c15d688c941cda106758045b5deb9a069/specification/keyvault/data-plane/Microsoft.KeyVault/preview/7.6-preview.1/secrets.json
 title: SecretClient
 namespace: com.azure.security.keyvault.secrets
 models-subpackage: implementation.models
diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/CHANGELOG.md b/sdk/monitor/azure-monitor-opentelemetry-exporter/CHANGELOG.md
index c5f9897de936..c83669324abc 100644
--- a/sdk/monitor/azure-monitor-opentelemetry-exporter/CHANGELOG.md
+++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/CHANGELOG.md
@@ -1,14 +1,14 @@
 # Release History
 
-## 1.0.0-beta.22 (Unreleased)
-
-### Features Added
-
-### Breaking Changes
+## 1.0.0-beta.22 (2024-05-09)
 
 ### Bugs Fixed
+- [Fix _OTELRESOURCE_ custom metrics with default resources](https://github.com/Azure/azure-sdk-for-java/pull/39380)
 
 ### Other Changes
+- [Update OpenTelemetry to 2.3.0](https://github.com/Azure/azure-sdk-for-java/pull/39843)
+- [Add attach type to sdkVersion](https://github.com/Azure/azure-sdk-for-java/pull/39883)
+- [Emit stable HTTP OTel metrics](https://github.com/Azure/azure-sdk-for-java/pull/39960)
 
 ## 1.0.0-beta.21 (2024-03-11)
 
diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/README.md b/sdk/monitor/azure-monitor-opentelemetry-exporter/README.md
index 810e2a5455a2..c3e14134d5dc 100644
--- a/sdk/monitor/azure-monitor-opentelemetry-exporter/README.md
+++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/README.md
@@ -23,7 +23,7 @@ For more information, please read [introduction to Application Insights][applica
 
   com.azure
   azure-monitor-opentelemetry-exporter
-  1.0.0-beta.21/version>
+  1.0.0-beta.22/version>
 
 ```
 [//]: # ({x-version-update-end})
diff --git a/sdk/spring/CHANGELOG.md b/sdk/spring/CHANGELOG.md
index e9cff45da533..8fcdaf273a34 100644
--- a/sdk/spring/CHANGELOG.md
+++ b/sdk/spring/CHANGELOG.md
@@ -1,5 +1,18 @@
 # Release History
 
+## 5.12.0 (2024-05-09)
+- This release is compatible with Spring Boot 3.0.0-3.0.13, 3.1.0-3.1.8, 3.2.0-3.2.5. (Note: 3.0.x (x>13), 3.1.y (y>8) and 3.2.z (z>5) should be supported, but they aren't tested with this release.)
+- This release is compatible with Spring Cloud 2022.0.0-2022.0.5, 2023.0.0-2023.0.1. (Note: 2022.0.x (x>5) and 2023.0.y (y>1) should be supported, but they aren't tested with this release.)
+
+### Spring Cloud Azure Dependencies (BOM)
+
+#### Dependency Updates
+- Upgrade `azure-sdk-bom` to 1.2.23.
+
+### Azure Spring Data Cosmos
+This section includes changes in `azure-spring-data-cosmos` module.
+Please refer to [azure-spring-data-cosmos/CHANGELOG.md](https://github.com/Azure/azure-sdk-for-java/blob/main/sdk/spring/azure-spring-data-cosmos/CHANGELOG.md#5120-2024-05-09) for more details.
+
 ## 4.18.0 (2024-05-07)
 - This release is compatible with Spring Boot 2.5.0-2.5.15, 2.6.0-2.6.15, 2.7.0-2.7.18. (Note: 2.5.x (x>15), 2.6.y (y>15) and 2.7.z (z>18) should be supported, but they aren't tested with this release.)
 - This release is compatible with Spring Cloud 2020.0.3-2020.0.6, 2021.0.0-2021.0.9. (Note: 2020.0.x (x>6) and 2021.0.y (y>9) should be supported, but they aren't tested with this release.)
diff --git a/sdk/spring/azure-spring-data-cosmos/CHANGELOG.md b/sdk/spring/azure-spring-data-cosmos/CHANGELOG.md
index ee1ac98b5886..f9cf51ba3a31 100644
--- a/sdk/spring/azure-spring-data-cosmos/CHANGELOG.md
+++ b/sdk/spring/azure-spring-data-cosmos/CHANGELOG.md
@@ -10,6 +10,18 @@
 
 #### Other Changes
 
+### 5.12.0 (2024-05-09)
+
+#### Features Added
+* Exposing the `indexQueryMetrics` to the `CosmosConfig` via the `application.properties` configuration file - See [PR 39623](https://github.com/Azure/azure-sdk-for-java/pull/39623).
+
+#### Bugs Fixed
+* Fixed all saveAll/insertAll bulk functionality to populated audit data - See [PR 39811](https://github.com/Azure/azure-sdk-for-java/pull/39811).
+* Fixed `existsById` API in `ReactiveCosmosTemplate` to return `Mono` containing `False` in case the item does not exist - See [PR 40050](https://github.com/Azure/azure-sdk-for-java/pull/40050).
+
+#### Other Changes
+* Updated `azure-cosmos` to version `4.58.0`.
+
 ### 3.45.0 (2024-05-07)
 
 #### Features Added
diff --git a/sdk/spring/spring-reference.yml b/sdk/spring/spring-reference.yml
index 43094715ba6a..f7d3d64cb201 100644
--- a/sdk/spring/spring-reference.yml
+++ b/sdk/spring/spring-reference.yml
@@ -8,12 +8,12 @@
       artifacts:
         - artifactId: spring-cloud-azure-dependencies
           groupId: com.azure.spring
-          versionGA: 4.17.0
-          versionPreview: 5.11.0
+          versionGA: 4.18.0
+          versionPreview: 5.12.0
           description: Bill of Materials (BOM) for Spring Cloud Azure support.
           type: spring
           links:
-            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.17.0/sdk/boms/spring-cloud-azure-dependencies
+            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.18.0/sdk/boms/spring-cloud-azure-dependencies
             msdocs: https://docs.microsoft.com/azure/developer/java/spring-framework/spring-cloud-azure#bill-of-material-bom
             repopath: https://search.maven.org/artifact/com.azure.spring/spring-cloud-azure-dependencies
           dependencyPattern:
@@ -37,32 +37,32 @@
                 
           springProperties:
             starter: false
-            compatibilityRange: "[2.5.0,3.2.4]"
+            compatibilityRange: "[2.5.0,3.2.5]"
             mappings:
               - compatibilityRange: "[2.5.0,2.5.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-dependencies
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.6.0,2.6.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-dependencies
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.7.0,2.7.18]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-dependencies
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[3.0.0,3.0.13]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-dependencies
-                version: 5.11.0
-              - compatibilityRange: "[3.1.0,3.1.10]"
+                version: 5.12.0
+              - compatibilityRange: "[3.1.0,3.1.11]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-dependencies
-                version: 5.11.0
-              - compatibilityRange: "[3.2.0,3.2.4]"
+                version: 5.12.0
+              - compatibilityRange: "[3.2.0,3.2.5]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-dependencies
-                version: 5.11.0
+                version: 5.12.0
 - name: Active Directory
   content:
     - name: Active Directory
@@ -73,8 +73,8 @@
       artifacts:
         - artifactId: spring-cloud-azure-starter-active-directory
           groupId: com.azure.spring
-          versionGA: 4.17.0
-          versionPreview: 5.11.0
+          versionGA: 4.18.0
+          versionPreview: 5.12.0
           description: |-
             Microsoft's Spring Boot Starter provides the most optimal way to connect your Web
             application to an Azure Active Directory (AAD for short) tenant and protect resource
@@ -82,39 +82,39 @@
             servers.
           type: spring
           links:
-            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.17.0/sdk/spring/spring-cloud-azure-starter-active-directory
+            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.18.0/sdk/spring/spring-cloud-azure-starter-active-directory
             msdocs: https://docs.microsoft.com/azure/developer/java/spring-framework/configure-spring-boot-starter-java-app-with-azure-active-directory
             repopath: https://search.maven.org/artifact/com.azure.spring/spring-cloud-azure-starter-active-directory
-            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.17.0/aad/spring-cloud-azure-starter-active-directory/
+            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.18.0/aad/spring-cloud-azure-starter-active-directory/
           springProperties:
             starter: true
             bom: spring-cloud-azure-dependencies
-            compatibilityRange: "[2.5.0,3.2.4]"
+            compatibilityRange: "[2.5.0,3.2.5]"
             mappings:
               - compatibilityRange: "[2.5.0,2.5.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-active-directory
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.6.0,2.6.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-active-directory
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.7.0,2.7.18]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-active-directory
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[3.0.0,3.0.13]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-active-directory
-                version: 5.11.0
-              - compatibilityRange: "[3.1.0,3.1.10]"
+                version: 5.12.0
+              - compatibilityRange: "[3.1.0,3.1.11]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-active-directory
-                version: 5.11.0
-              - compatibilityRange: "[3.2.0,3.2.4]"
+                version: 5.12.0
+              - compatibilityRange: "[3.2.0,3.2.5]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-active-directory
-                version: 5.11.0
+                version: 5.12.0
 - name: Active Directory B2C
   content:
     - name: Active Directory B2C
@@ -126,43 +126,43 @@
       artifacts:
         - artifactId: spring-cloud-azure-starter-active-directory-b2c
           groupId: com.azure.spring
-          versionGA: 4.17.0
-          versionPreview: 5.11.0
+          versionGA: 4.18.0
+          versionPreview: 5.12.0
           type: spring
           links:
-            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.17.0/sdk/spring/spring-cloud-azure-starter-active-directory-b2c
+            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.18.0/sdk/spring/spring-cloud-azure-starter-active-directory-b2c
             msdocs: https://docs.microsoft.com/azure/developer/java/spring-framework/configure-spring-boot-starter-java-app-with-azure-active-directory-b2c-oidc
             repopath: https://search.maven.org/artifact/com.azure.spring/spring-cloud-azure-starter-active-directory-b2c
-            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.17.0/aad/spring-cloud-azure-starter-active-directory-b2c/
+            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.18.0/aad/spring-cloud-azure-starter-active-directory-b2c/
           springProperties:
             starter: true
             bom: spring-cloud-azure-dependencies
-            compatibilityRange: "[2.5.0,3.2.4]"
+            compatibilityRange: "[2.5.0,3.2.5]"
             mappings:
               - compatibilityRange: "[2.5.0,2.5.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-active-directory-b2c
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.6.0,2.6.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-active-directory-b2c
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.7.0,2.7.18]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-active-directory-b2c
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[3.0.0,3.0.13]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-active-directory-b2c
-                version: 5.11.0
-              - compatibilityRange: "[3.1.0,3.1.10]"
+                version: 5.12.0
+              - compatibilityRange: "[3.1.0,3.1.11]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-active-directory-b2c
-                version: 5.11.0
-              - compatibilityRange: "[3.2.0,3.2.4]"
+                version: 5.12.0
+              - compatibilityRange: "[3.2.0,3.2.5]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-active-directory-b2c
-                version: 5.11.0
+                version: 5.12.0
 - name: App Configuration
   content:
     - name: App Configuration
@@ -177,86 +177,86 @@
       artifacts:
         - artifactId: spring-cloud-azure-starter-appconfiguration
           groupId: com.azure.spring
-          versionGA: 4.17.0
-          versionPreview: 5.11.0
+          versionGA: 4.18.0
+          versionPreview: 5.12.0
           description: |-
             Microsoft's Spring Boot Starter helps developers to finish the auto-configuration of
             Azure App Configuration.
           type: spring
           links:
-            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.17.0/sdk/spring/spring-cloud-azure-starter-appconfiguration
+            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.18.0/sdk/spring/spring-cloud-azure-starter-appconfiguration
             msdocs: https://docs.microsoft.com/azure/developer/java/spring-framework/spring-cloud-azure#auto-configure-azure-sdk-clients
             repopath: https://search.maven.org/artifact/com.azure.spring/spring-cloud-azure-starter-appconfiguration
-            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.17.0/appconfiguration/spring-cloud-azure-starter-appconfiguration/
+            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.18.0/appconfiguration/spring-cloud-azure-starter-appconfiguration/
           springProperties:
             starter: true
             bom: spring-cloud-azure-dependencies
-            compatibilityRange: "[2.5.0,3.2.4]"
+            compatibilityRange: "[2.5.0,3.2.5]"
             mappings:
               - compatibilityRange: "[2.5.0,2.5.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-appconfiguration
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.6.0,2.6.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-appconfiguration
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.7.0,2.7.18]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-appconfiguration
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[3.0.0,3.0.13]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-appconfiguration
-                version: 5.11.0
-              - compatibilityRange: "[3.1.0,3.1.10]"
+                version: 5.12.0
+              - compatibilityRange: "[3.1.0,3.1.11]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-appconfiguration
-                version: 5.11.0
-              - compatibilityRange: "[3.2.0,3.2.4]"
+                version: 5.12.0
+              - compatibilityRange: "[3.2.0,3.2.5]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-appconfiguration
-                version: 5.11.0
+                version: 5.12.0
         - artifactId: spring-cloud-azure-starter-appconfiguration-config
           groupId: com.azure.spring
-          versionGA: 4.17.0
-          versionPreview: 5.11.0
+          versionGA: 4.18.0
+          versionPreview: 5.12.0
           description: Microsoft's Spring Boot Starter helps developers to load properties
             and manage features from Azure App Configuration service for Spring Application.
           type: spring
           links:
-            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.17.0/sdk/spring/spring-cloud-azure-starter-appconfiguration-config
+            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.18.0/sdk/spring/spring-cloud-azure-starter-appconfiguration-config
             repopath: https://search.maven.org/artifact/com.azure.spring/spring-cloud-azure-starter-appconfiguration-config
-            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.17.0/appconfiguration/spring-cloud-azure-starter-appconfiguration-config/
+            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.18.0/appconfiguration/spring-cloud-azure-starter-appconfiguration-config/
           springProperties:
             starter: true
             bom: spring-cloud-azure-dependencies
-            compatibilityRange: "[2.5.0,3.2.4]"
+            compatibilityRange: "[2.5.0,3.2.5]"
             mappings:
               - compatibilityRange: "[2.5.0,2.5.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-appconfiguration-config
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.6.0,2.6.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-appconfiguration-config
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.7.0,2.7.18]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-appconfiguration-config
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[3.0.0,3.0.13]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-appconfiguration-config
-                version: 5.11.0
-              - compatibilityRange: "[3.1.0,3.1.10]"
+                version: 5.12.0
+              - compatibilityRange: "[3.1.0,3.1.11]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-appconfiguration-config
-                version: 5.11.0
-              - compatibilityRange: "[3.2.0,3.2.4]"
+                version: 5.12.0
+              - compatibilityRange: "[3.2.0,3.2.5]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-appconfiguration-config
-                version: 5.11.0
+                version: 5.12.0
 - name: Cosmos DB
   content:
     - name: Spring Data Cosmos
@@ -272,47 +272,47 @@
       artifacts:
         - artifactId: spring-cloud-azure-starter-data-cosmos
           groupId: com.azure.spring
-          versionGA: 4.17.0
-          versionPreview: 5.11.0
+          versionGA: 4.18.0
+          versionPreview: 5.12.0
           description: |-
             Microsoft's Spring Boot Starter helps developers to finish the auto-configuration of
             Spring Data Azure Cosmos DB, which enables developers to easily integrate with Azure Cosmos
             DB SQL API using Spring Data.
           type: spring
           links:
-            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.17.0/sdk/spring/spring-cloud-azure-starter-data-cosmos
+            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.18.0/sdk/spring/spring-cloud-azure-starter-data-cosmos
             msdocs: https://docs.microsoft.com/azure/developer/java/spring-framework/configure-spring-boot-starter-java-app-with-cosmos-db
             repopath: https://search.maven.org/artifact/com.azure.spring/spring-cloud-azure-starter-data-cosmos
-            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.17.0/cosmos/spring-cloud-azure-starter-data-cosmos/
+            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.18.0/cosmos/spring-cloud-azure-starter-data-cosmos/
           springProperties:
             starter: true
             bom: spring-cloud-azure-dependencies
-            compatibilityRange: "[2.5.0,3.2.4]"
+            compatibilityRange: "[2.5.0,3.2.5]"
             mappings:
               - compatibilityRange: "[2.5.0,2.5.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-data-cosmos
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.6.0,2.6.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-data-cosmos
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.7.0,2.7.18]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-data-cosmos
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[3.0.0,3.0.13]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-data-cosmos
-                version: 5.11.0
-              - compatibilityRange: "[3.1.0,3.1.10]"
+                version: 5.12.0
+              - compatibilityRange: "[3.1.0,3.1.11]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-data-cosmos
-                version: 5.11.0
-              - compatibilityRange: "[3.2.0,3.2.4]"
+                version: 5.12.0
+              - compatibilityRange: "[3.2.0,3.2.5]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-data-cosmos
-                version: 5.11.0
+                version: 5.12.0
     - name: Cosmos DB
       description: |-
         Azure Cosmos DB is a fully managed NoSQL database for modern app development.
@@ -323,46 +323,46 @@
       artifacts:
         - artifactId: spring-cloud-azure-starter-cosmos
           groupId: com.azure.spring
-          versionGA: 4.17.0
-          versionPreview: 5.11.0
+          versionGA: 4.18.0
+          versionPreview: 5.12.0
           description: |-
             Microsoft's Spring Boot Starter helps developers to finish the auto-configuration of
             Azure Cosmos DB, which enables developers to easily integrate with Azure Cosmos DB SQL API.
           type: spring
           links:
-            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.17.0/sdk/spring/spring-cloud-azure-starter-cosmos
+            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.18.0/sdk/spring/spring-cloud-azure-starter-cosmos
             msdocs: https://docs.microsoft.com/azure/developer/java/spring-framework/spring-cloud-azure#auto-configure-azure-sdk-clients
             repopath: https://search.maven.org/artifact/com.azure.spring/spring-cloud-azure-starter-cosmos
-            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.17.0/cosmos/spring-cloud-azure-starter-cosmos/
+            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.18.0/cosmos/spring-cloud-azure-starter-cosmos/
           springProperties:
             starter: true
             bom: spring-cloud-azure-dependencies
-            compatibilityRange: "[2.5.0,3.2.4]"
+            compatibilityRange: "[2.5.0,3.2.5]"
             mappings:
               - compatibilityRange: "[2.5.0,2.5.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-cosmos
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.6.0,2.6.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-cosmos
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.7.0,2.7.18]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-cosmos
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[3.0.0,3.0.13]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-cosmos
-                version: 5.11.0
-              - compatibilityRange: "[3.1.0,3.1.10]"
+                version: 5.12.0
+              - compatibilityRange: "[3.1.0,3.1.11]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-cosmos
-                version: 5.11.0
-              - compatibilityRange: "[3.2.0,3.2.4]"
+                version: 5.12.0
+              - compatibilityRange: "[3.2.0,3.2.5]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-cosmos
-                version: 5.11.0
+                version: 5.12.0
 - name: Key Vault
   content:
     - name: Key Vault
@@ -372,46 +372,46 @@
       artifacts:
         - artifactId: spring-cloud-azure-starter-keyvault
           groupId: com.azure.spring
-          versionGA: 4.17.0
-          versionPreview: 5.11.0
+          versionGA: 4.18.0
+          versionPreview: 5.12.0
           description: |-
             Microsoft's Spring Boot Starter helps developers to finish the auto-configuration of
             Azure Key Vault.
           type: spring
           links:
-            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.17.0/sdk/spring/spring-cloud-azure-starter-keyvault
+            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.18.0/sdk/spring/spring-cloud-azure-starter-keyvault
             msdocs: https://learn.microsoft.com/azure/key-vault/
             repopath: https://search.maven.org/artifact/com.azure.spring/spring-cloud-azure-starter-keyvault
-            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.17.0/keyvault/spring-cloud-azure-starter-keyvault/
+            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.18.0/keyvault/spring-cloud-azure-starter-keyvault/
           springProperties:
             starter: true
             bom: spring-cloud-azure-dependencies
-            compatibilityRange: "[2.5.0,3.2.4]"
+            compatibilityRange: "[2.5.0,3.2.5]"
             mappings:
               - compatibilityRange: "[2.5.0,2.5.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-keyvault
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.6.0,2.6.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-keyvault
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.7.0,2.7.18]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-keyvault
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[3.0.0,3.0.13]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-keyvault
-                version: 5.11.0
-              - compatibilityRange: "[3.1.0,3.1.10]"
+                version: 5.12.0
+              - compatibilityRange: "[3.1.0,3.1.11]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-keyvault
-                version: 5.11.0
-              - compatibilityRange: "[3.2.0,3.2.4]"
+                version: 5.12.0
+              - compatibilityRange: "[3.2.0,3.2.5]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-keyvault
-                version: 5.11.0
+                version: 5.12.0
     - name: Key Vault - Certificates
       description: |-
         Azure Key Vault enables Microsoft Azure applications and users to store and use certificates, which are
@@ -423,45 +423,45 @@
       artifacts:
         - artifactId: spring-cloud-azure-starter-keyvault-certificates
           groupId: com.azure.spring
-          versionGA: 4.17.0
-          versionPreview: 5.11.0
+          versionGA: 4.18.0
+          versionPreview: 5.12.0
           description: |-
             Microsoft's Spring Boot Starter helps developers to finish the auto-configuration of
             Azure Key Vault Certificates.
           type: spring
           links:
-            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.17.0/sdk/spring/spring-cloud-azure-starter-keyvault-certificates
+            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.18.0/sdk/spring/spring-cloud-azure-starter-keyvault-certificates
             msdocs: https://docs.microsoft.com/azure/developer/java/spring-framework/configure-spring-boot-starter-java-app-with-azure-key-vault-certificates
             repopath: https://search.maven.org/artifact/com.azure.spring/spring-cloud-azure-starter-keyvault-certificates
           springProperties:
             starter: true
             bom: spring-cloud-azure-dependencies
-            compatibilityRange: "[2.5.0,3.2.4]"
+            compatibilityRange: "[2.5.0,3.2.5]"
             mappings:
               - compatibilityRange: "[2.5.0,2.5.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-keyvault-certificates
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.6.0,2.6.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-keyvault-certificates
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.7.0,2.7.18]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-keyvault-certificates
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[3.0.0,3.0.13]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-keyvault-certificates
-                version: 5.11.0
-              - compatibilityRange: "[3.1.0,3.1.10]"
+                version: 5.12.0
+              - compatibilityRange: "[3.1.0,3.1.11]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-keyvault-certificates
-                version: 5.11.0
-              - compatibilityRange: "[3.2.0,3.2.4]"
+                version: 5.12.0
+              - compatibilityRange: "[3.2.0,3.2.5]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-keyvault-certificates
-                version: 5.11.0
+                version: 5.12.0
         - artifactId: azure-security-keyvault-jca
           groupId: com.azure
           versionGA: 2.8.0
@@ -485,8 +485,8 @@
       artifacts:
         - artifactId: spring-cloud-azure-starter-keyvault-secrets
           groupId: com.azure.spring
-          versionGA: 4.17.0
-          versionPreview: 5.11.0
+          versionGA: 4.18.0
+          versionPreview: 5.12.0
           description: |-
             Microsoft's Spring Boot Starter helps developers to finish the auto-configuration of
             Azure Key Vault Secrets, and adds Azure Key Vault as one of Spring PropertySource.
@@ -494,39 +494,39 @@
             externalized configuration property.
           type: spring
           links:
-            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.17.0/sdk/spring/spring-cloud-azure-starter-keyvault-secrets
+            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.18.0/sdk/spring/spring-cloud-azure-starter-keyvault-secrets
             msdocs: https://docs.microsoft.com/azure/developer/java/spring-framework/configure-spring-boot-starter-java-app-with-azure-key-vault
             repopath: https://search.maven.org/artifact/com.azure.spring/spring-cloud-azure-starter-keyvault-secrets
-            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.17.0/keyvault/spring-cloud-azure-starter-keyvault-secrets/
+            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.18.0/keyvault/spring-cloud-azure-starter-keyvault-secrets/
           springProperties:
             starter: true
             bom: spring-cloud-azure-dependencies
-            compatibilityRange: "[2.5.0,3.2.4]"
+            compatibilityRange: "[2.5.0,3.2.5]"
             mappings:
               - compatibilityRange: "[2.5.0,2.5.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-keyvault-secrets
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.6.0,2.6.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-keyvault-secrets
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.7.0,2.7.18]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-keyvault-secrets
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[3.0.0,3.0.13]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-keyvault-secrets
-                version: 5.11.0
-              - compatibilityRange: "[3.1.0,3.1.10]"
+                version: 5.12.0
+              - compatibilityRange: "[3.1.0,3.1.11]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-keyvault-secrets
-                version: 5.11.0
-              - compatibilityRange: "[3.2.0,3.2.4]"
+                version: 5.12.0
+              - compatibilityRange: "[3.2.0,3.2.5]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-keyvault-secrets
-                version: 5.11.0
+                version: 5.12.0
 - name: Storage
   content:
     - name: Storage
@@ -535,47 +535,47 @@
       artifacts:
         - artifactId: spring-cloud-azure-starter-storage
           groupId: com.azure.spring
-          versionGA: 4.17.0
-          versionPreview: 5.11.0
+          versionGA: 4.18.0
+          versionPreview: 5.12.0
           description: |-
             Microsoft's Spring Boot Starter helps developers to finish the auto-configuration of
             Azure Storage, and implements Spring Resource abstraction for Azure Storage
             service which allows you to interact with Storage Account using Spring programming model.
           type: spring
           links:
-            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.17.0/sdk/spring/spring-cloud-azure-starter-storage
+            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.18.0/sdk/spring/spring-cloud-azure-starter-storage
             msdocs: https://docs.microsoft.com/azure/storage/
             repopath: https://search.maven.org/artifact/com.azure.spring/spring-cloud-azure-starter-storage
-            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.17.0/storage/spring-cloud-azure-starter-storage/
+            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.18.0/storage/spring-cloud-azure-starter-storage/
           springProperties:
             starter: true
             bom: spring-cloud-azure-dependencies
-            compatibilityRange: "[2.5.0,3.2.4]"
+            compatibilityRange: "[2.5.0,3.2.5]"
             mappings:
               - compatibilityRange: "[2.5.0,2.5.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-storage
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.6.0,2.6.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-storage
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.7.0,2.7.18]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-storage
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[3.0.0,3.0.13]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-storage
-                version: 5.11.0
-              - compatibilityRange: "[3.1.0,3.1.10]"
+                version: 5.12.0
+              - compatibilityRange: "[3.1.0,3.1.11]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-storage
-                version: 5.11.0
-              - compatibilityRange: "[3.2.0,3.2.4]"
+                version: 5.12.0
+              - compatibilityRange: "[3.2.0,3.2.5]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-storage
-                version: 5.11.0
+                version: 5.12.0
     - name: Storage - Blobs
       description: |-
         Azure Blob Storage is Microsoft's object storage solution for the cloud. Blob Storage
@@ -589,47 +589,47 @@
       artifacts:
         - artifactId: spring-cloud-azure-starter-storage-blob
           groupId: com.azure.spring
-          versionGA: 4.17.0
-          versionPreview: 5.11.0
+          versionGA: 4.18.0
+          versionPreview: 5.12.0
           description: |-
             Microsoft's Spring Boot Starter helps developers to finish the auto-configuration of
             Azure Storage Blob, and implements Spring Resource abstraction for Azure Storage
             service which allows you to interact with Storage Blob using Spring programming model.
           type: spring
           links:
-            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.17.0/sdk/spring/spring-cloud-azure-starter-storage-blob
+            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.18.0/sdk/spring/spring-cloud-azure-starter-storage-blob
             msdocs: https://docs.microsoft.com/azure/developer/java/spring-framework/configure-spring-boot-starter-java-app-with-azure-storage
             repopath: https://search.maven.org/artifact/com.azure.spring/spring-cloud-azure-starter-storage-blob
-            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.17.0/storage/spring-cloud-azure-starter-storage-blob/
+            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.18.0/storage/spring-cloud-azure-starter-storage-blob/
           springProperties:
             starter: true
             bom: spring-cloud-azure-dependencies
-            compatibilityRange: "[2.5.0,3.2.4]"
+            compatibilityRange: "[2.5.0,3.2.5]"
             mappings:
               - compatibilityRange: "[2.5.0,2.5.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-storage-blob
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.6.0,2.6.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-storage-blob
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.7.0,2.7.18]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-storage-blob
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[3.0.0,3.0.13]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-storage-blob
-                version: 5.11.0
-              - compatibilityRange: "[3.1.0,3.1.10]"
+                version: 5.12.0
+              - compatibilityRange: "[3.1.0,3.1.11]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-storage-blob
-                version: 5.11.0
-              - compatibilityRange: "[3.2.0,3.2.4]"
+                version: 5.12.0
+              - compatibilityRange: "[3.2.0,3.2.5]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-storage-blob
-                version: 5.11.0
+                version: 5.12.0
     - name: Storage - Files Shares
       description: |-
         Azure File Share storage offers fully managed file shares in the cloud that are
@@ -644,47 +644,47 @@
       artifacts:
         - artifactId: spring-cloud-azure-starter-storage-file-share
           groupId: com.azure.spring
-          versionGA: 4.17.0
-          versionPreview: 5.11.0
+          versionGA: 4.18.0
+          versionPreview: 5.12.0
           description: |-
             Microsoft's Spring Boot Starter helps developers to finish the auto-configuration of
             Azure Storage File Share, and implements Spring Resource abstraction for Azure Storage
             service which allows you to interact with Storage File Share using Spring programming model.
           type: spring
           links:
-            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.17.0/sdk/spring/spring-cloud-azure-starter-storage-file-share
+            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.18.0/sdk/spring/spring-cloud-azure-starter-storage-file-share
             msdocs: https://docs.microsoft.com/azure/developer/java/spring-framework/spring-cloud-azure#resource-handling
             repopath: https://search.maven.org/artifact/com.azure.spring/spring-cloud-azure-starter-storage-file-share
-            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.17.0/storage/spring-cloud-azure-starter-storage-file-share/
+            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.18.0/storage/spring-cloud-azure-starter-storage-file-share/
           springProperties:
             starter: true
             bom: spring-cloud-azure-dependencies
-            compatibilityRange: "[2.5.0,3.2.4]"
+            compatibilityRange: "[2.5.0,3.2.5]"
             mappings:
               - compatibilityRange: "[2.5.0,2.5.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-storage-file-share
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.6.0,2.6.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-storage-file-share
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.7.0,2.7.18]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-storage-file-share
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[3.0.0,3.0.13]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-storage-file-share
-                version: 5.11.0
-              - compatibilityRange: "[3.1.0,3.1.10]"
+                version: 5.12.0
+              - compatibilityRange: "[3.1.0,3.1.11]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-storage-file-share
-                version: 5.11.0
-              - compatibilityRange: "[3.2.0,3.2.4]"
+                version: 5.12.0
+              - compatibilityRange: "[3.2.0,3.2.5]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-storage-file-share
-                version: 5.11.0
+                version: 5.12.0
     - name: Storage - Queues
       description: |-
         Azure Queue Storage is a service for storing large numbers of messages. You access
@@ -699,131 +699,131 @@
       artifacts:
         - artifactId: spring-cloud-azure-starter-storage-queue
           groupId: com.azure.spring
-          versionGA: 4.17.0
-          versionPreview: 5.11.0
+          versionGA: 4.18.0
+          versionPreview: 5.12.0
           description: |-
             Microsoft's Spring Boot Starter helps developers to finish the auto-configuration of
             Azure Storage Queue.
           type: spring
           links:
-            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.17.0/sdk/spring/spring-cloud-azure-starter-storage-queue
+            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.18.0/sdk/spring/spring-cloud-azure-starter-storage-queue
             msdocs: https://docs.microsoft.com/azure/developer/java/spring-framework/spring-cloud-azure#auto-configure-azure-sdk-clients
             repopath: https://search.maven.org/artifact/com.azure.spring/spring-cloud-azure-starter-storage-queue
-            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.17.0/storage/spring-cloud-azure-starter-storage-queue/
+            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.18.0/storage/spring-cloud-azure-starter-storage-queue/
           springProperties:
             starter: true
             bom: spring-cloud-azure-dependencies
-            compatibilityRange: "[2.5.0,3.2.4]"
+            compatibilityRange: "[2.5.0,3.2.5]"
             mappings:
               - compatibilityRange: "[2.5.0,2.5.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-storage-queue
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.6.0,2.6.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-storage-queue
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.7.0,2.7.18]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-storage-queue
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[3.0.0,3.0.13]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-storage-queue
-                version: 5.11.0
-              - compatibilityRange: "[3.1.0,3.1.10]"
+                version: 5.12.0
+              - compatibilityRange: "[3.1.0,3.1.11]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-storage-queue
-                version: 5.11.0
-              - compatibilityRange: "[3.2.0,3.2.4]"
+                version: 5.12.0
+              - compatibilityRange: "[3.2.0,3.2.5]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-storage-queue
-                version: 5.11.0
+                version: 5.12.0
         - artifactId: spring-cloud-azure-starter-integration-storage-queue
           groupId: com.azure.spring
-          versionGA: 4.17.0
-          versionPreview: 5.11.0
+          versionGA: 4.18.0
+          versionPreview: 5.12.0
           description: |-
             Microsoft's Spring Boot Starter helps developers to finish the auto-configuration of
             Spring Integration Azure Storage Queue.
           type: spring
           links:
-            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.17.0/sdk/spring/spring-cloud-azure-starter-integration-storage-queue
+            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.18.0/sdk/spring/spring-cloud-azure-starter-integration-storage-queue
             msdocs: https://docs.microsoft.com/azure/developer/java/spring-framework/configure-spring-boot-starter-java-app-with-azure-service-bus
             repopath: https://search.maven.org/artifact/com.azure.spring/spring-cloud-azure-starter-integration-storage-queue
-            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.17.0/storage/spring-cloud-azure-starter-integration-storage-queue/
+            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.18.0/storage/spring-cloud-azure-starter-integration-storage-queue/
           springProperties:
             starter: true
             bom: spring-cloud-azure-dependencies
-            compatibilityRange: "[2.5.0,3.2.4]"
+            compatibilityRange: "[2.5.0,3.2.5]"
             mappings:
               - compatibilityRange: "[2.5.0,2.5.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-integration-storage-queue
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.6.0,2.6.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-integration-storage-queue
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.7.0,2.7.18]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-integration-storage-queue
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[3.0.0,3.0.13]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-integration-storage-queue
-                version: 5.11.0
-              - compatibilityRange: "[3.1.0,3.1.10]"
+                version: 5.12.0
+              - compatibilityRange: "[3.1.0,3.1.11]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-integration-storage-queue
-                version: 5.11.0
-              - compatibilityRange: "[3.2.0,3.2.4]"
+                version: 5.12.0
+              - compatibilityRange: "[3.2.0,3.2.5]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-integration-storage-queue
-                version: 5.11.0
+                version: 5.12.0
         - artifactId: spring-integration-azure-storage-queue
           groupId: com.azure.spring
-          versionGA: 4.17.0
-          versionPreview: 5.11.0
+          versionGA: 4.18.0
+          versionPreview: 5.12.0
           description: |-
             Microsoft's Spring Integration extension for Azure Storage Queue. Spring Integration extends
             the Spring programming modoel to support well-known Enterprise Integration Patterns.
           type: spring
           links:
-            javadoc: https://azuresdkdocs.blob.core.windows.net/$web/java/spring-integration-azure-storage-queue/4.17.0/index.html
-            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.17.0/sdk/spring/spring-integration-azure-storage-queue
+            javadoc: https://azuresdkdocs.blob.core.windows.net/$web/java/spring-integration-azure-storage-queue/4.18.0/index.html
+            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.18.0/sdk/spring/spring-integration-azure-storage-queue
             msdocs: https://docs.microsoft.com/azure/developer/java/spring-framework/spring-cloud-azure#spring-integration-support
             repopath: https://search.maven.org/artifact/com.azure.spring/spring-integration-azure-storage-queue
-            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.17.0/storage/spring-integration-azure-storage-queue/
+            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.18.0/storage/spring-integration-azure-storage-queue/
           springProperties:
             starter: true
             bom: spring-cloud-azure-dependencies
-            compatibilityRange: "[2.5.0,3.2.4]"
+            compatibilityRange: "[2.5.0,3.2.5]"
             mappings:
               - compatibilityRange: "[2.5.0,2.5.15]"
                 groupId: com.azure.spring
                 artifactId: spring-integration-azure-storage-queue
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.6.0,2.6.15]"
                 groupId: com.azure.spring
                 artifactId: spring-integration-azure-storage-queue
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.7.0,2.7.18]"
                 groupId: com.azure.spring
                 artifactId: spring-integration-azure-storage-queue
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[3.0.0,3.0.13]"
                 groupId: com.azure.spring
                 artifactId: spring-integration-azure-storage-queue
-                version: 5.11.0
-              - compatibilityRange: "[3.1.0,3.1.10]"
+                version: 5.12.0
+              - compatibilityRange: "[3.1.0,3.1.11]"
                 groupId: com.azure.spring
                 artifactId: spring-integration-azure-storage-queue
-                version: 5.11.0
-              - compatibilityRange: "[3.2.0,3.2.4]"
+                version: 5.12.0
+              - compatibilityRange: "[3.2.0,3.2.5]"
                 groupId: com.azure.spring
                 artifactId: spring-integration-azure-storage-queue
-                version: 5.11.0
+                version: 5.12.0
 - name: Service Bus
   content:
     - name: Service Bus
@@ -839,175 +839,175 @@
       artifacts:
         - artifactId: spring-cloud-azure-starter-servicebus
           groupId: com.azure.spring
-          versionGA: 4.17.0
-          versionPreview: 5.11.0
+          versionGA: 4.18.0
+          versionPreview: 5.12.0
           description: |-
             Microsoft's Spring Boot Starter helps developers to finish the auto-configuration of
             Azure Service Bus.
           type: spring
           links:
-            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.17.0/sdk/spring/spring-cloud-azure-starter-servicebus
+            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.18.0/sdk/spring/spring-cloud-azure-starter-servicebus
             msdocs: https://docs.microsoft.com/azure/developer/java/spring-framework/spring-cloud-azure#auto-configure-azure-sdk-clients
             repopath: https://search.maven.org/artifact/com.azure.spring/spring-cloud-azure-starter-servicebus
-            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.17.0/servicebus/spring-cloud-azure-starter-servicebus/
+            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.18.0/servicebus/spring-cloud-azure-starter-servicebus/
           springProperties:
             starter: true
             bom: spring-cloud-azure-dependencies
-            compatibilityRange: "[2.5.0,3.2.4]"
+            compatibilityRange: "[2.5.0,3.2.5]"
             mappings:
               - compatibilityRange: "[2.5.0,2.5.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-servicebus
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.6.0,2.6.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-servicebus
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.7.0,2.7.18]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-servicebus
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[3.0.0,3.0.13]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-servicebus
-                version: 5.11.0
-              - compatibilityRange: "[3.1.0,3.1.10]"
+                version: 5.12.0
+              - compatibilityRange: "[3.1.0,3.1.11]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-servicebus
-                version: 5.11.0
-              - compatibilityRange: "[3.2.0,3.2.4]"
+                version: 5.12.0
+              - compatibilityRange: "[3.2.0,3.2.5]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-servicebus
-                version: 5.11.0
+                version: 5.12.0
         - artifactId: spring-cloud-azure-starter-integration-servicebus
           groupId: com.azure.spring
-          versionGA: 4.17.0
-          versionPreview: 5.11.0
+          versionGA: 4.18.0
+          versionPreview: 5.12.0
           description: |-
             Microsoft's Spring Boot Starter helps developers to finish the auto-configuration of
             Spring Integration Azure Service Bus.
           type: spring
           links:
-            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.17.0/sdk/spring/spring-cloud-azure-starter-integration-servicebus
+            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.18.0/sdk/spring/spring-cloud-azure-starter-integration-servicebus
             msdocs: https://docs.microsoft.com/azure/developer/java/spring-framework/configure-spring-boot-starter-java-app-with-azure-service-bus
             repopath: https://search.maven.org/artifact/com.azure.spring/spring-cloud-azure-starter-integration-servicebus
-            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.17.0/servicebus/spring-cloud-azure-starter-integration-servicebus/
+            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.18.0/servicebus/spring-cloud-azure-starter-integration-servicebus/
           springProperties:
             starter: true
             bom: spring-cloud-azure-dependencies
-            compatibilityRange: "[2.5.0,3.2.4]"
+            compatibilityRange: "[2.5.0,3.2.5]"
             mappings:
               - compatibilityRange: "[2.5.0,2.5.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-integration-servicebus
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.6.0,2.6.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-integration-servicebus
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.7.0,2.7.18]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-integration-servicebus
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[3.0.0,3.0.13]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-integration-servicebus
-                version: 5.11.0
-              - compatibilityRange: "[3.1.0,3.1.10]"
+                version: 5.12.0
+              - compatibilityRange: "[3.1.0,3.1.11]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-integration-servicebus
-                version: 5.11.0
-              - compatibilityRange: "[3.2.0,3.2.4]"
+                version: 5.12.0
+              - compatibilityRange: "[3.2.0,3.2.5]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-integration-servicebus
-                version: 5.11.0
+                version: 5.12.0
         - artifactId: spring-integration-azure-servicebus
           groupId: com.azure.spring
-          versionGA: 4.17.0
-          versionPreview: 5.11.0
+          versionGA: 4.18.0
+          versionPreview: 5.12.0
           description: |-
             Microsoft's Spring Integration extension for Azure Service Bus. Spring Integration extends
             the Spring programming modoel to support well-known Enterprise Integration Patterns.
           type: spring
           links:
-            javadoc: https://azuresdkdocs.blob.core.windows.net/$web/java/spring-integration-azure-servicebus/4.17.0/index.html
-            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.17.0/sdk/spring/spring-integration-azure-servicebus
+            javadoc: https://azuresdkdocs.blob.core.windows.net/$web/java/spring-integration-azure-servicebus/4.18.0/index.html
+            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.18.0/sdk/spring/spring-integration-azure-servicebus
             msdocs: https://docs.microsoft.com/azure/developer/java/spring-framework/spring-cloud-azure#spring-integration-support
             repopath: https://search.maven.org/artifact/com.azure.spring/spring-integration-azure-servicebus
-            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.17.0/servicebus/spring-integration-azure-servicebus/
+            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.18.0/servicebus/spring-integration-azure-servicebus/
           springProperties:
             starter: true
             bom: spring-cloud-azure-dependencies
-            compatibilityRange: "[2.5.0,3.2.4]"
+            compatibilityRange: "[2.5.0,3.2.5]"
             mappings:
               - compatibilityRange: "[2.5.0,2.5.15]"
                 groupId: com.azure.spring
                 artifactId: spring-integration-azure-servicebus
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.6.0,2.6.15]"
                 groupId: com.azure.spring
                 artifactId: spring-integration-azure-servicebus
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.7.0,2.7.18]"
                 groupId: com.azure.spring
                 artifactId: spring-integration-azure-servicebus
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[3.0.0,3.0.13]"
                 groupId: com.azure.spring
                 artifactId: spring-integration-azure-servicebus
-                version: 5.11.0
-              - compatibilityRange: "[3.1.0,3.1.10]"
+                version: 5.12.0
+              - compatibilityRange: "[3.1.0,3.1.11]"
                 groupId: com.azure.spring
                 artifactId: spring-integration-azure-servicebus
-                version: 5.11.0
-              - compatibilityRange: "[3.2.0,3.2.4]"
+                version: 5.12.0
+              - compatibilityRange: "[3.2.0,3.2.5]"
                 groupId: com.azure.spring
                 artifactId: spring-integration-azure-servicebus
-                version: 5.11.0
+                version: 5.12.0
         - artifactId: spring-cloud-azure-stream-binder-servicebus
           groupId: com.azure.spring
-          versionGA: 4.17.0
-          versionPreview: 5.11.0
+          versionGA: 4.18.0
+          versionPreview: 5.12.0
           description: |-
             Microsoft's Spring Cloud Stream Binder provides Spring Cloud Stream Binder for Azure
             Service Bus which allows you to build message-driven microservice using Spring Cloud
             Stream based on Azure Service Bus.
           type: spring
           links:
-            javadoc: https://azuresdkdocs.blob.core.windows.net/$web/java/spring-cloud-azure-stream-binder-servicebus/4.17.0/index.html
-            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.17.0/sdk/spring/spring-cloud-azure-stream-binder-servicebus
+            javadoc: https://azuresdkdocs.blob.core.windows.net/$web/java/spring-cloud-azure-stream-binder-servicebus/4.18.0/index.html
+            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.18.0/sdk/spring/spring-cloud-azure-stream-binder-servicebus
             msdocs: https://docs.microsoft.com/azure/developer/java/spring-framework/configure-spring-cloud-stream-binder-java-app-with-service-bus
             repopath: https://search.maven.org/artifact/com.azure.spring/spring-cloud-azure-stream-binder-servicebus
-            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.17.0/servicebus/spring-cloud-azure-stream-binder-servicebus/
+            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.18.0/servicebus/spring-cloud-azure-stream-binder-servicebus/
           springProperties:
             starter: true
             bom: spring-cloud-azure-dependencies
-            compatibilityRange: "[2.5.0,3.2.4]"
+            compatibilityRange: "[2.5.0,3.2.5]"
             mappings:
               - compatibilityRange: "[2.5.0,2.5.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-stream-binder-servicebus
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.6.0,2.6.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-stream-binder-servicebus
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.7.0,2.7.18]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-stream-binder-servicebus
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[3.0.0,3.0.13]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-stream-binder-servicebus
-                version: 5.11.0
-              - compatibilityRange: "[3.1.0,3.1.10]"
+                version: 5.12.0
+              - compatibilityRange: "[3.1.0,3.1.11]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-stream-binder-servicebus
-                version: 5.11.0
-              - compatibilityRange: "[3.2.0,3.2.4]"
+                version: 5.12.0
+              - compatibilityRange: "[3.2.0,3.2.5]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-stream-binder-servicebus
-                version: 5.11.0
+                version: 5.12.0
     - name: Service Bus JMS
       description: |-
         Microsoft Azure Service Bus is a fully managed enterprise integration message broker.
@@ -1018,46 +1018,46 @@
       artifacts:
         - artifactId: spring-cloud-azure-starter-servicebus-jms
           groupId: com.azure.spring
-          versionGA: 4.17.0
-          versionPreview: 5.11.0
+          versionGA: 4.18.0
+          versionPreview: 5.12.0
           description: |-
             Microsoft's Spring Boot Starter helps developers to finish the auto-configuration of
             Spring JMS with Azure Service Bus Queue and Topic.
           type: spring
           links:
-            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.17.0/sdk/spring/spring-cloud-azure-starter-servicebus-jms
+            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.18.0/sdk/spring/spring-cloud-azure-starter-servicebus-jms
             msdocs: https://docs.microsoft.com/azure/developer/java/spring-framework/configure-spring-boot-starter-java-app-with-azure-service-bus
             repopath: https://search.maven.org/artifact/com.azure.spring/spring-cloud-azure-starter-servicebus-jms
-            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.17.0/servicebus/spring-cloud-azure-starter-servicebus-jms/
+            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.18.0/servicebus/spring-cloud-azure-starter-servicebus-jms/
           springProperties:
             starter: true
             bom: spring-cloud-azure-dependencies
-            compatibilityRange: "[2.5.0,3.2.4]"
+            compatibilityRange: "[2.5.0,3.2.5]"
             mappings:
               - compatibilityRange: "[2.5.0,2.5.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-servicebus-jms
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.6.0,2.6.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-servicebus-jms
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.7.0,2.7.18]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-servicebus-jms
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[3.0.0,3.0.13]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-servicebus-jms
-                version: 5.11.0
-              - compatibilityRange: "[3.1.0,3.1.10]"
+                version: 5.12.0
+              - compatibilityRange: "[3.1.0,3.1.11]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-servicebus-jms
-                version: 5.11.0
-              - compatibilityRange: "[3.2.0,3.2.4]"
+                version: 5.12.0
+              - compatibilityRange: "[3.2.0,3.2.5]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-servicebus-jms
-                version: 5.11.0
+                version: 5.12.0
 - name: Event Grid
   content:
     - name: Event Grid
@@ -1079,46 +1079,46 @@
       artifacts:
         - artifactId: spring-cloud-azure-starter-eventgrid
           groupId: com.azure.spring
-          versionGA: 4.17.0
-          versionPreview: 5.11.0
+          versionGA: 4.18.0
+          versionPreview: 5.12.0
           description: |-
             Microsoft's Spring Boot Starter helps developers to finish the auto-configuration of
             Azure Event Grid.
           type: spring
           links:
-            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.17.0/sdk/spring/spring-cloud-azure-starter-eventgrid
+            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.18.0/sdk/spring/spring-cloud-azure-starter-eventgrid
             msdocs: https://learn.microsoft.com/azure/developer/java/spring-framework/configure-spring-boot-initializer-java-app-with-event-grid
             repopath: https://search.maven.org/artifact/com.azure.spring/spring-cloud-azure-starter-eventgrid
-            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.17.0/eventgrid/spring-cloud-azure-starter-eventgrid/
+            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.18.0/eventgrid/spring-cloud-azure-starter-eventgrid/
           springProperties:
             starter: true
             bom: spring-cloud-azure-dependencies
-            compatibilityRange: "[2.5.0,3.2.4]"
+            compatibilityRange: "[2.5.0,3.2.5]"
             mappings:
               - compatibilityRange: "[2.5.0,2.5.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-eventgrid
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.6.0,2.6.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-eventgrid
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.7.0,2.7.18]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-eventgrid
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[3.0.0,3.0.13]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-eventgrid
-                version: 5.11.0
-              - compatibilityRange: "[3.1.0,3.1.10]"
+                version: 5.12.0
+              - compatibilityRange: "[3.1.0,3.1.11]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-eventgrid
-                version: 5.11.0
-              - compatibilityRange: "[3.2.0,3.2.4]"
+                version: 5.12.0
+              - compatibilityRange: "[3.2.0,3.2.5]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-eventgrid
-                version: 5.11.0
+                version: 5.12.0
 - name: Event Hubs
   content:
     - name: Event Hubs
@@ -1134,175 +1134,175 @@
       artifacts:
         - artifactId: spring-cloud-azure-starter-eventhubs
           groupId: com.azure.spring
-          versionGA: 4.17.0
-          versionPreview: 5.11.0
+          versionGA: 4.18.0
+          versionPreview: 5.12.0
           description: |-
             Microsoft's Spring Boot Starter helps developers to finish the auto-configuration of
             Azure Event Hubs.
           type: spring
           links:
-            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.17.0/sdk/spring/spring-cloud-azure-starter-eventhubs
+            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.18.0/sdk/spring/spring-cloud-azure-starter-eventhubs
             msdocs: https://docs.microsoft.com/azure/developer/java/spring-framework/spring-cloud-azure#auto-configure-azure-sdk-clients
             repopath: https://search.maven.org/artifact/com.azure.spring/spring-cloud-azure-starter-eventhubs
-            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.17.0/eventhubs/spring-cloud-azure-starter-eventhubs/
+            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.18.0/eventhubs/spring-cloud-azure-starter-eventhubs/
           springProperties:
             starter: true
             bom: spring-cloud-azure-dependencies
-            compatibilityRange: "[2.5.0,3.2.4]"
+            compatibilityRange: "[2.5.0,3.2.5]"
             mappings:
               - compatibilityRange: "[2.5.0,2.5.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-eventhubs
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.6.0,2.6.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-eventhubs
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.7.0,2.7.18]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-eventhubs
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[3.0.0,3.0.13]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-eventhubs
-                version: 5.11.0
-              - compatibilityRange: "[3.1.0,3.1.10]"
+                version: 5.12.0
+              - compatibilityRange: "[3.1.0,3.1.11]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-eventhubs
-                version: 5.11.0
-              - compatibilityRange: "[3.2.0,3.2.4]"
+                version: 5.12.0
+              - compatibilityRange: "[3.2.0,3.2.5]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-eventhubs
-                version: 5.11.0
+                version: 5.12.0
         - artifactId: spring-cloud-azure-starter-integration-eventhubs
           groupId: com.azure.spring
-          versionGA: 4.17.0
-          versionPreview: 5.11.0
+          versionGA: 4.18.0
+          versionPreview: 5.12.0
           description: |-
             Microsoft's Spring Boot Starter helps developers to finish the auto-configuration of
             Spring Integration Azure Event Hubs.
           type: spring
           links:
-            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.17.0/sdk/spring/spring-cloud-azure-starter-integration-eventhubs
+            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.18.0/sdk/spring/spring-cloud-azure-starter-integration-eventhubs
             msdocs: https://docs.microsoft.com/azure/developer/java/spring-framework/configure-spring-boot-starter-java-app-with-azure-service-bus
             repopath: https://search.maven.org/artifact/com.azure.spring/spring-cloud-azure-starter-integration-eventhubs
-            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.17.0/eventhubs/spring-cloud-azure-starter-integration-eventhubs/
+            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.18.0/eventhubs/spring-cloud-azure-starter-integration-eventhubs/
           springProperties:
             starter: true
             bom: spring-cloud-azure-dependencies
-            compatibilityRange: "[2.5.0,3.2.4]"
+            compatibilityRange: "[2.5.0,3.2.5]"
             mappings:
               - compatibilityRange: "[2.5.0,2.5.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-integration-eventhubs
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.6.0,2.6.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-integration-eventhubs
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.7.0,2.7.18]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-integration-eventhubs
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[3.0.0,3.0.13]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-integration-eventhubs
-                version: 5.11.0
-              - compatibilityRange: "[3.1.0,3.1.10]"
+                version: 5.12.0
+              - compatibilityRange: "[3.1.0,3.1.11]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-integration-eventhubs
-                version: 5.11.0
-              - compatibilityRange: "[3.2.0,3.2.4]"
+                version: 5.12.0
+              - compatibilityRange: "[3.2.0,3.2.5]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-integration-eventhubs
-                version: 5.11.0
+                version: 5.12.0
         - artifactId: spring-integration-azure-eventhubs
           groupId: com.azure.spring
-          versionGA: 4.17.0
-          versionPreview: 5.11.0
+          versionGA: 4.18.0
+          versionPreview: 5.12.0
           description: |-
             Microsoft's Spring Integration extension for Azure Event Hubs. Spring Integration extends
             the Spring programming modoel to support well-known Enterprise Integration Patterns.
           type: spring
           links:
-            javadoc: https://azuresdkdocs.blob.core.windows.net/$web/java/spring-integration-azure-eventhubs/4.17.0/index.html
-            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.17.0/sdk/spring/spring-integration-azure-eventhubs
+            javadoc: https://azuresdkdocs.blob.core.windows.net/$web/java/spring-integration-azure-eventhubs/4.18.0/index.html
+            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.18.0/sdk/spring/spring-integration-azure-eventhubs
             msdocs: https://docs.microsoft.com/azure/developer/java/spring-framework/spring-cloud-azure#spring-integration-support
             repopath: https://search.maven.org/artifact/com.azure.spring/spring-integration-azure-eventhubs
-            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.17.0/eventhubs/spring-integration-azure-eventhubs/
+            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.18.0/eventhubs/spring-integration-azure-eventhubs/
           springProperties:
             starter: true
             bom: spring-cloud-azure-dependencies
-            compatibilityRange: "[2.5.0,3.2.4]"
+            compatibilityRange: "[2.5.0,3.2.5]"
             mappings:
               - compatibilityRange: "[2.5.0,2.5.15]"
                 groupId: com.azure.spring
                 artifactId: spring-integration-azure-eventhubs
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.6.0,2.6.15]"
                 groupId: com.azure.spring
                 artifactId: spring-integration-azure-eventhubs
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.7.0,2.7.18]"
                 groupId: com.azure.spring
                 artifactId: spring-integration-azure-eventhubs
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[3.0.0,3.0.13]"
                 groupId: com.azure.spring
                 artifactId: spring-integration-azure-eventhubs
-                version: 5.11.0
-              - compatibilityRange: "[3.1.0,3.1.10]"
+                version: 5.12.0
+              - compatibilityRange: "[3.1.0,3.1.11]"
                 groupId: com.azure.spring
                 artifactId: spring-integration-azure-eventhubs
-                version: 5.11.0
-              - compatibilityRange: "[3.2.0,3.2.4]"
+                version: 5.12.0
+              - compatibilityRange: "[3.2.0,3.2.5]"
                 groupId: com.azure.spring
                 artifactId: spring-integration-azure-eventhubs
-                version: 5.11.0
+                version: 5.12.0
         - artifactId: spring-cloud-azure-stream-binder-eventhubs
           groupId: com.azure.spring
-          versionGA: 4.17.0
-          versionPreview: 5.11.0
+          versionGA: 4.18.0
+          versionPreview: 5.12.0
           description: |-
             Microsoft's Spring Cloud Stream Binder provides Spring Cloud Stream Binder for Azure
             Event Hubs which allows you to build message-driven microservice using Spring Cloud
             Stream based on Azure Event Hubs.
           type: spring
           links:
-            javadoc: https://azuresdkdocs.blob.core.windows.net/$web/java/spring-cloud-azure-stream-binder-eventhubs/4.17.0/index.html
-            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.17.0/sdk/spring/spring-cloud-azure-stream-binder-eventhubs
+            javadoc: https://azuresdkdocs.blob.core.windows.net/$web/java/spring-cloud-azure-stream-binder-eventhubs/4.18.0/index.html
+            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.18.0/sdk/spring/spring-cloud-azure-stream-binder-eventhubs
             msdocs: https://docs.microsoft.com/azure/developer/java/spring-framework/spring-cloud-azure#spring-cloud-stream-binder-for-azure-event-hubs
             repopath: https://search.maven.org/artifact/com.azure.spring/spring-cloud-azure-stream-binder-eventhubs
-            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.17.0/eventhubs/spring-cloud-azure-stream-binder-eventhubs/
+            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.18.0/eventhubs/spring-cloud-azure-stream-binder-eventhubs/
           springProperties:
             starter: true
             bom: spring-cloud-azure-dependencies
-            compatibilityRange: "[2.5.0,3.2.4]"
+            compatibilityRange: "[2.5.0,3.2.5]"
             mappings:
               - compatibilityRange: "[2.5.0,2.5.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-stream-binder-eventhubs
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.6.0,2.6.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-stream-binder-eventhubs
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.7.0,2.7.18]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-stream-binder-eventhubs
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[3.0.0,3.0.13]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-stream-binder-eventhubs
-                version: 5.11.0
-              - compatibilityRange: "[3.1.0,3.1.10]"
+                version: 5.12.0
+              - compatibilityRange: "[3.1.0,3.1.11]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-stream-binder-eventhubs
-                version: 5.11.0
-              - compatibilityRange: "[3.2.0,3.2.4]"
+                version: 5.12.0
+              - compatibilityRange: "[3.2.0,3.2.5]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-stream-binder-eventhubs
-                version: 5.11.0
+                version: 5.12.0
 - name: MySQL
   content:
     - name: Database for MySQL
@@ -1314,46 +1314,46 @@
       artifacts:
         - artifactId: spring-cloud-azure-starter-jdbc-mysql
           groupId: com.azure.spring
-          versionGA: 4.17.0
-          versionPreview: 5.11.0
+          versionGA: 4.18.0
+          versionPreview: 5.12.0
           description: |-
             Microsoft's Spring Boot Starter helps developers to finish the auto-configuration of
             Azure Database for MySQL.
           type: spring
           links:
-            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.17.0/sdk/spring/spring-cloud-azure-starter-jdbc-mysql
+            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.18.0/sdk/spring/spring-cloud-azure-starter-jdbc-mysql
             msdocs: https://docs.microsoft.com/azure/developer/java/spring-framework/spring-cloud-azure#auto-configure-azure-sdk-clients
             repopath: https://search.maven.org/artifact/com.azure.spring/spring-cloud-azure-starter-jdbc-mysql
-            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.17.0/mysql/spring-cloud-azure-starter-jdbc-mysql/
+            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.18.0/mysql/spring-cloud-azure-starter-jdbc-mysql/
           springProperties:
             starter: true
             bom: spring-cloud-azure-dependencies
-            compatibilityRange: "[2.5.0,3.2.4]"
+            compatibilityRange: "[2.5.0,3.2.5]"
             mappings:
               - compatibilityRange: "[2.5.0,2.5.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-jdbc-mysql
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.6.0,2.6.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-jdbc-mysql
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.7.0,2.7.18]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-jdbc-mysql
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[3.0.0,3.0.13]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-jdbc-mysql
-                version: 5.11.0
-              - compatibilityRange: "[3.1.0,3.1.10]"
+                version: 5.12.0
+              - compatibilityRange: "[3.1.0,3.1.11]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-jdbc-mysql
-                version: 5.11.0
-              - compatibilityRange: "[3.2.0,3.2.4]"
+                version: 5.12.0
+              - compatibilityRange: "[3.2.0,3.2.5]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-jdbc-mysql
-                version: 5.11.0
+                version: 5.12.0
 - name: PostgreSQL
   content:
     - name: Database for PostgreSQL
@@ -1365,43 +1365,43 @@
       artifacts:
         - artifactId: spring-cloud-azure-starter-jdbc-postgresql
           groupId: com.azure.spring
-          versionGA: 4.17.0
-          versionPreview: 5.11.0
+          versionGA: 4.18.0
+          versionPreview: 5.12.0
           description: |-
             Microsoft's Spring Boot Starter helps developers to finish the auto-configuration of
             Azure Database for PostgreSQL.
           type: spring
           links:
-            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.17.0/sdk/spring/spring-cloud-azure-starter-jdbc-postgresql
+            github: https://github.com/Azure/azure-sdk-for-java/tree/spring-cloud-azure_4.18.0/sdk/spring/spring-cloud-azure-starter-jdbc-postgresql
             msdocs: https://docs.microsoft.com/azure/developer/java/spring-framework/spring-cloud-azure#auto-configure-azure-sdk-clients
             repopath: https://search.maven.org/artifact/com.azure.spring/spring-cloud-azure-starter-jdbc-postgresql
-            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.17.0/postgresql/spring-cloud-azure-starter-jdbc-postgresql/
+            sample: https://github.com/Azure-Samples/azure-spring-boot-samples/tree/spring-cloud-azure_4.18.0/postgresql/spring-cloud-azure-starter-jdbc-postgresql/
           springProperties:
             starter: true
             bom: spring-cloud-azure-dependencies
-            compatibilityRange: "[2.5.0,3.2.4]"
+            compatibilityRange: "[2.5.0,3.2.5]"
             mappings:
               - compatibilityRange: "[2.5.0,2.5.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-jdbc-postgresql
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.6.0,2.6.15]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-jdbc-postgresql
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[2.7.0,2.7.18]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-jdbc-postgresql
-                version: 4.17.0
+                version: 4.18.0
               - compatibilityRange: "[3.0.0,3.0.13]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-jdbc-postgresql
-                version: 5.11.0
-              - compatibilityRange: "[3.1.0,3.1.10]"
+                version: 5.12.0
+              - compatibilityRange: "[3.1.0,3.1.11]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-jdbc-postgresql
-                version: 5.11.0
-              - compatibilityRange: "[3.2.0,3.2.4]"
+                version: 5.12.0
+              - compatibilityRange: "[3.2.0,3.2.5]"
                 groupId: com.azure.spring
                 artifactId: spring-cloud-azure-starter-jdbc-postgresql
-                version: 5.11.0
+                version: 5.12.0