diff --git a/eng/code-quality-reports/src/main/resources/spotbugs/spotbugs-exclude.xml b/eng/code-quality-reports/src/main/resources/spotbugs/spotbugs-exclude.xml index 885e270e1ba4c..7df72d00e293d 100755 --- a/eng/code-quality-reports/src/main/resources/spotbugs/spotbugs-exclude.xml +++ b/eng/code-quality-reports/src/main/resources/spotbugs/spotbugs-exclude.xml @@ -150,7 +150,7 @@ - + @@ -2732,7 +2732,7 @@ - + diff --git a/eng/common/pipelines/templates/steps/docs-metadata-release.yml b/eng/common/pipelines/templates/steps/docs-metadata-release.yml index 2f58b90d4d10e..7b6fb183a54ee 100644 --- a/eng/common/pipelines/templates/steps/docs-metadata-release.yml +++ b/eng/common/pipelines/templates/steps/docs-metadata-release.yml @@ -81,7 +81,7 @@ steps: - ${{ if parameters.SparseCheckoutPaths }}: - template: /eng/common/pipelines/templates/steps/sparse-checkout.yml parameters: - SkipDefaultCheckout: true + SkipCheckoutNone: true Repositories: - Name: ${{ parameters.TargetDocRepoOwner }}/${{ parameters.TargetDocRepoName }} WorkingDirectory: ${{ parameters.WorkingDirectory }}/repo diff --git a/eng/common/pipelines/templates/steps/sparse-checkout.yml b/eng/common/pipelines/templates/steps/sparse-checkout.yml index 0a2b537be1a93..39d5a7bff17dc 100644 --- a/eng/common/pipelines/templates/steps/sparse-checkout.yml +++ b/eng/common/pipelines/templates/steps/sparse-checkout.yml @@ -8,13 +8,17 @@ parameters: - Name: $(Build.Repository.Name) Commitish: $(Build.SourceVersion) WorkingDirectory: $(System.DefaultWorkingDirectory) + # NOTE: SkipDefaultCheckout is being deprecated in favor of SkipCheckoutNone - name: SkipDefaultCheckout type: boolean default: false + - name: SkipCheckoutNone + type: boolean + default: false steps: - - ${{ if not(parameters.SkipDefaultCheckout) }}: - - checkout: none + - ${{ if and(not(parameters.SkipDefaultCheckout), not(parameters.SkipCheckoutNone)) }}: + - checkout: none - task: PowerShell@2 displayName: 'Sparse checkout repositories' diff --git a/eng/common/pipelines/templates/steps/update-docsms-metadata.yml b/eng/common/pipelines/templates/steps/update-docsms-metadata.yml index 571d62fc2aa75..2635ad479432b 100644 --- a/eng/common/pipelines/templates/steps/update-docsms-metadata.yml +++ b/eng/common/pipelines/templates/steps/update-docsms-metadata.yml @@ -46,7 +46,7 @@ steps: - template: /eng/common/pipelines/templates/steps/sparse-checkout.yml parameters: - SkipDefaultCheckout: true + SkipCheckoutNone: true Repositories: - Name: ${{ parameters.TargetDocRepoOwner }}/${{ parameters.TargetDocRepoName }} WorkingDirectory: $(DocRepoLocation) @@ -76,7 +76,7 @@ steps: displayName: Checkout daily docs branch if it exists workingDirectory: $(DocRepoLocation) - # If NOT performing a daily docs build, set the $(TargetBranchName) to the + # If NOT performing a daily docs build, set the $(TargetBranchName) to the # default branch of the documentation repository. - ${{ if ne(parameters.DailyDocsBuild, 'true') }}: - template: /eng/common/pipelines/templates/steps/set-default-branch.yml @@ -103,7 +103,7 @@ steps: -PackageSourceOverride '${{ parameters.PackageSourceOverride }}' ` -TenantId '$(opensource-aad-tenant-id)' ` -ClientId '$(opensource-aad-app-id)' ` - -ClientSecret '$(opensource-aad-secret)' + -ClientSecret '$(opensource-aad-secret)' displayName: Apply Documentation Updates - template: /eng/common/pipelines/templates/steps/git-push-changes.yml diff --git a/eng/jacoco-test-coverage/pom.xml b/eng/jacoco-test-coverage/pom.xml index 5ea3d5bde7174..79f6594a913f1 100644 --- a/eng/jacoco-test-coverage/pom.xml +++ b/eng/jacoco-test-coverage/pom.xml @@ -123,12 +123,12 @@ com.azure azure-core - 1.32.0-beta.1 + 1.32.0 com.azure azure-core-amqp - 2.8.0-beta.1 + 2.7.1 com.azure @@ -148,17 +148,17 @@ com.azure azure-core-http-netty - 1.13.0-beta.1 + 1.12.5 com.azure azure-core-http-okhttp - 1.12.0-beta.1 + 1.11.2 com.azure azure-core-management - 1.8.0-beta.1 + 1.8.0 com.azure @@ -168,12 +168,12 @@ com.azure azure-core-serializer-json-gson - 1.2.0-beta.1 + 1.1.20 com.azure azure-core-serializer-json-jackson - 1.3.0-beta.1 + 1.2.21 com.azure diff --git a/eng/versioning/version_client.txt b/eng/versioning/version_client.txt index 750ecf348eef1..e397040b23ac4 100644 --- a/eng/versioning/version_client.txt +++ b/eng/versioning/version_client.txt @@ -69,22 +69,22 @@ com.azure:azure-communication-jobrouter;1.0.0-beta.1;1.0.0-beta.1 com.azure:azure-communication-rooms;1.0.0-beta.2;1.0.0-beta.3 com.azure:azure-containers-containerregistry;1.0.7;1.1.0-beta.2 com.azure:azure-containers-containerregistry-perf;1.0.0-beta.1;1.0.0-beta.1 -com.azure:azure-core;1.31.0;1.32.0-beta.1 -com.azure:azure-core-amqp;2.7.0;2.8.0-beta.1 +com.azure:azure-core;1.31.0;1.32.0 +com.azure:azure-core-amqp;2.7.0;2.7.1 com.azure:azure-core-amqp-experimental;1.0.0-beta.1;1.0.0-beta.1 com.azure:azure-core-experimental;1.0.0-beta.31;1.0.0-beta.32 com.azure:azure-core-http-jdk-httpclient;1.0.0-beta.1;1.0.0-beta.1 -com.azure:azure-core-http-netty;1.12.4;1.13.0-beta.1 -com.azure:azure-core-http-okhttp;1.11.1;1.12.0-beta.1 +com.azure:azure-core-http-netty;1.12.4;1.12.5 +com.azure:azure-core-http-okhttp;1.11.1;1.11.2 com.azure:azure-core-http-vertx;1.0.0-beta.1;1.0.0-beta.1 -com.azure:azure-core-management;1.7.1;1.8.0-beta.1 +com.azure:azure-core-management;1.7.1;1.8.0 com.azure:azure-core-metrics-opentelemetry;1.0.0-beta.1;1.0.0-beta.1 com.azure:azure-core-perf;1.0.0-beta.1;1.0.0-beta.1 com.azure:azure-core-serializer-avro-apache;1.0.0-beta.27;1.0.0-beta.28 com.azure:azure-core-serializer-avro-jackson;1.0.0-beta.1;1.0.0-beta.2 -com.azure:azure-core-serializer-json-gson;1.1.19;1.2.0-beta.1 -com.azure:azure-core-serializer-json-jackson;1.2.20;1.3.0-beta.1 -com.azure:azure-core-test;1.11.0;1.12.0-beta.1 +com.azure:azure-core-serializer-json-gson;1.1.19;1.1.20 +com.azure:azure-core-serializer-json-jackson;1.2.20;1.2.21 +com.azure:azure-core-test;1.11.0;1.12.0 com.azure:azure-core-tracing-opentelemetry;1.0.0-beta.27;1.0.0-beta.28 com.azure:azure-cosmos;4.35.1;4.36.0-beta.1 com.azure:azure-cosmos-benchmark;4.0.1-beta.1;4.0.1-beta.1 @@ -383,7 +383,7 @@ com.azure.tools:azure-sdk-build-tool;1.0.0-beta.1;1.0.0-beta.2 # In the pom, the version update tag after the version should name the unreleased package and the dependency version: # unreleased_com.azure:azure-ai-formrecognizer;4.0.0-beta.7 -unreleased_com.azure:azure-core;1.32.0-beta.1 +unreleased_com.azure:azure-core;1.32.0 # Released Beta dependencies: Copy the entry from above, prepend "beta_", remove the current # version and set the version to the released beta. Released beta dependencies are only valid diff --git a/sdk/appconfiguration/azure-data-appconfiguration/pom.xml b/sdk/appconfiguration/azure-data-appconfiguration/pom.xml index 96b78ceb22cd9..ecd450784bf3d 100644 --- a/sdk/appconfiguration/azure-data-appconfiguration/pom.xml +++ b/sdk/appconfiguration/azure-data-appconfiguration/pom.xml @@ -45,7 +45,7 @@ com.azure azure-core - 1.32.0-beta.1 + 1.32.0 com.azure diff --git a/sdk/core/azure-core-amqp-experimental/pom.xml b/sdk/core/azure-core-amqp-experimental/pom.xml index 1ce99d2d91d6b..112fe69318d40 100644 --- a/sdk/core/azure-core-amqp-experimental/pom.xml +++ b/sdk/core/azure-core-amqp-experimental/pom.xml @@ -61,7 +61,7 @@ com.azure azure-core-amqp - 2.8.0-beta.1 + 2.7.1 diff --git a/sdk/core/azure-core-amqp/CHANGELOG.md b/sdk/core/azure-core-amqp/CHANGELOG.md index 777992aca9c93..8278f7efa7165 100644 --- a/sdk/core/azure-core-amqp/CHANGELOG.md +++ b/sdk/core/azure-core-amqp/CHANGELOG.md @@ -1,6 +1,6 @@ # Release History -## 2.8.0-beta.1 (Unreleased) +## 2.7.1 (2022-09-01) ### Features Added @@ -8,11 +8,11 @@ error counters. Metrics are off by default and can be enabled with [azure-core-metrics-opentelemetry](https://github.com/Azure/azure-sdk-for-java/blob/main/sdk/core/azure-core-metrics-opentelemetry/README.md) plugin. ([#30583](https://github.com/Azure/azure-sdk-for-java/pull/30583)) -### Breaking Changes +### Other Changes -### Bugs Fixed +#### Dependency Updates -### Other Changes +- Upgraded Reactor from `3.4.21` to `3.4.22`. ## 2.7.0 (2022-08-05) diff --git a/sdk/core/azure-core-amqp/README.md b/sdk/core/azure-core-amqp/README.md index ea42b719663d6..2423823baa2cd 100644 --- a/sdk/core/azure-core-amqp/README.md +++ b/sdk/core/azure-core-amqp/README.md @@ -48,7 +48,7 @@ add the direct dependency to your project as follows. com.azure azure-core-amqp - 2.7.0 + 2.7.1 ``` [//]: # ({x-version-update-end}) diff --git a/sdk/core/azure-core-amqp/pom.xml b/sdk/core/azure-core-amqp/pom.xml index 0457cf15f150a..47458934a831d 100644 --- a/sdk/core/azure-core-amqp/pom.xml +++ b/sdk/core/azure-core-amqp/pom.xml @@ -14,7 +14,7 @@ com.azure azure-core-amqp - 2.8.0-beta.1 + 2.7.1 jar Microsoft Azure Java Core AMQP Library @@ -67,7 +67,7 @@ com.azure azure-core - 1.32.0-beta.1 + 1.32.0 com.microsoft.azure @@ -114,7 +114,7 @@ com.azure azure-core-test - 1.12.0-beta.1 + 1.12.0 test diff --git a/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/RequestResponseChannel.java b/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/RequestResponseChannel.java index 27b343010c406..ca062ec23ce80 100644 --- a/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/RequestResponseChannel.java +++ b/sdk/core/azure-core-amqp/src/main/java/com/azure/core/amqp/implementation/RequestResponseChannel.java @@ -364,7 +364,7 @@ public Mono sendWithAck(final Message message, DeliveryState deliverySt sendLink.advance(); }); } catch (IOException | RejectedExecutionException e) { - recordDelivery(sink.contextView(), null); + recordDelivery(getSinkContext(sink), null); sink.error(e); } }))); @@ -407,7 +407,7 @@ private void settleMessage(Message message) { return; } - recordDelivery(sink.contextView(), message); + recordDelivery(getSinkContext(sink), message); sink.success(message); } @@ -490,7 +490,7 @@ private void terminateUnconfirmedSends(Throwable error) { while ((next = unconfirmedSends.pollFirstEntry()) != null) { // pollFirstEntry: atomic retrieve and remove of each entry. MonoSink sink = next.getValue(); - recordDelivery(sink.contextView(), null); + recordDelivery(getSinkContext(sink), null); sink.error(error); count++; } @@ -521,6 +521,13 @@ private Mono captureStartTime(Message toSend, Mono publisher) return publisher; } + @SuppressWarnings("deprecation") + private static ContextView getSinkContext(MonoSink sink) { + // Use currentContext instead of contextView as it's supported back to Reactor 3.4.0 and gives the widest + // range of support possible. + return sink.currentContext(); + } + /** * Records send call duration metric. **/ diff --git a/sdk/core/azure-core-experimental/CHANGELOG.md b/sdk/core/azure-core-experimental/CHANGELOG.md index 3466a708f1c19..6726982af50eb 100644 --- a/sdk/core/azure-core-experimental/CHANGELOG.md +++ b/sdk/core/azure-core-experimental/CHANGELOG.md @@ -1,14 +1,12 @@ # Release History -## 1.0.0-beta.32 (Unreleased) +## 1.0.0-beta.32 (2022-09-01) -### Features Added - -### Breaking Changes +### Other Changes -### Bugs Fixed +#### Dependency Updates -### Other Changes +- Upgraded `azure-core` from `1.31.0` to `1.32.0`. ## 1.0.0-beta.31 (2022-08-05) diff --git a/sdk/core/azure-core-experimental/README.md b/sdk/core/azure-core-experimental/README.md index a77a8296ebb40..f189e1578bb2d 100644 --- a/sdk/core/azure-core-experimental/README.md +++ b/sdk/core/azure-core-experimental/README.md @@ -17,7 +17,7 @@ Azure Core Experimental contains types that are being evaluated and might eventu com.azure azure-core-experimental - 1.0.0-beta.31 + 1.0.0-beta.32 ``` [//]: # ({x-version-update-end}) diff --git a/sdk/core/azure-core-experimental/pom.xml b/sdk/core/azure-core-experimental/pom.xml index 76d4bf8f2803b..90c72402e6739 100644 --- a/sdk/core/azure-core-experimental/pom.xml +++ b/sdk/core/azure-core-experimental/pom.xml @@ -67,7 +67,7 @@ com.azure azure-core - 1.32.0-beta.1 + 1.32.0 diff --git a/sdk/core/azure-core-http-jdk-httpclient/pom.xml b/sdk/core/azure-core-http-jdk-httpclient/pom.xml index fe2c8c7171dc5..7b2d5906d0e71 100644 --- a/sdk/core/azure-core-http-jdk-httpclient/pom.xml +++ b/sdk/core/azure-core-http-jdk-httpclient/pom.xml @@ -71,27 +71,27 @@ com.azure azure-core - 1.32.0-beta.1 + 1.32.0 com.azure azure-core - 1.32.0-beta.1 + 1.32.0 test-jar test com.azure azure-core-test - 1.12.0-beta.1 + 1.12.0 test com.azure azure-core-test - 1.12.0-beta.1 + 1.12.0 test-jar test diff --git a/sdk/core/azure-core-http-netty/CHANGELOG.md b/sdk/core/azure-core-http-netty/CHANGELOG.md index f4d0320edeb3c..57b0651bd9b11 100644 --- a/sdk/core/azure-core-http-netty/CHANGELOG.md +++ b/sdk/core/azure-core-http-netty/CHANGELOG.md @@ -1,15 +1,18 @@ # Release History -## 1.13.0-beta.1 (Unreleased) - -### Features Added - -### Breaking Changes +## 1.12.5 (2022-09-01) ### Bugs Fixed +- Fixed a bug where `HttpResponse.writeBodyTo` could leak `ByteBuf`s. ([#30670](https://github.com/Azure/azure-sdk-for-java/pull/30670)) + ### Other Changes +#### Dependency Updates + +- Upgraded `azure-core` from `1.31.0` to `1.32.0`. +- Upgraded Reactor Netty from `1.0.21` to `1.0.22`. + ## 1.12.4 (2022-08-05) ### Other Changes diff --git a/sdk/core/azure-core-http-netty/README.md b/sdk/core/azure-core-http-netty/README.md index 108cd84aa89fb..092e4843af566 100644 --- a/sdk/core/azure-core-http-netty/README.md +++ b/sdk/core/azure-core-http-netty/README.md @@ -47,7 +47,7 @@ add the direct dependency to your project as follows. com.azure azure-core-http-netty - 1.12.4 + 1.12.5 ``` [//]: # ({x-version-update-end}) diff --git a/sdk/core/azure-core-http-netty/pom.xml b/sdk/core/azure-core-http-netty/pom.xml index e6b6a81f2664c..75217843ef2bf 100644 --- a/sdk/core/azure-core-http-netty/pom.xml +++ b/sdk/core/azure-core-http-netty/pom.xml @@ -15,7 +15,7 @@ com.azure azure-core-http-netty jar - 1.13.0-beta.1 + 1.12.5 Microsoft Azure Netty HTTP Client Library This package contains the Netty HTTP client plugin for azure-core. @@ -68,7 +68,7 @@ com.azure azure-core - 1.32.0-beta.1 + 1.32.0 @@ -132,20 +132,20 @@ com.azure azure-core - 1.32.0-beta.1 + 1.32.0 test-jar test com.azure azure-core-test - 1.12.0-beta.1 + 1.12.0 test com.azure azure-core-test - 1.12.0-beta.1 + 1.12.0 test-jar test diff --git a/sdk/core/azure-core-http-okhttp/CHANGELOG.md b/sdk/core/azure-core-http-okhttp/CHANGELOG.md index 72055ccd7fdec..4481a08e6f58e 100644 --- a/sdk/core/azure-core-http-okhttp/CHANGELOG.md +++ b/sdk/core/azure-core-http-okhttp/CHANGELOG.md @@ -1,14 +1,12 @@ # Release History -## 1.12.0-beta.1 (Unreleased) +## 1.11.2 (2022-09-01) -### Features Added - -### Breaking Changes +### Other Changes -### Bugs Fixed +#### Dependency Updates -### Other Changes +- Upgraded `azure-core` from `1.31.0` to `1.32.0`. ## 1.11.1 (2022-08-05) diff --git a/sdk/core/azure-core-http-okhttp/README.md b/sdk/core/azure-core-http-okhttp/README.md index 9f1760c9e1b1c..af353cd309cf6 100644 --- a/sdk/core/azure-core-http-okhttp/README.md +++ b/sdk/core/azure-core-http-okhttp/README.md @@ -47,7 +47,7 @@ add the direct dependency to your project as follows. com.azure azure-core-http-okhttp - 1.11.1 + 1.11.2 ``` [//]: # ({x-version-update-end}) diff --git a/sdk/core/azure-core-http-okhttp/pom.xml b/sdk/core/azure-core-http-okhttp/pom.xml index c2d29e60f4a09..b6cc46998c90a 100644 --- a/sdk/core/azure-core-http-okhttp/pom.xml +++ b/sdk/core/azure-core-http-okhttp/pom.xml @@ -15,7 +15,7 @@ com.azure azure-core-http-okhttp jar - 1.12.0-beta.1 + 1.11.2 Microsoft Azure OkHttp HTTP Client Library This package contains the OkHttp HTTP client plugin for azure-core. @@ -67,7 +67,7 @@ com.azure azure-core - 1.32.0-beta.1 + 1.32.0 @@ -80,20 +80,20 @@ com.azure azure-core - 1.32.0-beta.1 + 1.32.0 test-jar test com.azure azure-core-test - 1.12.0-beta.1 + 1.12.0 test com.azure azure-core-test - 1.12.0-beta.1 + 1.12.0 test-jar test diff --git a/sdk/core/azure-core-http-vertx/pom.xml b/sdk/core/azure-core-http-vertx/pom.xml index 30b40f9bf9243..b60267e91fad1 100644 --- a/sdk/core/azure-core-http-vertx/pom.xml +++ b/sdk/core/azure-core-http-vertx/pom.xml @@ -67,7 +67,7 @@ com.azure azure-core - 1.32.0-beta.1 + 1.32.0 @@ -88,20 +88,20 @@ com.azure azure-core - 1.32.0-beta.1 + 1.32.0 test-jar test com.azure azure-core-test - 1.12.0-beta.1 + 1.12.0 test com.azure azure-core-test - 1.12.0-beta.1 + 1.12.0 test-jar test diff --git a/sdk/core/azure-core-jackson-tests/pom.xml b/sdk/core/azure-core-jackson-tests/pom.xml index 4327a8f61da5e..35deaa715d15b 100644 --- a/sdk/core/azure-core-jackson-tests/pom.xml +++ b/sdk/core/azure-core-jackson-tests/pom.xml @@ -51,14 +51,14 @@ com.azure azure-core - 1.32.0-beta.1 + 1.32.0 test com.azure azure-core - 1.32.0-beta.1 + 1.32.0 tests test-jar test diff --git a/sdk/core/azure-core-management/CHANGELOG.md b/sdk/core/azure-core-management/CHANGELOG.md index 7eb58362190fa..ccc86fb5bd41b 100644 --- a/sdk/core/azure-core-management/CHANGELOG.md +++ b/sdk/core/azure-core-management/CHANGELOG.md @@ -1,16 +1,16 @@ # Release History -## 1.8.0-beta.1 (Unreleased) +## 1.8.0 (2022-09-01) ### Features Added - Added new Azure region `Region.QATAR_CENTRAL`. -### Breaking Changes +### Other Changes -### Bugs Fixed +#### Dependency Updates -### Other Changes +- Upgraded `azure-core` from `1.31.0` to `1.32.0`. ## 1.7.1 (2022-08-05) diff --git a/sdk/core/azure-core-management/README.md b/sdk/core/azure-core-management/README.md index 7e06b1d6cfa71..6ede85cc687b0 100644 --- a/sdk/core/azure-core-management/README.md +++ b/sdk/core/azure-core-management/README.md @@ -15,7 +15,7 @@ Azure Core Management library is a collection of classes common to the [Azure Re com.azure azure-core-management - 1.7.1 + 1.8.0 ``` [//]: # ({x-version-update-end}) diff --git a/sdk/core/azure-core-management/pom.xml b/sdk/core/azure-core-management/pom.xml index 2ac1b492101ce..b6ab8464fe132 100644 --- a/sdk/core/azure-core-management/pom.xml +++ b/sdk/core/azure-core-management/pom.xml @@ -13,7 +13,7 @@ com.azure azure-core-management - 1.8.0-beta.1 + 1.8.0 jar Microsoft Azure Management Java Core Library @@ -65,7 +65,7 @@ com.azure azure-core - 1.32.0-beta.1 + 1.32.0 @@ -89,7 +89,7 @@ com.azure azure-core-http-netty - 1.13.0-beta.1 + 1.12.5 test diff --git a/sdk/core/azure-core-metrics-opentelemetry/CHANGELOG.md b/sdk/core/azure-core-metrics-opentelemetry/CHANGELOG.md index d2e7ea714fe50..63f9c3371bb42 100644 --- a/sdk/core/azure-core-metrics-opentelemetry/CHANGELOG.md +++ b/sdk/core/azure-core-metrics-opentelemetry/CHANGELOG.md @@ -1,8 +1,8 @@ -## 1.0.0-beta.1 (Unreleased) +## 1.0.0-beta.1 (2022-09-01) ### Features Added -- Initial version +- Initial release. Please see the README for more information. ### Breaking Changes diff --git a/sdk/core/azure-core-metrics-opentelemetry/pom.xml b/sdk/core/azure-core-metrics-opentelemetry/pom.xml index 8957fca6d97e7..ce5c51d63ff4a 100644 --- a/sdk/core/azure-core-metrics-opentelemetry/pom.xml +++ b/sdk/core/azure-core-metrics-opentelemetry/pom.xml @@ -40,7 +40,7 @@ com.azure azure-core - 1.32.0-beta.1 + 1.32.0 com.google.code.findbugs @@ -67,13 +67,13 @@ com.azure azure-core-test - 1.12.0-beta.1 + 1.12.0 test com.azure azure-core-http-netty - 1.13.0-beta.1 + 1.12.5 test diff --git a/sdk/core/azure-core-perf/pom.xml b/sdk/core/azure-core-perf/pom.xml index 35bd7e91aadce..ac7b085019c6c 100644 --- a/sdk/core/azure-core-perf/pom.xml +++ b/sdk/core/azure-core-perf/pom.xml @@ -21,17 +21,17 @@ com.azure azure-core - 1.32.0-beta.1 + 1.32.0 com.azure azure-core-http-netty - 1.13.0-beta.1 + 1.12.5 com.azure azure-core-http-okhttp - 1.12.0-beta.1 + 1.11.2 com.azure diff --git a/sdk/core/azure-core-serializer-avro-apache/CHANGELOG.md b/sdk/core/azure-core-serializer-avro-apache/CHANGELOG.md index fd6972f4ee0c6..c82a302005b68 100644 --- a/sdk/core/azure-core-serializer-avro-apache/CHANGELOG.md +++ b/sdk/core/azure-core-serializer-avro-apache/CHANGELOG.md @@ -1,14 +1,12 @@ # Release History -## 1.0.0-beta.28 (Unreleased) +## 1.0.0-beta.28 (2022-09-01) -### Features Added - -### Breaking Changes +### Other Changes -### Bugs Fixed +#### Dependency Updates -### Other Changes +- Upgraded `azure-core` from `1.31.0` to `1.32.0`. ## 1.0.0-beta.27 (2022-08-05) diff --git a/sdk/core/azure-core-serializer-avro-apache/README.md b/sdk/core/azure-core-serializer-avro-apache/README.md index 9769551f6e3f0..29a298c8afe63 100644 --- a/sdk/core/azure-core-serializer-avro-apache/README.md +++ b/sdk/core/azure-core-serializer-avro-apache/README.md @@ -15,7 +15,7 @@ Azure Core Apache Avro Serializer is a plugin for the `azure-core` `AvroSerializ com.azure azure-core-serializer-avro-apache - 1.0.0-beta.27 + 1.0.0-beta.28 ``` [//]: # ({x-version-update-end}) diff --git a/sdk/core/azure-core-serializer-avro-apache/pom.xml b/sdk/core/azure-core-serializer-avro-apache/pom.xml index 46d5192f8faea..97fdc1deb5390 100644 --- a/sdk/core/azure-core-serializer-avro-apache/pom.xml +++ b/sdk/core/azure-core-serializer-avro-apache/pom.xml @@ -66,7 +66,7 @@ com.azure azure-core - 1.32.0-beta.1 + 1.32.0 com.azure diff --git a/sdk/core/azure-core-serializer-avro-jackson/pom.xml b/sdk/core/azure-core-serializer-avro-jackson/pom.xml index da34441ba5382..286b6e99a1b42 100644 --- a/sdk/core/azure-core-serializer-avro-jackson/pom.xml +++ b/sdk/core/azure-core-serializer-avro-jackson/pom.xml @@ -63,7 +63,7 @@ com.azure azure-core - 1.32.0-beta.1 + 1.32.0 com.azure diff --git a/sdk/core/azure-core-serializer-json-gson/CHANGELOG.md b/sdk/core/azure-core-serializer-json-gson/CHANGELOG.md index 7171c58edaa6f..7099646327c04 100644 --- a/sdk/core/azure-core-serializer-json-gson/CHANGELOG.md +++ b/sdk/core/azure-core-serializer-json-gson/CHANGELOG.md @@ -1,14 +1,13 @@ # Release History -## 1.2.0-beta.1 (Unreleased) +## 1.1.20 (2022-09-01) -### Features Added - -### Breaking Changes +### Other Changes -### Bugs Fixed +#### Dependency Updates -### Other Changes +- Upgraded `azure-core` from `1.31.0` to `1.32.0`. +- Upgraded GSON from `2.9.0` to `2.9.1`. ## 1.1.19 (2022-08-05) diff --git a/sdk/core/azure-core-serializer-json-gson/README.md b/sdk/core/azure-core-serializer-json-gson/README.md index c87e4533d32d0..936a2dba253d0 100644 --- a/sdk/core/azure-core-serializer-json-gson/README.md +++ b/sdk/core/azure-core-serializer-json-gson/README.md @@ -47,7 +47,7 @@ add the direct dependency to your project as follows. com.azure azure-core-serializer-json-gson - 1.1.19 + 1.1.20 ``` [//]: # ({x-version-update-end}) diff --git a/sdk/core/azure-core-serializer-json-gson/pom.xml b/sdk/core/azure-core-serializer-json-gson/pom.xml index efc178fd0ef83..e255f9c4959eb 100644 --- a/sdk/core/azure-core-serializer-json-gson/pom.xml +++ b/sdk/core/azure-core-serializer-json-gson/pom.xml @@ -15,7 +15,7 @@ com.azure azure-core-serializer-json-gson jar - 1.2.0-beta.1 + 1.1.20 Microsoft Azure Gson JSON Serializer Library This package contains the Gson JSON serializer client plugin for azure-core. @@ -65,7 +65,7 @@ com.azure azure-core - 1.32.0-beta.1 + 1.32.0 diff --git a/sdk/core/azure-core-serializer-json-jackson/CHANGELOG.md b/sdk/core/azure-core-serializer-json-jackson/CHANGELOG.md index 0037e08a3694d..41502793a3d22 100644 --- a/sdk/core/azure-core-serializer-json-jackson/CHANGELOG.md +++ b/sdk/core/azure-core-serializer-json-jackson/CHANGELOG.md @@ -1,14 +1,12 @@ # Release History -## 1.3.0-beta.1 (Unreleased) +## 1.2.21 (2022-09-01) -### Features Added - -### Breaking Changes +### Other Changes -### Bugs Fixed +#### Dependency Updates -### Other Changes +- Upgraded `azure-core` from `1.31.0` to `1.32.0`. ## 1.2.20 (2022-08-05) diff --git a/sdk/core/azure-core-serializer-json-jackson/README.md b/sdk/core/azure-core-serializer-json-jackson/README.md index 82c4311869b30..cbbc938d7ea4a 100644 --- a/sdk/core/azure-core-serializer-json-jackson/README.md +++ b/sdk/core/azure-core-serializer-json-jackson/README.md @@ -47,7 +47,7 @@ add the direct dependency to your project as follows. com.azure azure-core-serializer-json-jackson - 1.2.20 + 1.2.21 ``` [//]: # ({x-version-update-end}) diff --git a/sdk/core/azure-core-serializer-json-jackson/pom.xml b/sdk/core/azure-core-serializer-json-jackson/pom.xml index 038b6d7f08e46..69648dde786f7 100644 --- a/sdk/core/azure-core-serializer-json-jackson/pom.xml +++ b/sdk/core/azure-core-serializer-json-jackson/pom.xml @@ -15,7 +15,7 @@ com.azure azure-core-serializer-json-jackson jar - 1.3.0-beta.1 + 1.2.21 Microsoft Azure Jackson JSON Serializer Library This package contains the Jackson JSON serializer client plugin for azure-core. @@ -66,7 +66,7 @@ com.azure azure-core - 1.32.0-beta.1 + 1.32.0 diff --git a/sdk/core/azure-core-test/CHANGELOG.md b/sdk/core/azure-core-test/CHANGELOG.md index ade69cb69a741..6e584124c72f9 100644 --- a/sdk/core/azure-core-test/CHANGELOG.md +++ b/sdk/core/azure-core-test/CHANGELOG.md @@ -1,15 +1,17 @@ # Release History -## 1.12.0-beta.1 (Unreleased) +## 1.12.0 (2022-09-01) ### Features Added -### Breaking Changes - -### Bugs Fixed +- Added metrics-based testing utilities. ### Other Changes +#### Dependency Updates + +- Upgraded `azure-core` from `1.31.0` to `1.32.0`. + ## 1.11.0 (2022-08-05) ### Features Added diff --git a/sdk/core/azure-core-test/README.md b/sdk/core/azure-core-test/README.md index 05e7e49a5a27d..5e52a9d146e42 100644 --- a/sdk/core/azure-core-test/README.md +++ b/sdk/core/azure-core-test/README.md @@ -18,7 +18,7 @@ To use this package, add the following to your _pom.xml_. com.azure azure-core-test - 1.11.0 + 1.12.0 ``` [//]: # ({x-version-update-end}) diff --git a/sdk/core/azure-core-test/pom.xml b/sdk/core/azure-core-test/pom.xml index 4ece63584f392..aae72097432e6 100644 --- a/sdk/core/azure-core-test/pom.xml +++ b/sdk/core/azure-core-test/pom.xml @@ -13,7 +13,7 @@ com.azure azure-core-test jar - 1.12.0-beta.1 + 1.12.0 Microsoft Azure Java Core Test Library This package contains core test types for Azure Java clients. @@ -53,7 +53,7 @@ com.azure azure-core - 1.32.0-beta.1 + 1.32.0 diff --git a/sdk/core/azure-core-tracing-opentelemetry/CHANGELOG.md b/sdk/core/azure-core-tracing-opentelemetry/CHANGELOG.md index ee58ab12267a0..b639647a86429 100644 --- a/sdk/core/azure-core-tracing-opentelemetry/CHANGELOG.md +++ b/sdk/core/azure-core-tracing-opentelemetry/CHANGELOG.md @@ -1,14 +1,12 @@ # Release History -## 1.0.0-beta.28 (Unreleased) +## 1.0.0-beta.28 (2022-09-01) -### Features Added - -### Breaking Changes +### Other Changes -### Bugs Fixed +#### Dependency Updates -### Other Changes +- Upgraded `azure-core` from `1.31.0` to `1.32.0`. ## 1.0.0-beta.27 (2022-08-05) diff --git a/sdk/core/azure-core-tracing-opentelemetry/README.md b/sdk/core/azure-core-tracing-opentelemetry/README.md index 2d1e40d50e87b..d2ade85ec5495 100644 --- a/sdk/core/azure-core-tracing-opentelemetry/README.md +++ b/sdk/core/azure-core-tracing-opentelemetry/README.md @@ -51,7 +51,7 @@ To enable Azure SDK tracing, add the latest `com.azure:azure-core-tracing-opente com.azure azure-core-tracing-opentelemetry - 1.0.0-beta.27 + 1.0.0-beta.28 ``` [//]: # ({x-version-update-end}) diff --git a/sdk/core/azure-core-tracing-opentelemetry/pom.xml b/sdk/core/azure-core-tracing-opentelemetry/pom.xml index 9aea806264d94..d2010dcbf74cb 100644 --- a/sdk/core/azure-core-tracing-opentelemetry/pom.xml +++ b/sdk/core/azure-core-tracing-opentelemetry/pom.xml @@ -50,7 +50,7 @@ com.azure azure-core - 1.32.0-beta.1 + 1.32.0 com.google.code.findbugs @@ -69,13 +69,13 @@ com.azure azure-core-test - 1.12.0-beta.1 + 1.12.0 test com.azure azure-core-http-netty - 1.13.0-beta.1 + 1.12.5 test diff --git a/sdk/core/azure-core/CHANGELOG.md b/sdk/core/azure-core/CHANGELOG.md index 24b6579649129..3861d123bfdf7 100644 --- a/sdk/core/azure-core/CHANGELOG.md +++ b/sdk/core/azure-core/CHANGELOG.md @@ -1,16 +1,20 @@ # Release History -## 1.32.0-beta.1 (Unreleased) +## 1.32.0 (2022-09-01) +### Features Added + +- Added new constructor overloads to `PagedIterable` and introduced `PageRetrieverSync`. - Added `com.azure.core.util.metrics.LongGauge` instrument support to metrics. +- Added `CoreUtils.stringJoin` which optimizes `String.join` for small `List`s. -### Features Added +### Other Changes -### Breaking Changes +- Miscellaneous performance improvements. -### Bugs Fixed +#### Dependency Updates -### Other Changes +- Upgraded Reactor from `3.4.2` to `3.4.22`. ## 1.31.0 (2022-08-05) diff --git a/sdk/core/azure-core/README.md b/sdk/core/azure-core/README.md index e051caf8b628e..7aa94df9a6249 100644 --- a/sdk/core/azure-core/README.md +++ b/sdk/core/azure-core/README.md @@ -58,7 +58,7 @@ add the direct dependency to your project as follows. com.azure azure-core - 1.31.0 + 1.32.0 ``` [//]: # ({x-version-update-end}) diff --git a/sdk/core/azure-core/pom.xml b/sdk/core/azure-core/pom.xml index 1029a9a43094f..82c3700cea0e5 100644 --- a/sdk/core/azure-core/pom.xml +++ b/sdk/core/azure-core/pom.xml @@ -15,7 +15,7 @@ com.azure azure-core jar - 1.32.0-beta.1 + 1.32.0 Microsoft Azure Java Core Library This package contains core types for Azure Java clients. diff --git a/sdk/core/azure-json-gson/src/main/java/com/azure/json/gson/GsonJsonProvider.java b/sdk/core/azure-json-gson/src/main/java/com/azure/json/gson/GsonJsonProvider.java new file mode 100644 index 0000000000000..6ae9888c87969 --- /dev/null +++ b/sdk/core/azure-json-gson/src/main/java/com/azure/json/gson/GsonJsonProvider.java @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.json.gson; + +import com.azure.json.JsonOptions; +import com.azure.json.JsonProvider; +import com.azure.json.JsonReader; +import com.azure.json.JsonWriter; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; + +/** + * Implementation of {@link JsonProvider} that creates instances using GSON. + */ +public class GsonJsonProvider implements JsonProvider { + @Override + public JsonReader createReader(byte[] json, JsonOptions options) { + return GsonJsonReader.fromBytes(json, options); + } + + @Override + public JsonReader createReader(String json, JsonOptions options) { + return GsonJsonReader.fromString(json, options); + } + + @Override + public JsonReader createReader(InputStream json, JsonOptions options) { + return GsonJsonReader.fromStream(json, options); + } + + @Override + public JsonReader createReader(Reader json, JsonOptions options) { + return GsonJsonReader.fromReader(json, options); + } + + @Override + public JsonWriter createWriter(OutputStream json, JsonOptions options) { + return GsonJsonWriter.toStream(json, options); + } + + @Override + public JsonWriter createWriter(Writer json, JsonOptions options) { + return GsonJsonWriter.toWriter(json, options); + } +} diff --git a/sdk/core/azure-json-gson/src/main/java/com/azure/json/gson/GsonJsonReader.java b/sdk/core/azure-json-gson/src/main/java/com/azure/json/gson/GsonJsonReader.java index 4087f6b15454a..7a9f8260c4014 100644 --- a/sdk/core/azure-json-gson/src/main/java/com/azure/json/gson/GsonJsonReader.java +++ b/sdk/core/azure-json-gson/src/main/java/com/azure/json/gson/GsonJsonReader.java @@ -3,6 +3,7 @@ package com.azure.json.gson; +import com.azure.json.JsonOptions; import com.azure.json.JsonReader; import com.azure.json.JsonToken; @@ -25,46 +26,71 @@ public final class GsonJsonReader extends JsonReader { private final byte[] jsonBytes; private final String jsonString; private final boolean resetSupported; + private final boolean nonNumericNumbersSupported; private JsonToken currentToken; private boolean consumed = false; + private boolean complete = false; /** * Constructs an instance of {@link GsonJsonReader} from a {@code byte[]}. * * @param json JSON {@code byte[]}. + * @param options {@link JsonOptions} to configure the creation of the {@link JsonReader}. * @return An instance of {@link GsonJsonReader}. */ - public static JsonReader fromBytes(byte[] json) { + static JsonReader fromBytes(byte[] json, JsonOptions options) { return new GsonJsonReader(new InputStreamReader(new ByteArrayInputStream(json), StandardCharsets.UTF_8), - true, json, null); + true, json, null, options); } /** * Constructs an instance of {@link GsonJsonReader} from a String. * * @param json JSON String. + * @param options {@link JsonOptions} to configure the creation of the {@link JsonReader}. * @return An instance of {@link GsonJsonReader}. */ - public static JsonReader fromString(String json) { - return new GsonJsonReader(new StringReader(json), true, null, json); + static JsonReader fromString(String json, JsonOptions options) { + return new GsonJsonReader(new StringReader(json), true, null, json, options); } /** * Constructs an instance of {@link GsonJsonReader} from an {@link InputStream}. * * @param json JSON {@link InputStream}. + * @param options {@link JsonOptions} to configure the creation of the {@link JsonReader}. * @return An instance of {@link GsonJsonReader}. */ - public static JsonReader fromStream(InputStream json) { - return new GsonJsonReader(new InputStreamReader(json, StandardCharsets.UTF_8), false, null, null); + static JsonReader fromStream(InputStream json, JsonOptions options) { + return new GsonJsonReader(new InputStreamReader(json, StandardCharsets.UTF_8), json.markSupported(), null, null, + options); } - private GsonJsonReader(Reader reader, boolean resetSupported, byte[] jsonBytes, String jsonString) { + /** + * Constructs an instance of {@link GsonJsonReader} from a {@link Reader}. + * + * @param json JSON {@link Reader}. + * @param options {@link JsonOptions} to configure the creation of the {@link JsonReader}. + * @return An instance of {@link GsonJsonReader}. + */ + static JsonReader fromReader(Reader json, JsonOptions options) { + return new GsonJsonReader(json, json.markSupported(), null, null, options); + } + + private GsonJsonReader(Reader reader, boolean resetSupported, byte[] jsonBytes, String jsonString, + JsonOptions options) { + this(reader, resetSupported, jsonBytes, jsonString, options.isNonNumericNumbersSupported()); + } + + private GsonJsonReader(Reader reader, boolean resetSupported, byte[] jsonBytes, String jsonString, + boolean nonNumericNumbersSupported) { this.reader = new com.google.gson.stream.JsonReader(reader); + this.reader.setLenient(nonNumericNumbersSupported); this.resetSupported = resetSupported; this.jsonBytes = jsonBytes; this.jsonString = jsonString; + this.nonNumericNumbersSupported = nonNumericNumbersSupported; } @Override @@ -74,6 +100,10 @@ public JsonToken currentToken() { @Override public JsonToken nextToken() { + if (complete) { + return currentToken; + } + // GSON requires explicitly beginning and ending arrays and objects and consuming null values. // The contract of JsonReader implicitly overlooks these properties. try { @@ -112,7 +142,12 @@ public JsonToken nextToken() { } } - currentToken = mapToken(reader.peek()); + com.google.gson.stream.JsonToken gsonToken = reader.peek(); + if (gsonToken == com.google.gson.stream.JsonToken.END_DOCUMENT) { + complete = true; + } + + currentToken = mapToken(gsonToken); consumed = false; return currentToken; } catch (IOException e) { @@ -235,7 +270,8 @@ public JsonReader bufferObject() { consumed = true; StringBuilder bufferedObject = new StringBuilder(); readChildren(bufferedObject); - return GsonJsonReader.fromString(bufferedObject.toString()); + String json = bufferedObject.toString(); + return new GsonJsonReader(new StringReader(json), true, null, json, nonNumericNumbersSupported); } else { throw new IllegalStateException("Cannot buffer a JSON object from a non-object, non-field name " + "starting location. Starting location: " + currentToken()); @@ -254,9 +290,11 @@ public JsonReader reset() { } if (jsonBytes != null) { - return GsonJsonReader.fromBytes(jsonBytes); + return new GsonJsonReader( + new InputStreamReader(new ByteArrayInputStream(jsonBytes), StandardCharsets.UTF_8), true, jsonBytes, + null, nonNumericNumbersSupported); } else { - return GsonJsonReader.fromString(jsonString); + return new GsonJsonReader(new StringReader(jsonString), true, null, jsonString, nonNumericNumbersSupported); } } @@ -275,33 +313,19 @@ private static JsonToken mapToken(com.google.gson.stream.JsonToken token) { } switch (token) { - case BEGIN_OBJECT: - return JsonToken.START_OBJECT; - - case END_OBJECT: - case END_DOCUMENT: - return JsonToken.END_OBJECT; - - case BEGIN_ARRAY: - return JsonToken.START_ARRAY; - - case END_ARRAY: - return JsonToken.END_ARRAY; - - case NAME: - return JsonToken.FIELD_NAME; - - case STRING: - return JsonToken.STRING; + case BEGIN_OBJECT: return JsonToken.START_OBJECT; + case END_OBJECT: return JsonToken.END_OBJECT; - case NUMBER: - return JsonToken.NUMBER; + case BEGIN_ARRAY: return JsonToken.START_ARRAY; + case END_ARRAY: return JsonToken.END_ARRAY; - case BOOLEAN: - return JsonToken.BOOLEAN; + case NAME: return JsonToken.FIELD_NAME; + case STRING: return JsonToken.STRING; + case NUMBER: return JsonToken.NUMBER; + case BOOLEAN: return JsonToken.BOOLEAN; + case NULL: return JsonToken.NULL; - case NULL: - return JsonToken.NULL; + case END_DOCUMENT: return JsonToken.END_DOCUMENT; default: throw new IllegalStateException("Unsupported token type: '" + token + "'."); diff --git a/sdk/core/azure-json-gson/src/main/java/com/azure/json/gson/GsonJsonWriter.java b/sdk/core/azure-json-gson/src/main/java/com/azure/json/gson/GsonJsonWriter.java index 2818bb42cb905..0e5b382d935d1 100644 --- a/sdk/core/azure-json-gson/src/main/java/com/azure/json/gson/GsonJsonWriter.java +++ b/sdk/core/azure-json-gson/src/main/java/com/azure/json/gson/GsonJsonWriter.java @@ -3,6 +3,7 @@ package com.azure.json.gson; +import com.azure.json.JsonOptions; import com.azure.json.JsonToken; import com.azure.json.JsonWriteContext; import com.azure.json.JsonWriter; @@ -11,6 +12,7 @@ import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.UncheckedIOException; +import java.io.Writer; import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.Objects; @@ -31,15 +33,30 @@ public final class GsonJsonWriter extends JsonWriter { * isn't the owner of the stream. * * @param stream The {@link OutputStream} that will be written. + * @param options {@link JsonOptions} to configure the creation of the {@link JsonWriter}. * @return An instance of {@link GsonJsonWriter}. */ - public static JsonWriter toStream(OutputStream stream) { - return new GsonJsonWriter(new com.google.gson.stream.JsonWriter( - new OutputStreamWriter(stream, StandardCharsets.UTF_8))); + static JsonWriter toStream(OutputStream stream, JsonOptions options) { + return new GsonJsonWriter(new OutputStreamWriter(stream, StandardCharsets.UTF_8), options); } - private GsonJsonWriter(com.google.gson.stream.JsonWriter writer) { - this.writer = writer; + /** + * Creates a {@link GsonJsonWriter} that writes the given {@link Writer}. + *

+ * The passed {@link Writer} won't be closed when {@link #close()} is called as the {@link GsonJsonWriter} + * isn't the owner of the stream. + * + * @param writer The {@link Writer} that will be written. + * @param options {@link JsonOptions} to configure the creation of the {@link JsonWriter}. + * @return An instance of {@link GsonJsonWriter}. + */ + static JsonWriter toWriter(Writer writer, JsonOptions options) { + return new GsonJsonWriter(writer, options); + } + + private GsonJsonWriter(Writer writer, JsonOptions options) { + this.writer = new com.google.gson.stream.JsonWriter(writer); + this.writer.setLenient(options.isNonNumericNumbersSupported()); } @Override diff --git a/sdk/core/azure-json-gson/src/main/java/module-info.java b/sdk/core/azure-json-gson/src/main/java/module-info.java index eaa4376caf735..9ef2e6e8dc8d1 100644 --- a/sdk/core/azure-json-gson/src/main/java/module-info.java +++ b/sdk/core/azure-json-gson/src/main/java/module-info.java @@ -7,4 +7,6 @@ requires com.google.gson; exports com.azure.json.gson; + + provides com.azure.json.JsonProvider with com.azure.json.gson.GsonJsonProvider; } diff --git a/sdk/core/azure-json-gson/src/main/resources/META-INF/services/com.azure.json.JsonProvider b/sdk/core/azure-json-gson/src/main/resources/META-INF/services/com.azure.json.JsonProvider new file mode 100644 index 0000000000000..2c52ef3599b3f --- /dev/null +++ b/sdk/core/azure-json-gson/src/main/resources/META-INF/services/com.azure.json.JsonProvider @@ -0,0 +1 @@ +com.azure.json.gson.GsonJsonProvider diff --git a/sdk/core/azure-json-gson/src/test/java/com/azure/json/gson/GsonJsonInstantiationTests.java b/sdk/core/azure-json-gson/src/test/java/com/azure/json/gson/GsonJsonInstantiationTests.java index 236a88e99f243..03b96f5f6e07a 100644 --- a/sdk/core/azure-json-gson/src/test/java/com/azure/json/gson/GsonJsonInstantiationTests.java +++ b/sdk/core/azure-json-gson/src/test/java/com/azure/json/gson/GsonJsonInstantiationTests.java @@ -24,11 +24,13 @@ public void throwsNullPointerException(Executable executable) { @SuppressWarnings("resource") private static Stream throwsNullPointerExceptionSupplier() { return Stream.of( - () -> GsonJsonReader.fromBytes(null), - () -> GsonJsonReader.fromString(null), - () -> GsonJsonReader.fromStream(null), + () -> GsonJsonReader.fromBytes(null, null), + () -> GsonJsonReader.fromReader(null, null), + () -> GsonJsonReader.fromString(null, null), + () -> GsonJsonReader.fromStream(null, null), - () -> GsonJsonWriter.toStream(null) + () -> GsonJsonWriter.toStream(null, null), + () -> GsonJsonWriter.toWriter(null, null) ); } } diff --git a/sdk/core/azure-json-gson/src/test/java/com/azure/json/gson/GsonJsonReaderContractTests.java b/sdk/core/azure-json-gson/src/test/java/com/azure/json/gson/GsonJsonReaderContractTests.java index e03a1d1280329..71abd8e5bdf78 100644 --- a/sdk/core/azure-json-gson/src/test/java/com/azure/json/gson/GsonJsonReaderContractTests.java +++ b/sdk/core/azure-json-gson/src/test/java/com/azure/json/gson/GsonJsonReaderContractTests.java @@ -3,6 +3,7 @@ package com.azure.json.gson; +import com.azure.json.JsonOptions; import com.azure.json.JsonReader; import com.azure.json.contract.JsonReaderContractTests; @@ -12,6 +13,6 @@ public class GsonJsonReaderContractTests extends JsonReaderContractTests { @Override public JsonReader getJsonReader(String json) { - return GsonJsonReader.fromString(json); + return GsonJsonReader.fromString(json, new JsonOptions()); } } diff --git a/sdk/core/azure-json-gson/src/test/java/com/azure/json/gson/GsonJsonWriterContractTests.java b/sdk/core/azure-json-gson/src/test/java/com/azure/json/gson/GsonJsonWriterContractTests.java index 88b2a0828fcd8..34d0aeaf18c99 100644 --- a/sdk/core/azure-json-gson/src/test/java/com/azure/json/gson/GsonJsonWriterContractTests.java +++ b/sdk/core/azure-json-gson/src/test/java/com/azure/json/gson/GsonJsonWriterContractTests.java @@ -3,6 +3,7 @@ package com.azure.json.gson; +import com.azure.json.JsonOptions; import com.azure.json.JsonWriter; import com.azure.json.contract.JsonWriterContractTests; import org.junit.jupiter.api.BeforeEach; @@ -21,7 +22,7 @@ public class GsonJsonWriterContractTests extends JsonWriterContractTests { @BeforeEach public void beforeEach() { this.outputStream = new ByteArrayOutputStream(); - this.writer = GsonJsonWriter.toStream(outputStream); + this.writer = GsonJsonWriter.toStream(outputStream, new JsonOptions()); } @Override diff --git a/sdk/core/azure-json/src/main/java/com/azure/json/JsonOptions.java b/sdk/core/azure-json/src/main/java/com/azure/json/JsonOptions.java new file mode 100644 index 0000000000000..deb7c0f21f403 --- /dev/null +++ b/sdk/core/azure-json/src/main/java/com/azure/json/JsonOptions.java @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.json; + +/** + * Contains configuration options for creating a {@link JsonReader} or {@link JsonWriter}. + */ +public final class JsonOptions { + static final JsonOptions DEFAULT_OPTIONS = new JsonOptions(); + + private boolean nonNumericNumbersSupported = true; + + /** + * Whether non-numeric numbers such as {@code NaN} and {@code INF} and {@code -INF} are supported. + *

+ * By default, this is configured to true. + * + * @return Whether non-numeric numbers are supported. + */ + public boolean isNonNumericNumbersSupported() { + return nonNumericNumbersSupported; + } + + /** + * Sets whether non-numeric numbers such as {@code NaN} and {@code INF} and {@code -INF} are supported. + *

+ * By default, this is configured to true. + * + * @param nonNumericNumbersSupported Whether non-numeric numbers are supported. + * @return The updated JsonOptions object. + */ + public JsonOptions setNonNumericNumbersSupported(boolean nonNumericNumbersSupported) { + this.nonNumericNumbersSupported = nonNumericNumbersSupported; + return this; + } +} diff --git a/sdk/core/azure-json/src/main/java/com/azure/json/JsonProvider.java b/sdk/core/azure-json/src/main/java/com/azure/json/JsonProvider.java new file mode 100644 index 0000000000000..699bf67dafc18 --- /dev/null +++ b/sdk/core/azure-json/src/main/java/com/azure/json/JsonProvider.java @@ -0,0 +1,141 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.json; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; + +/** + * An interface to be implemented by any azure-json plugin that wishes to provide an alternate {@link JsonReader} or + * {@link JsonWriter} implementation. + */ +public interface JsonProvider { + /** + * Creates an instance of {@link JsonReader} that reads a {@code byte[]}. + * + * @param json The JSON represented as a {@code byte[]}. + * @return A new instance of {@link JsonReader}. + * @throws NullPointerException If {@code json} is null. + */ + default JsonReader createReader(byte[] json) { + return createReader(json, JsonOptions.DEFAULT_OPTIONS); + } + + /** + * Creates an instance of {@link JsonReader} that reads a {@code byte[]}. + * + * @param json The JSON represented as a {@code byte[]}. + * @param options {@link JsonOptions} to configure the creation of the {@link JsonReader}. + * @return A new instance of {@link JsonReader}. + * @throws NullPointerException If {@code json} is null. + */ + JsonReader createReader(byte[] json, JsonOptions options); + + /** + * Creates an instance of {@link JsonReader} that reads a {@link String}. + * + * @param json The JSON represented as a {@link String}. + * @return A new instance of {@link JsonReader}. + * @throws NullPointerException If {@code json} is null. + */ + default JsonReader createReader(String json) { + return createReader(json, JsonOptions.DEFAULT_OPTIONS); + } + + /** + * Creates an instance of {@link JsonReader} that reads a {@link String}. + * + * @param json The JSON represented as a {@link String}. + * @param options {@link JsonOptions} to configure the creation of the {@link JsonReader}. + * @return A new instance of {@link JsonReader}. + * @throws NullPointerException If {@code json} is null. + */ + JsonReader createReader(String json, JsonOptions options); + + /** + * Creates an instance of {@link JsonReader} that reads a {@link InputStream}. + * + * @param json The JSON represented as a {@link InputStream}. + * @return A new instance of {@link JsonReader}. + * @throws NullPointerException If {@code json} is null. + */ + default JsonReader createReader(InputStream json) { + return createReader(json, JsonOptions.DEFAULT_OPTIONS); + } + + /** + * Creates an instance of {@link JsonReader} that reads a {@link InputStream}. + * + * @param json The JSON represented as a {@link InputStream}. + * @param options {@link JsonOptions} to configure the creation of the {@link JsonReader}. + * @return A new instance of {@link JsonReader}. + * @throws NullPointerException If {@code json} is null. + */ + JsonReader createReader(InputStream json, JsonOptions options); + + /** + * Creates an instance of {@link JsonReader} that reads a {@link Reader}. + * + * @param json The JSON represented as a {@link Reader}. + * @return A new instance of {@link JsonReader}. + * @throws NullPointerException If {@code json} is null. + */ + default JsonReader createReader(Reader json) { + return createReader(json, JsonOptions.DEFAULT_OPTIONS); + } + + /** + * Creates an instance of {@link JsonReader} that reads a {@link Reader}. + * + * @param json The JSON represented as a {@link Reader}. + * @param options {@link JsonOptions} to configure the creation of the {@link JsonReader}. + * @return A new instance of {@link JsonReader}. + * @throws NullPointerException If {@code json} is null. + */ + JsonReader createReader(Reader json, JsonOptions options); + + /** + * Creates an instance of {@link JsonWriter} that writes to an {@link OutputStream}. + * + * @param json The JSON represented as an {@link OutputStream}. + * @return A new instance of {@link JsonWriter}. + * @throws NullPointerException If {@code json} is null. + */ + default JsonWriter createWriter(OutputStream json) { + return createWriter(json, JsonOptions.DEFAULT_OPTIONS); + } + + /** + * Creates an instance of {@link JsonWriter} that writes to an {@link OutputStream}. + * + * @param json The JSON represented as an {@link OutputStream}. + * @param options {@link JsonOptions} to configure the creation of the {@link JsonWriter}. + * @return A new instance of {@link JsonWriter}. + * @throws NullPointerException If {@code json} is null. + */ + JsonWriter createWriter(OutputStream json, JsonOptions options); + + /** + * Creates an instance of {@link JsonWriter} that writes to an {@link Writer}. + * + * @param json The JSON represented as an {@link Writer}. + * @return A new instance of {@link JsonWriter}. + * @throws NullPointerException If {@code json} is null. + */ + default JsonWriter createWriter(Writer json) { + return createWriter(json, JsonOptions.DEFAULT_OPTIONS); + } + + /** + * Creates an instance of {@link JsonWriter} that writes to an {@link Writer}. + * + * @param json The JSON represented as an {@link Writer}. + * @param options {@link JsonOptions} to configure the creation of the {@link JsonWriter}. + * @return A new instance of {@link JsonWriter}. + * @throws NullPointerException If {@code json} is null. + */ + JsonWriter createWriter(Writer json, JsonOptions options); +} diff --git a/sdk/core/azure-json/src/main/java/com/azure/json/JsonProviders.java b/sdk/core/azure-json/src/main/java/com/azure/json/JsonProviders.java new file mode 100644 index 0000000000000..e995663167f3a --- /dev/null +++ b/sdk/core/azure-json/src/main/java/com/azure/json/JsonProviders.java @@ -0,0 +1,269 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.json; + +import com.azure.json.implementation.DefaultJsonReader; +import com.azure.json.implementation.DefaultJsonWriter; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; +import java.util.Iterator; +import java.util.ServiceLoader; + +/** + * Handles loading an instance of {@link JsonProvider} found on the classpath. + */ +public final class JsonProviders { + private static final String CANNOT_FIND_JSON = "A request was made to load a JsonReader and JsonWriter provider " + + "but one could not be found on the classpath. If you are using a dependency manager, consider including a " + + "dependency on azure-json-gson or azure-json-reflect or indicate to the loader to fallback to the default " + + "implementation. Depending on your existing dependencies, you have the choice of Jackson or JSON " + + "implementations. Additionally, refer to https://aka.ms/azsdk/java/docs/custom-json to learn about writing " + + "your own implementation."; + + private static JsonProvider defaultProvider; + + static { + // Use as classloader to load provider-configuration files and provider classes the classloader + // that loaded this class. In most cases this will be the System classloader. + // But this choice here provides additional flexibility in managed environments that control + // classloading differently (OSGi, Spring and others) and don't/ depend on the + // System classloader to load HttpClientProvider classes. + ServiceLoader serviceLoader = ServiceLoader.load(JsonProvider.class, + JsonProvider.class.getClassLoader()); + // Use the first provider found in the service loader iterator. + Iterator it = serviceLoader.iterator(); + if (it.hasNext()) { + defaultProvider = it.next(); + } + + while (it.hasNext()) { + it.next(); + } + } + + private JsonProviders() { + // no-op + } + + /** + * Creates an instance of {@link JsonReader} that reads a {@code byte[]}. + *

+ * If a provider could not be found on the classpath this will use the default implementation, effectively the + * equivalent to {@link #createReader(byte[], JsonOptions, boolean) createReader(json, new JsonOptions(), true)}. + * + * @param json The JSON represented as a {@code byte[]}. + * @return A new instance of {@link JsonReader}. + * @throws NullPointerException If {@code json} is null. + */ + public static JsonReader createReader(byte[] json) { + return createReader(json, JsonOptions.DEFAULT_OPTIONS, true); + } + + /** + * Creates an instance of {@link JsonReader} that reads a {@code byte[]}. + * + * @param json The JSON represented as a {@code byte[]}. + * @param options {@link JsonOptions} to configure the creation of the {@link JsonReader}. + * @param useDefault Whether the default implementation should be used if one could not be found on the classpath. + * @return A new instance of {@link JsonReader}. + * @throws NullPointerException If {@code json} is null. + * @throws IllegalStateException If a provider could not be found on the classpath and {@code useDefault} is false. + */ + public static JsonReader createReader(byte[] json, JsonOptions options, boolean useDefault) { + if (defaultProvider == null) { + if (useDefault) { + return DefaultJsonReader.fromBytes(json, options); + } else { + throw new IllegalStateException(CANNOT_FIND_JSON); + } + } else { + return defaultProvider.createReader(json, options); + } + } + + /** + * Creates an instance of {@link JsonReader} that reads a {@link String}. + *

+ * If a provider could not be found on the classpath this will use the default implementation, effectively the + * equivalent to {@link #createReader(String, JsonOptions, boolean) createReader(json, new JsonOptions(), true)}. + * + * @param json The JSON represented as a {@link String}. + * @return A new instance of {@link JsonReader}. + * @throws NullPointerException If {@code json} is null. + */ + public static JsonReader createReader(String json) { + return createReader(json, JsonOptions.DEFAULT_OPTIONS, true); + } + + /** + * Creates an instance of {@link JsonReader} that reads a {@link String}. + * + * @param json The JSON represented as a {@link String}. + * @param options {@link JsonOptions} to configure the creation of the {@link JsonReader}. + * @param useDefault Whether the default implementation should be used if one could not be found on the classpath. + * @return A new instance of {@link JsonReader}. + * @throws NullPointerException If {@code json} is null. + * @throws IllegalStateException If a provider could not be found on the classpath and {@code useDefault} is false. + */ + public static JsonReader createReader(String json, JsonOptions options, boolean useDefault) { + if (defaultProvider == null) { + if (useDefault) { + return DefaultJsonReader.fromString(json, options); + } else { + throw new IllegalStateException(CANNOT_FIND_JSON); + } + } else { + return defaultProvider.createReader(json, options); + } + } + + /** + * Creates an instance of {@link JsonReader} that reads a {@link InputStream}. + *

+ * If a provider could not be found on the classpath this will use the default implementation, effectively the + * equivalent to + * {@link #createReader(InputStream, JsonOptions, boolean) createReader(json, new JsonOptions(), true)}. + * + * @param json The JSON represented as a {@link InputStream}. + * @return A new instance of {@link JsonReader}. + * @throws NullPointerException If {@code json} is null. + */ + public static JsonReader createReader(InputStream json) { + return createReader(json, JsonOptions.DEFAULT_OPTIONS, true); + } + + /** + * Creates an instance of {@link JsonReader} that reads a {@link InputStream}. + * + * @param json The JSON represented as a {@link InputStream}. + * @param options {@link JsonOptions} to configure the creation of the {@link JsonReader}. + * @param useDefault Whether the default implementation should be used if one could not be found on the classpath. + * @return A new instance of {@link JsonReader}. + * @throws NullPointerException If {@code json} is null. + * @throws IllegalStateException If a provider could not be found on the classpath and {@code useDefault} is false. + */ + public static JsonReader createReader(InputStream json, JsonOptions options, boolean useDefault) { + if (defaultProvider == null) { + if (useDefault) { + return DefaultJsonReader.fromStream(json, options); + } else { + throw new IllegalStateException(CANNOT_FIND_JSON); + } + } else { + return defaultProvider.createReader(json, options); + } + } + + /** + * Creates an instance of {@link JsonReader} that reads a {@link Reader}. + *

+ * If a provider could not be found on the classpath this will use the default implementation, effectively the + * equivalent to {@link #createReader(Reader, JsonOptions, boolean) createReader(json, new JsonOptions(), true)}. + * + * @param json The JSON represented as a {@link Reader}. + * @return A new instance of {@link JsonReader}. + * @throws NullPointerException If {@code json} is null. + */ + public static JsonReader createReader(Reader json) { + return createReader(json, JsonOptions.DEFAULT_OPTIONS, true); + } + + /** + * Creates an instance of {@link JsonReader} that reads a {@link Reader}. + * + * @param json The JSON represented as a {@link Reader}. + * @param options {@link JsonOptions} to configure the creation of the {@link JsonReader}. + * @param useDefault Whether the default implementation should be used if one could not be found on the classpath. + * @return A new instance of {@link JsonReader}. + * @throws NullPointerException If {@code json} is null. + * @throws IllegalStateException If a provider could not be found on the classpath and {@code useDefault} is false. + */ + public static JsonReader createReader(Reader json, JsonOptions options, boolean useDefault) { + if (defaultProvider == null) { + if (useDefault) { + return DefaultJsonReader.fromReader(json, options); + } else { + throw new IllegalStateException(CANNOT_FIND_JSON); + } + } else { + return defaultProvider.createReader(json, options); + } + } + + /** + * Creates an instance of {@link JsonWriter} that writes to an {@link OutputStream}. + *

+ * If a provider could not be found on the classpath this will use the default implementation, effectively the + * equivalent to + * {@link #createWriter(OutputStream, JsonOptions, boolean) createWriter(json, new JsonOptions(), true)}. + * + * @param json The JSON represented as an {@link OutputStream}. + * @return A new instance of {@link JsonWriter}. + * @throws NullPointerException If {@code json} is null. + */ + public static JsonWriter createWriter(OutputStream json) { + return createWriter(json, JsonOptions.DEFAULT_OPTIONS, true); + } + + /** + * Creates an instance of {@link JsonWriter} that writes to an {@link OutputStream}. + * + * @param json The JSON represented as an {@link OutputStream}. + * @param options {@link JsonOptions} to configure the creation of the {@link JsonWriter}. + * @param useDefault Whether the default implementation should be used if one could not be found on the classpath. + * @return A new instance of {@link JsonWriter}. + * @throws NullPointerException If {@code json} is null. + * @throws IllegalStateException If a provider could not be found on the classpath and {@code useDefault} is false. + */ + public static JsonWriter createWriter(OutputStream json, JsonOptions options, boolean useDefault) { + if (defaultProvider == null) { + if (useDefault) { + return DefaultJsonWriter.toStream(json, options); + } else { + throw new IllegalStateException(CANNOT_FIND_JSON); + } + } else { + return defaultProvider.createWriter(json, options); + } + } + + /** + * Creates an instance of {@link JsonWriter} that writes to an {@link Writer}. + *

+ * If a provider could not be found on the classpath this will use the default implementation, effectively the + * equivalent to {@link #createWriter(Writer, JsonOptions, boolean) createWriter(json, new JsonOptions(), true)}. + * + * @param json The JSON represented as an {@link Writer}. + * @return A new instance of {@link JsonWriter}. + * @throws NullPointerException If {@code json} is null. + */ + public static JsonWriter createWriter(Writer json) { + return createWriter(json, JsonOptions.DEFAULT_OPTIONS, true); + } + + /** + * Creates an instance of {@link JsonWriter} that writes to an {@link Writer}. + * + * @param json The JSON represented as an {@link Writer}. + * @param options {@link JsonOptions} to configure the creation of the {@link JsonWriter}. + * @param useDefault Whether the default implementation should be used if one could not be found on the classpath. + * @return A new instance of {@link JsonWriter}. + * @throws NullPointerException If {@code json} is null. + * @throws IllegalStateException If a provider could not be found on the classpath and {@code useDefault} is false. + */ + public static JsonWriter createWriter(Writer json, JsonOptions options, boolean useDefault) { + if (defaultProvider == null) { + if (useDefault) { + return DefaultJsonWriter.toWriter(json, options); + } else { + throw new IllegalStateException(CANNOT_FIND_JSON); + } + } else { + return defaultProvider.createWriter(json, options); + } + } +} diff --git a/sdk/core/azure-json/src/main/java/com/azure/json/JsonReader.java b/sdk/core/azure-json/src/main/java/com/azure/json/JsonReader.java index 04b6c0adcb9c8..7edf214626f0e 100644 --- a/sdk/core/azure-json/src/main/java/com/azure/json/JsonReader.java +++ b/sdk/core/azure-json/src/main/java/com/azure/json/JsonReader.java @@ -491,7 +491,14 @@ private Object readUntypedHelper(int depth) { return getBoolean(); } else if (token == JsonToken.NUMBER) { String numberText = getText(); - if (numberText.contains(".")) { + + if ("INF".equals(numberText) || "Infinity".equals(numberText) + || "-INF".equals(numberText) || "-Infinity".equals(numberText) + || "NaN".equals(numberText)) { + // Return special Double values as text as not all implementations of JsonReader may be able to handle + // them as Doubles when parsing generically. + return numberText; + } else if (numberText.contains(".")) { // Unlike integers always use Double to prevent floating point rounding issues. return Double.parseDouble(numberText); } else { diff --git a/sdk/core/azure-json/src/main/java/com/azure/json/JsonToken.java b/sdk/core/azure-json/src/main/java/com/azure/json/JsonToken.java index f87889278f47e..f33f3594647f0 100644 --- a/sdk/core/azure-json/src/main/java/com/azure/json/JsonToken.java +++ b/sdk/core/azure-json/src/main/java/com/azure/json/JsonToken.java @@ -50,5 +50,10 @@ public enum JsonToken { /** * String, in value context. */ - STRING + STRING, + + /** + * JSON document has completed. + */ + END_DOCUMENT } diff --git a/sdk/core/azure-json/src/main/java/com/azure/json/DefaultJsonReader.java b/sdk/core/azure-json/src/main/java/com/azure/json/implementation/DefaultJsonReader.java similarity index 62% rename from sdk/core/azure-json/src/main/java/com/azure/json/DefaultJsonReader.java rename to sdk/core/azure-json/src/main/java/com/azure/json/implementation/DefaultJsonReader.java index f62e87e4aec36..dcc197af19dbc 100644 --- a/sdk/core/azure-json/src/main/java/com/azure/json/DefaultJsonReader.java +++ b/sdk/core/azure-json/src/main/java/com/azure/json/implementation/DefaultJsonReader.java @@ -1,13 +1,19 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.json; +package com.azure.json.implementation; +import com.azure.json.JsonOptions; +import com.azure.json.JsonReader; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; import com.azure.json.implementation.jackson.core.JsonFactory; import com.azure.json.implementation.jackson.core.JsonParser; +import com.azure.json.implementation.jackson.core.json.JsonReadFeature; import java.io.IOException; import java.io.InputStream; +import java.io.Reader; import java.io.UncheckedIOException; /** @@ -20,18 +26,22 @@ public final class DefaultJsonReader extends JsonReader { private final byte[] jsonBytes; private final String jsonString; private final boolean resetSupported; + private final boolean nonNumericNumbersSupported; + + private JsonToken currentToken; /** * Constructs an instance of {@link DefaultJsonReader} from a {@code byte[]}. * * @param json JSON {@code byte[]}. + * @param options {@link JsonOptions} to configure the creation of the {@link JsonReader}. * @return An instance of {@link DefaultJsonReader}. * @throws UncheckedIOException If a {@link DefaultJsonReader} wasn't able to be constructed from the JSON * {@code byte[]}. */ - public static JsonReader fromBytes(byte[] json) { + public static JsonReader fromBytes(byte[] json, JsonOptions options) { try { - return new DefaultJsonReader(FACTORY.createParser(json), true, json, null); + return new DefaultJsonReader(FACTORY.createParser(json), true, json, null, options); } catch (IOException e) { throw new UncheckedIOException(e); } @@ -41,12 +51,13 @@ public static JsonReader fromBytes(byte[] json) { * Constructs an instance of {@link DefaultJsonReader} from a String. * * @param json JSON String. + * @param options {@link JsonOptions} to configure the creation of the {@link JsonWriter}. * @return An instance of {@link DefaultJsonReader}. * @throws UncheckedIOException If a {@link DefaultJsonReader} wasn't able to be constructed from the JSON String. */ - public static JsonReader fromString(String json) { + public static JsonReader fromString(String json, JsonOptions options) { try { - return new DefaultJsonReader(FACTORY.createParser(json), true, null, json); + return new DefaultJsonReader(FACTORY.createParser(json), true, null, json, options); } catch (IOException e) { throw new UncheckedIOException(e); } @@ -56,34 +67,61 @@ public static JsonReader fromString(String json) { * Constructs an instance of {@link DefaultJsonReader} from an {@link InputStream}. * * @param json JSON {@link InputStream}. + * @param options {@link JsonOptions} to configure the creation of the {@link JsonWriter}. * @return An instance of {@link DefaultJsonReader}. * @throws UncheckedIOException If a {@link DefaultJsonReader} wasn't able to be constructed from the JSON * {@link InputStream}. */ - public static JsonReader fromStream(InputStream json) { + public static JsonReader fromStream(InputStream json, JsonOptions options) { + try { + return new DefaultJsonReader(FACTORY.createParser(json), json.markSupported(), null, null, options); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + /** + * Constructs an instance of {@link DefaultJsonReader} from a {@link Reader}. + * + * @param reader JSON {@link Reader}. + * @param options {@link JsonOptions} to configure the creation of the {@link JsonWriter}. + * @return An instance of {@link DefaultJsonReader}. + * @throws UncheckedIOException If a {@link DefaultJsonReader} wasn't able to be constructed from the JSON + * {@link Reader}. + */ + public static JsonReader fromReader(Reader reader, JsonOptions options) { try { - return new DefaultJsonReader(FACTORY.createParser(json), true, null, null); + return new DefaultJsonReader(FACTORY.createParser(reader), reader.markSupported(), null, null, options); } catch (IOException e) { throw new UncheckedIOException(e); } } - private DefaultJsonReader(JsonParser parser, boolean resetSupported, byte[] jsonBytes, String jsonString) { + private DefaultJsonReader(JsonParser parser, boolean resetSupported, byte[] jsonBytes, String jsonString, + JsonOptions options) { + this(parser, resetSupported, jsonBytes, jsonString, options.isNonNumericNumbersSupported()); + } + + private DefaultJsonReader(JsonParser parser, boolean resetSupported, byte[] jsonBytes, String jsonString, + boolean nonNumericNumbersSupported) { this.parser = parser; + this.parser.configure(JsonReadFeature.ALLOW_NON_NUMERIC_NUMBERS.mappedFeature(), nonNumericNumbersSupported); this.resetSupported = resetSupported; this.jsonBytes = jsonBytes; this.jsonString = jsonString; + this.nonNumericNumbersSupported = nonNumericNumbersSupported; } @Override public JsonToken currentToken() { - return mapToken(parser.currentToken()); + return currentToken; } @Override public JsonToken nextToken() { try { - return mapToken(parser.nextToken()); + currentToken = mapToken(parser.nextToken(), currentToken); + return currentToken; } catch (IOException e) { throw new UncheckedIOException(e); } @@ -181,7 +219,12 @@ public JsonReader bufferObject() { || (currentToken == JsonToken.FIELD_NAME && nextToken() == JsonToken.START_OBJECT)) { StringBuilder bufferedObject = new StringBuilder(); readChildren(bufferedObject); - return DefaultJsonReader.fromString(bufferedObject.toString()); + String json = bufferedObject.toString(); + try { + return new DefaultJsonReader(FACTORY.createParser(json), true, null, json, nonNumericNumbersSupported); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } } else { throw new IllegalStateException("Cannot buffer a JSON object from a non-object, non-field name " + "starting location. Starting location: " + currentToken()); @@ -199,10 +242,16 @@ public JsonReader reset() { throw new IllegalStateException("'reset' isn't supported by this JsonReader."); } - if (jsonBytes != null) { - return DefaultJsonReader.fromBytes(jsonBytes); - } else { - return DefaultJsonReader.fromString(jsonString); + try { + if (jsonBytes != null) { + return new DefaultJsonReader(FACTORY.createParser(jsonBytes), true, jsonBytes, null, + nonNumericNumbersSupported); + } else { + return new DefaultJsonReader(FACTORY.createParser(jsonString), true, null, jsonString, + nonNumericNumbersSupported); + } + } catch (IOException ex) { + throw new UncheckedIOException(ex); } } @@ -217,30 +266,24 @@ public void close() throws IOException { * azure-json doesn't support the EMBEDDED_OBJECT or NOT_AVAILABLE Jackson Core JsonTokens, but those should only * be returned by specialty implementations that aren't used. */ - private static JsonToken mapToken(com.azure.json.implementation.jackson.core.JsonToken token) { + private static JsonToken mapToken(com.azure.json.implementation.jackson.core.JsonToken nextToken, + JsonToken currentToken) { // Special case for when currentToken is called after instantiating the JsonReader. - if (token == null) { + if (nextToken == null && currentToken == null) { return null; + } else if (nextToken == null) { + return JsonToken.END_DOCUMENT; } - switch (token) { - case START_OBJECT: - return JsonToken.START_OBJECT; - - case END_OBJECT: - return JsonToken.END_OBJECT; - - case START_ARRAY: - return JsonToken.START_ARRAY; - - case END_ARRAY: - return JsonToken.END_ARRAY; + switch (nextToken) { + case START_OBJECT: return JsonToken.START_OBJECT; + case END_OBJECT: return JsonToken.END_OBJECT; - case FIELD_NAME: - return JsonToken.FIELD_NAME; + case START_ARRAY: return JsonToken.START_ARRAY; + case END_ARRAY: return JsonToken.END_ARRAY; - case VALUE_STRING: - return JsonToken.STRING; + case FIELD_NAME: return JsonToken.FIELD_NAME; + case VALUE_STRING: return JsonToken.STRING; case VALUE_NUMBER_INT: case VALUE_NUMBER_FLOAT: @@ -250,11 +293,10 @@ private static JsonToken mapToken(com.azure.json.implementation.jackson.core.Jso case VALUE_FALSE: return JsonToken.BOOLEAN; - case VALUE_NULL: - return JsonToken.NULL; + case VALUE_NULL: return JsonToken.NULL; default: - throw new IllegalStateException("Unsupported token type: '" + token + "'."); + throw new IllegalStateException("Unsupported token type: '" + nextToken + "'."); } } } diff --git a/sdk/core/azure-json/src/main/java/com/azure/json/DefaultJsonWriter.java b/sdk/core/azure-json/src/main/java/com/azure/json/implementation/DefaultJsonWriter.java similarity index 82% rename from sdk/core/azure-json/src/main/java/com/azure/json/DefaultJsonWriter.java rename to sdk/core/azure-json/src/main/java/com/azure/json/implementation/DefaultJsonWriter.java index e45830914ae2a..5ce38df8786a0 100644 --- a/sdk/core/azure-json/src/main/java/com/azure/json/DefaultJsonWriter.java +++ b/sdk/core/azure-json/src/main/java/com/azure/json/implementation/DefaultJsonWriter.java @@ -1,14 +1,20 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.json; +package com.azure.json.implementation; +import com.azure.json.JsonOptions; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriteContext; +import com.azure.json.JsonWriter; import com.azure.json.implementation.jackson.core.JsonFactory; import com.azure.json.implementation.jackson.core.JsonGenerator; +import com.azure.json.implementation.jackson.core.json.JsonWriteFeature; import java.io.IOException; import java.io.OutputStream; import java.io.UncheckedIOException; +import java.io.Writer; import java.util.Objects; /** @@ -29,20 +35,43 @@ public final class DefaultJsonWriter extends JsonWriter { * isn't the owner of the stream. * * @param stream The {@link OutputStream} that will be written. + * @param options {@link JsonOptions} to configure the creation of the {@link JsonWriter}. * @return An instance of {@link DefaultJsonWriter}. * @throws UncheckedIOException If a {@link DefaultJsonWriter} wasn't able to be constructed from the * {@link OutputStream}. */ - public static JsonWriter toStream(OutputStream stream) { + public static JsonWriter toStream(OutputStream stream, JsonOptions options) { try { - return new DefaultJsonWriter(FACTORY.createGenerator(stream)); + return new DefaultJsonWriter(FACTORY.createGenerator(stream), options); } catch (IOException e) { throw new UncheckedIOException(e); } } - private DefaultJsonWriter(JsonGenerator generator) { + /** + * Creates a {@link DefaultJsonWriter} that writes the given {@link Writer}. + *

+ * The passed {@link Writer} won't be closed when {@link #close()} is called as the {@link DefaultJsonWriter} + * isn't the owner of the stream. + * + * @param writer The {@link Writer} that will be written. + * @param options {@link JsonOptions} to configure the creation of the {@link JsonWriter}. + * @return An instance of {@link DefaultJsonWriter}. + * @throws UncheckedIOException If a {@link DefaultJsonWriter} wasn't able to be constructed from the + * {@link Writer}. + */ + public static JsonWriter toWriter(Writer writer, JsonOptions options) { + try { + return new DefaultJsonWriter(FACTORY.createGenerator(writer), options); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + private DefaultJsonWriter(JsonGenerator generator, JsonOptions options) { this.generator = generator; + this.generator.configure(JsonWriteFeature.WRITE_NAN_AS_STRINGS.mappedFeature(), + options.isNonNumericNumbersSupported()); } @Override diff --git a/sdk/core/azure-json/src/main/java/com/azure/json/implementation/package-info.java b/sdk/core/azure-json/src/main/java/com/azure/json/implementation/package-info.java new file mode 100644 index 0000000000000..46016bb266715 --- /dev/null +++ b/sdk/core/azure-json/src/main/java/com/azure/json/implementation/package-info.java @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +/** + * Contains general implementation classes for handling JSON. + */ +package com.azure.json.implementation; diff --git a/sdk/core/azure-json/src/main/java/module-info.java b/sdk/core/azure-json/src/main/java/module-info.java index 614f137bfebec..2ee0b1b8bac4e 100644 --- a/sdk/core/azure-json/src/main/java/module-info.java +++ b/sdk/core/azure-json/src/main/java/module-info.java @@ -3,4 +3,7 @@ module com.azure.json { exports com.azure.json; + exports com.azure.json.implementation; + + uses com.azure.json.JsonProvider; } diff --git a/sdk/core/azure-json/src/test/java/com/azure/json/contract/JsonReaderContractTests.java b/sdk/core/azure-json/src/test/java/com/azure/json/contract/JsonReaderContractTests.java index 035a05cbf315d..61b968d59e6d3 100644 --- a/sdk/core/azure-json/src/test/java/com/azure/json/contract/JsonReaderContractTests.java +++ b/sdk/core/azure-json/src/test/java/com/azure/json/contract/JsonReaderContractTests.java @@ -13,14 +13,21 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Base64; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import java.util.function.Function; import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -46,13 +53,14 @@ public abstract class JsonReaderContractTests { @ParameterizedTest @MethodSource("basicOperationsSupplier") - public void basicOperations(String json, T expectedValue, Function function) { - JsonReader reader = getJsonReader(json); - reader.nextToken(); // Initialize the JsonReader for reading. + public void basicOperations(String json, T expectedValue, Function function) throws IOException { + try (JsonReader reader = getJsonReader(json)) { + reader.nextToken(); // Initialize the JsonReader for reading. - T actualValue = assertDoesNotThrow(() -> function.apply(reader)); + T actualValue = assertDoesNotThrow(() -> function.apply(reader)); - assertEquals(expectedValue, actualValue); + assertEquals(expectedValue, actualValue); + } } private static Stream basicOperationsSupplier() { @@ -98,13 +106,14 @@ private static Stream basicOperationsSupplier() { // Byte arrays can't use Object.equals as they'll be compared by memory location instead of value equality. @ParameterizedTest @MethodSource("binaryOperationsSupplier") - public void binaryOperations(String json, byte[] expectedValue, Function function) { - JsonReader reader = getJsonReader(json); - reader.nextToken(); // Initialize the JsonReader for reading. + public void binaryOperations(String json, byte[] expectedValue, Function function) throws IOException { + try (JsonReader reader = getJsonReader(json)) { + reader.nextToken(); // Initialize the JsonReader for reading. - byte[] actualValue = assertDoesNotThrow(() -> function.apply(reader)); + byte[] actualValue = assertDoesNotThrow(() -> function.apply(reader)); - assertArrayEquals(expectedValue, actualValue); + assertArrayEquals(expectedValue, actualValue); + } } private static Stream binaryOperationsSupplier() { @@ -118,137 +127,142 @@ private static Stream binaryOperationsSupplier() { } @Test - public void emptyObject() { + public void emptyObject() throws IOException { String json = "{}"; - JsonReader reader = getJsonReader(json); + try (JsonReader reader = getJsonReader(json)) { - assertJsonReaderStructInitialization(reader, JsonToken.START_OBJECT); + assertJsonReaderStructInitialization(reader, JsonToken.START_OBJECT); - while (reader.nextToken() != JsonToken.END_OBJECT) { - fail("Empty object shouldn't have any non-END_OBJECT JsonTokens but found: " + reader.currentToken()); + while (reader.nextToken() != JsonToken.END_OBJECT) { + fail("Empty object shouldn't have any non-END_OBJECT JsonTokens but found: " + reader.currentToken()); + } } } @Test - public void emptyArray() { + public void emptyArray() throws IOException { String json = "[]"; - JsonReader reader = getJsonReader(json); + try (JsonReader reader = getJsonReader(json)) { - assertJsonReaderStructInitialization(reader, JsonToken.START_ARRAY); + assertJsonReaderStructInitialization(reader, JsonToken.START_ARRAY); - while (reader.nextToken() != JsonToken.END_ARRAY) { - fail("Empty array shouldn't have any non-END_ARRAY JsonTokens but found: " + reader.currentToken()); + while (reader.nextToken() != JsonToken.END_ARRAY) { + fail("Empty array shouldn't have any non-END_ARRAY JsonTokens but found: " + reader.currentToken()); + } } } @Test - public void simpleObject() { + public void simpleObject() throws IOException { String json = "{\"stringProperty\":\"string\",\"nullProperty\":null,\"integerProperty\":10,\"floatProperty\":10.0,\"booleanProperty\":true}"; - JsonReader reader = getJsonReader(json); - - assertJsonReaderStructInitialization(reader, JsonToken.START_OBJECT); - - String stringProperty = null; - boolean hasNullProperty = false; - int integerProperty = 0; - float floatProperty = 0.0F; - boolean booleanProperty = false; - while (reader.nextToken() != JsonToken.END_OBJECT) { - String fieldName = reader.getFieldName(); - reader.nextToken(); - - if ("stringProperty".equals(fieldName)) { - stringProperty = reader.getString(); - } else if ("nullProperty".equals(fieldName)) { - hasNullProperty = true; - } else if ("integerProperty".equals(fieldName)) { - integerProperty = reader.getInt(); - } else if ("floatProperty".equals(fieldName)) { - floatProperty = reader.getFloat(); - } else if ("booleanProperty".equals(fieldName)) { - booleanProperty = reader.getBoolean(); - } else { - fail("Unknown property name: '" + fieldName + "'"); + try (JsonReader reader = getJsonReader(json)) { + + assertJsonReaderStructInitialization(reader, JsonToken.START_OBJECT); + + String stringProperty = null; + boolean hasNullProperty = false; + int integerProperty = 0; + float floatProperty = 0.0F; + boolean booleanProperty = false; + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("stringProperty".equals(fieldName)) { + stringProperty = reader.getString(); + } else if ("nullProperty".equals(fieldName)) { + hasNullProperty = true; + } else if ("integerProperty".equals(fieldName)) { + integerProperty = reader.getInt(); + } else if ("floatProperty".equals(fieldName)) { + floatProperty = reader.getFloat(); + } else if ("booleanProperty".equals(fieldName)) { + booleanProperty = reader.getBoolean(); + } else { + fail("Unknown property name: '" + fieldName + "'"); + } } - } - assertEquals("string", stringProperty); - assertTrue(hasNullProperty, "Didn't find the expected 'nullProperty'."); - assertEquals(10, integerProperty); - assertEquals(10.0F, floatProperty); - assertEquals(true, booleanProperty); + assertEquals("string", stringProperty); + assertTrue(hasNullProperty, "Didn't find the expected 'nullProperty'."); + assertEquals(10, integerProperty); + assertEquals(10.0F, floatProperty); + assertEquals(true, booleanProperty); + } } @Test - public void arrayOfBasicTypesInJsonRoot() { + public void arrayOfBasicTypesInJsonRoot() throws IOException { String json = "[\"string\",null,10,10.0,true]"; - JsonReader reader = getJsonReader(json); + try (JsonReader reader = getJsonReader(json)) { - assertJsonReaderStructInitialization(reader, JsonToken.START_ARRAY); + assertJsonReaderStructInitialization(reader, JsonToken.START_ARRAY); - Object[] jsonArray = new Object[5]; - int jsonArrayIndex = 0; - while (reader.nextToken() != JsonToken.END_ARRAY) { - jsonArray[jsonArrayIndex++] = ContractUtils.readUntypedField(reader); - } + Object[] jsonArray = new Object[5]; + int jsonArrayIndex = 0; + while (reader.nextToken() != JsonToken.END_ARRAY) { + jsonArray[jsonArrayIndex++] = ContractUtils.readUntypedField(reader); + } - assertEquals("string", jsonArray[0]); - assertNull(jsonArray[1]); - assertEquals(10, jsonArray[2]); - assertEquals(10.0F, jsonArray[3]); - assertEquals(true, jsonArray[4]); + assertEquals("string", jsonArray[0]); + assertNull(jsonArray[1]); + assertEquals(10, jsonArray[2]); + assertEquals(10.0F, jsonArray[3]); + assertEquals(true, jsonArray[4]); + } } @ParameterizedTest @MethodSource("objectWithInnerObjectSupplier") - public void objectWithInnerObject(String json) { - JsonReader reader = getJsonReader(json); - - assertJsonReaderStructInitialization(reader, JsonToken.START_OBJECT); - - String stringProperty = null; - boolean hasNullProperty = false; - int integerProperty = 0; - float floatProperty = 0.0F; - boolean booleanProperty = false; - String innerStringProperty = null; - while (reader.nextToken() != JsonToken.END_OBJECT) { - String fieldName = reader.getFieldName(); - reader.nextToken(); - - if ("stringProperty".equals(fieldName)) { - stringProperty = reader.getString(); - } else if ("nullProperty".equals(fieldName)) { - hasNullProperty = true; - } else if ("integerProperty".equals(fieldName)) { - integerProperty = reader.getInt(); - } else if ("floatProperty".equals(fieldName)) { - floatProperty = reader.getFloat(); - } else if ("booleanProperty".equals(fieldName)) { - booleanProperty = reader.getBoolean(); - } else if ("innerObject".equals(fieldName)) { - assertEquals(JsonToken.START_OBJECT, reader.currentToken()); - while (reader.nextToken() != JsonToken.END_OBJECT) { - fieldName = reader.getFieldName(); - reader.nextToken(); - - if ("innerStringProperty".equals(fieldName)) { - innerStringProperty = reader.getString(); - } else { - fail("Unknown property name: '" + fieldName + "'"); + public void objectWithInnerObject(String json) throws IOException { + try (JsonReader reader = getJsonReader(json)) { + + assertJsonReaderStructInitialization(reader, JsonToken.START_OBJECT); + + String stringProperty = null; + boolean hasNullProperty = false; + int integerProperty = 0; + float floatProperty = 0.0F; + boolean booleanProperty = false; + String innerStringProperty = null; + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("stringProperty".equals(fieldName)) { + stringProperty = reader.getString(); + } else if ("nullProperty".equals(fieldName)) { + hasNullProperty = true; + } else if ("integerProperty".equals(fieldName)) { + integerProperty = reader.getInt(); + } else if ("floatProperty".equals(fieldName)) { + floatProperty = reader.getFloat(); + } else if ("booleanProperty".equals(fieldName)) { + booleanProperty = reader.getBoolean(); + } else if ("innerObject".equals(fieldName)) { + assertEquals(JsonToken.START_OBJECT, reader.currentToken()); + while (reader.nextToken() != JsonToken.END_OBJECT) { + fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("innerStringProperty".equals(fieldName)) { + innerStringProperty = reader.getString(); + } else { + fail("Unknown property name: '" + fieldName + "'"); + } } + } else { + fail("Unknown property name: '" + fieldName + "'"); } - } else { - fail("Unknown property name: '" + fieldName + "'"); } - } - assertEquals("string", stringProperty); - assertTrue(hasNullProperty, "Didn't find the expected 'nullProperty'."); - assertEquals(10, integerProperty); - assertEquals(10.0F, floatProperty); - assertEquals(true, booleanProperty); - assertEquals("innerString", innerStringProperty); + assertEquals("string", stringProperty); + assertTrue(hasNullProperty, "Didn't find the expected 'nullProperty'."); + assertEquals(10, integerProperty); + assertEquals(10.0F, floatProperty); + assertEquals(true, booleanProperty); + assertEquals("innerString", innerStringProperty); + } } private static Stream objectWithInnerObjectSupplier() { @@ -270,50 +284,51 @@ private static Stream objectWithInnerObjectSupplier() { @ParameterizedTest @MethodSource("objectWithInnerArraySupplier") - public void objectWithInnerArray(String json) { - JsonReader reader = getJsonReader(json); - - assertJsonReaderStructInitialization(reader, JsonToken.START_OBJECT); - - String stringProperty = null; - boolean hasNullProperty = false; - int integerProperty = 0; - float floatProperty = 0.0F; - boolean booleanProperty = false; - String innerStringProperty = null; - while (reader.nextToken() != JsonToken.END_OBJECT) { - String fieldName = reader.getFieldName(); - reader.nextToken(); - - if ("stringProperty".equals(fieldName)) { - stringProperty = reader.getString(); - } else if ("nullProperty".equals(fieldName)) { - hasNullProperty = true; - } else if ("integerProperty".equals(fieldName)) { - integerProperty = reader.getInt(); - } else if ("floatProperty".equals(fieldName)) { - floatProperty = reader.getFloat(); - } else if ("booleanProperty".equals(fieldName)) { - booleanProperty = reader.getBoolean(); - } else if ("innerArray".equals(fieldName)) { - assertEquals(JsonToken.START_ARRAY, reader.currentToken()); - while (reader.nextToken() != JsonToken.END_ARRAY) { - if (innerStringProperty != null) { - fail("Only expected one value in the inner array but found more."); + public void objectWithInnerArray(String json) throws IOException { + try (JsonReader reader = getJsonReader(json)) { + + assertJsonReaderStructInitialization(reader, JsonToken.START_OBJECT); + + String stringProperty = null; + boolean hasNullProperty = false; + int integerProperty = 0; + float floatProperty = 0.0F; + boolean booleanProperty = false; + String innerStringProperty = null; + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("stringProperty".equals(fieldName)) { + stringProperty = reader.getString(); + } else if ("nullProperty".equals(fieldName)) { + hasNullProperty = true; + } else if ("integerProperty".equals(fieldName)) { + integerProperty = reader.getInt(); + } else if ("floatProperty".equals(fieldName)) { + floatProperty = reader.getFloat(); + } else if ("booleanProperty".equals(fieldName)) { + booleanProperty = reader.getBoolean(); + } else if ("innerArray".equals(fieldName)) { + assertEquals(JsonToken.START_ARRAY, reader.currentToken()); + while (reader.nextToken() != JsonToken.END_ARRAY) { + if (innerStringProperty != null) { + fail("Only expected one value in the inner array but found more."); + } + innerStringProperty = reader.getString(); } - innerStringProperty = reader.getString(); + } else { + fail("Unknown property name: '" + fieldName + "'"); } - } else { - fail("Unknown property name: '" + fieldName + "'"); } - } - assertEquals("string", stringProperty); - assertTrue(hasNullProperty, "Didn't find the expected 'nullProperty'."); - assertEquals(10, integerProperty); - assertEquals(10.0F, floatProperty); - assertEquals(true, booleanProperty); - assertEquals("innerString", innerStringProperty); + assertEquals("string", stringProperty); + assertTrue(hasNullProperty, "Didn't find the expected 'nullProperty'."); + assertEquals(10, integerProperty); + assertEquals(10.0F, floatProperty); + assertEquals(true, booleanProperty); + assertEquals("innerString", innerStringProperty); + } } private static Stream objectWithInnerArraySupplier() { @@ -334,33 +349,34 @@ private static Stream objectWithInnerArraySupplier() { @ParameterizedTest @MethodSource("arrayWithInnerArraySupplier") - public void arrayWithInnerArray(String json) { - JsonReader reader = getJsonReader(json); + public void arrayWithInnerArray(String json) throws IOException { + try (JsonReader reader = getJsonReader(json)) { - assertJsonReaderStructInitialization(reader, JsonToken.START_ARRAY); + assertJsonReaderStructInitialization(reader, JsonToken.START_ARRAY); - Object[] jsonArray = new Object[6]; - int jsonArrayIndex = 0; - while (reader.nextToken() != JsonToken.END_ARRAY) { - if (reader.currentToken() == JsonToken.START_ARRAY) { - while (reader.nextToken() != JsonToken.END_ARRAY) { - if (jsonArray[5] != null) { - fail("Only expected one value in the inner array but found more."); - } + Object[] jsonArray = new Object[6]; + int jsonArrayIndex = 0; + while (reader.nextToken() != JsonToken.END_ARRAY) { + if (reader.currentToken() == JsonToken.START_ARRAY) { + while (reader.nextToken() != JsonToken.END_ARRAY) { + if (jsonArray[5] != null) { + fail("Only expected one value in the inner array but found more."); + } - jsonArray[5] = reader.getString(); + jsonArray[5] = reader.getString(); + } + } else { + jsonArray[jsonArrayIndex++] = ContractUtils.readUntypedField(reader); } - } else { - jsonArray[jsonArrayIndex++] = ContractUtils.readUntypedField(reader); } - } - assertEquals("string", jsonArray[0]); - assertNull(jsonArray[1]); - assertEquals(10, jsonArray[2]); - assertEquals(10.0F, jsonArray[3]); - assertEquals(true, jsonArray[4]); - assertEquals("innerString", jsonArray[5]); + assertEquals("string", jsonArray[0]); + assertNull(jsonArray[1]); + assertEquals(10, jsonArray[2]); + assertEquals(10.0F, jsonArray[3]); + assertEquals(true, jsonArray[4]); + assertEquals("innerString", jsonArray[5]); + } } private static Stream arrayWithInnerArraySupplier() { @@ -378,36 +394,37 @@ private static Stream arrayWithInnerArraySupplier() { @ParameterizedTest @MethodSource("arrayWithInnerObjectSupplier") - public void arrayWithInnerObject(String json) { - JsonReader reader = getJsonReader(json); - - assertJsonReaderStructInitialization(reader, JsonToken.START_ARRAY); - - Object[] jsonArray = new Object[6]; - int jsonArrayIndex = 0; - while (reader.nextToken() != JsonToken.END_ARRAY) { - if (reader.currentToken() == JsonToken.START_OBJECT) { - while (reader.nextToken() != JsonToken.END_OBJECT) { - String fieldName = reader.getFieldName(); - reader.nextToken(); - - if ("innerStringProperty".equals(fieldName)) { - jsonArray[5] = reader.getString(); - } else { - fail("Unknown property name: '" + fieldName + "'"); + public void arrayWithInnerObject(String json) throws IOException { + try (JsonReader reader = getJsonReader(json)) { + + assertJsonReaderStructInitialization(reader, JsonToken.START_ARRAY); + + Object[] jsonArray = new Object[6]; + int jsonArrayIndex = 0; + while (reader.nextToken() != JsonToken.END_ARRAY) { + if (reader.currentToken() == JsonToken.START_OBJECT) { + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("innerStringProperty".equals(fieldName)) { + jsonArray[5] = reader.getString(); + } else { + fail("Unknown property name: '" + fieldName + "'"); + } } + } else { + jsonArray[jsonArrayIndex++] = ContractUtils.readUntypedField(reader); } - } else { - jsonArray[jsonArrayIndex++] = ContractUtils.readUntypedField(reader); } - } - assertEquals("string", jsonArray[0]); - assertNull(jsonArray[1]); - assertEquals(10, jsonArray[2]); - assertEquals(10.0F, jsonArray[3]); - assertEquals(true, jsonArray[4]); - assertEquals("innerString", jsonArray[5]); + assertEquals("string", jsonArray[0]); + assertNull(jsonArray[1]); + assertEquals(10, jsonArray[2]); + assertEquals(10.0F, jsonArray[3]); + assertEquals(true, jsonArray[4]); + assertEquals("innerString", jsonArray[5]); + } } private static Stream arrayWithInnerObjectSupplier() { @@ -423,6 +440,129 @@ private static Stream arrayWithInnerObjectSupplier() { ); } + @ParameterizedTest + @MethodSource("readUntypedSimpleSupplier") + public void readUntypedSimple(String json, int nextCount, Object expected) throws IOException { + try (JsonReader reader = getJsonReader(json)) { + for (int i = 0; i < nextCount; i++) { + reader.nextToken(); + } + + Object actual = reader.readUntyped(); + assertEquals(expected, actual); + } + + } + + private static Stream readUntypedSimpleSupplier() { + return Stream.of( + Arguments.of("null", 1, null), + Arguments.of("true", 1, true), + Arguments.of("false", 1, false), + Arguments.of("3.14", 1, 3.14), + Arguments.of("NaN", 1, String.valueOf(Double.NaN)), + Arguments.of("-Infinity", 1, String.valueOf(Double.NEGATIVE_INFINITY)), + Arguments.of("Infinity", 1, String.valueOf(Double.POSITIVE_INFINITY)), + Arguments.of("42", 1, 42), + Arguments.of("420000000000", 1, 420000000000L), + Arguments.of("\"hello\"", 1, "hello") + ); + } + + @SuppressWarnings("unchecked") + @ParameterizedTest + @MethodSource("readUntypedArraySupplier") + public void readUntypedArray(String json, int nextCount, List expected) throws IOException { + try (JsonReader reader = getJsonReader(json)) { + for (int i = 0; i < nextCount; i++) { + reader.nextToken(); + } + + List actual = (List) reader.readUntyped(); + assertIterableEquals(expected, actual); + } + + } + + private static Stream readUntypedArraySupplier() { + return Stream.of( + Arguments.of("[]", 1, new ArrayList<>()), + Arguments.of("[42,true,\"hello\"]", 1, Arrays.asList(42, true, "hello")) + ); + } + + @SuppressWarnings("unchecked") + @ParameterizedTest + @MethodSource("readUntypedObjectSupplier") + public void readUntypedObject(String json, int nextCount, Map expected) throws IOException { + try (JsonReader reader = getJsonReader(json)) { + for (int i = 0; i < nextCount; i++) { + reader.nextToken(); + } + + Map actual = (Map) reader.readUntyped(); + assertEquals(expected.size(), actual.size()); + for (Map.Entry expectedKvp : expected.entrySet()) { + assertTrue(actual.containsKey(expectedKvp.getKey())); + assertEquals(expectedKvp.getValue(), actual.get(expectedKvp.getKey())); + } + } + } + + private static Stream readUntypedObjectSupplier() { + Map complexExpected = new LinkedHashMap<>(); + complexExpected.put("field1", 42); + complexExpected.put("field2", true); + complexExpected.put("field3", "hello"); + + return Stream.of( + Arguments.of("{}", 1, new LinkedHashMap<>()), + Arguments.of("{\"field1\":42,\"field2\":true,\"field3\":\"hello\"}", 1, complexExpected) + ); + } + + @ParameterizedTest + @MethodSource("readUntypedIllegalStartSupplier") + public void readUntypedIllegalStart(String json, int nextCount) throws IOException { + try (JsonReader reader = getJsonReader(json)) { + for (int i = 0; i < nextCount; i++) { + reader.nextToken(); + } + + assertThrows(IllegalStateException.class, reader::readUntyped); + } + } + + private static Stream readUntypedIllegalStartSupplier() { + return Stream.of( + Arguments.of("{}", 2), + Arguments.of("[]", 2), + Arguments.of("{\"field\":\"value\"}", 2) + ); + } + + @Test + public void readUntypedPreventsStackOverflow() throws IOException { + // At 1000 levels of nesting readUntyped will throw an exception. + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < 1001; i++) { + builder.append("{\"field\":"); + } + + builder.append("null"); + + for (int i = 0; i < 1001; i++) { + builder.append('}'); + } + + String deeplyNestJson = builder.toString(); + + try (JsonReader reader = getJsonReader(deeplyNestJson)) { + reader.nextToken(); + assertThrows(IllegalStateException.class, reader::readUntyped); + } + } + @ParameterizedTest @MethodSource("bufferObjectSupplier") public void bufferObject(String json, int nextCount) { diff --git a/sdk/core/azure-json/src/test/java/com/azure/json/DefaultJsonReaderContractTests.java b/sdk/core/azure-json/src/test/java/com/azure/json/implementation/DefaultJsonReaderContractTests.java similarity index 69% rename from sdk/core/azure-json/src/test/java/com/azure/json/DefaultJsonReaderContractTests.java rename to sdk/core/azure-json/src/test/java/com/azure/json/implementation/DefaultJsonReaderContractTests.java index 7a957a2cc1301..171ac70a956a2 100644 --- a/sdk/core/azure-json/src/test/java/com/azure/json/DefaultJsonReaderContractTests.java +++ b/sdk/core/azure-json/src/test/java/com/azure/json/implementation/DefaultJsonReaderContractTests.java @@ -1,8 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.json; +package com.azure.json.implementation; +import com.azure.json.JsonOptions; +import com.azure.json.JsonReader; import com.azure.json.contract.JsonReaderContractTests; /** @@ -11,6 +13,6 @@ public class DefaultJsonReaderContractTests extends JsonReaderContractTests { @Override public JsonReader getJsonReader(String json) { - return DefaultJsonReader.fromString(json); + return DefaultJsonReader.fromString(json, new JsonOptions()); } } diff --git a/sdk/core/azure-json/src/test/java/com/azure/json/DefaultJsonWriterContractTests.java b/sdk/core/azure-json/src/test/java/com/azure/json/implementation/DefaultJsonWriterContractTests.java similarity index 84% rename from sdk/core/azure-json/src/test/java/com/azure/json/DefaultJsonWriterContractTests.java rename to sdk/core/azure-json/src/test/java/com/azure/json/implementation/DefaultJsonWriterContractTests.java index 1c69d7f352a63..c1117545c5f69 100644 --- a/sdk/core/azure-json/src/test/java/com/azure/json/DefaultJsonWriterContractTests.java +++ b/sdk/core/azure-json/src/test/java/com/azure/json/implementation/DefaultJsonWriterContractTests.java @@ -1,8 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.json; +package com.azure.json.implementation; +import com.azure.json.JsonOptions; +import com.azure.json.JsonWriter; import com.azure.json.contract.JsonWriterContractTests; import org.junit.jupiter.api.BeforeEach; @@ -20,7 +22,7 @@ public class DefaultJsonWriterContractTests extends JsonWriterContractTests { @BeforeEach public void beforeEach() { this.outputStream = new ByteArrayOutputStream(); - this.writer = DefaultJsonWriter.toStream(outputStream); + this.writer = DefaultJsonWriter.toStream(outputStream, new JsonOptions()); } @Override diff --git a/sdk/core/azure-xml/src/main/java/com/azure/xml/XmlProvider.java b/sdk/core/azure-xml/src/main/java/com/azure/xml/XmlProvider.java new file mode 100644 index 0000000000000..79c40e12b6f61 --- /dev/null +++ b/sdk/core/azure-xml/src/main/java/com/azure/xml/XmlProvider.java @@ -0,0 +1,69 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.xml; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; + +/** + * An interface to be implemented by any azure-xml plugin that wishes to provide an alternate {@link XmlReader} or + * {@link XmlWriter} implementation. + */ +public interface XmlProvider { + /** + * Creates an instance of {@link XmlReader} that reads a {@code byte[]}. + * + * @param json The JSON represented as a {@code byte[]}. + * @return A new instance of {@link XmlReader}. + * @throws NullPointerException If {@code json} is null. + */ + XmlReader createReader(byte[] json); + + /** + * Creates an instance of {@link XmlReader} that reads a {@link String}. + * + * @param json The JSON represented as a {@link String}. + * @return A new instance of {@link XmlReader}. + * @throws NullPointerException If {@code json} is null. + */ + XmlReader createReader(String json); + + /** + * Creates an instance of {@link XmlReader} that reads a {@link InputStream}. + * + * @param json The JSON represented as a {@link InputStream}. + * @return A new instance of {@link XmlReader}. + * @throws NullPointerException If {@code json} is null. + */ + XmlReader createReader(InputStream json); + + /** + * Creates an instance of {@link XmlReader} that reads a {@link Reader}. + * + * @param json The JSON represented as a {@link Reader}. + * @return A new instance of {@link XmlReader}. + * @throws NullPointerException If {@code json} is null. + */ + XmlReader createReader(Reader json); + + /** + * Creates an instance of {@link XmlWriter} that writes to an {@link OutputStream}. + * + * @param json The JSON represented as an {@link OutputStream}. + * @return A new instance of {@link XmlWriter}. + * @throws NullPointerException If {@code json} is null. + */ + XmlWriter createWriter(OutputStream json); + + /** + * Creates an instance of {@link XmlWriter} that writes to an {@link Writer}. + * + * @param json The JSON represented as an {@link Writer}. + * @return A new instance of {@link XmlWriter}. + * @throws NullPointerException If {@code json} is null. + */ + XmlWriter createWriter(Writer json); +} diff --git a/sdk/core/azure-xml/src/main/java/com/azure/xml/XmlProviders.java b/sdk/core/azure-xml/src/main/java/com/azure/xml/XmlProviders.java new file mode 100644 index 0000000000000..243be901851f0 --- /dev/null +++ b/sdk/core/azure-xml/src/main/java/com/azure/xml/XmlProviders.java @@ -0,0 +1,260 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.xml; + +import com.azure.xml.implementation.DefaultXmlReader; +import com.azure.xml.implementation.DefaultXmlWriter; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; +import java.util.Iterator; +import java.util.ServiceLoader; + +/** + * Handles loading an instance of {@link XmlProvider} found on the classpath. + */ +public final class XmlProviders { + private static final String CANNOT_FIND_XML = "A request was made to load an XmlReader and XmlWriter provider " + + "but one could not be found on the classpath. If you are using a dependency manager, consider including a " + + "dependency that supplies a provider for XmlProvider or indicate to the loader to fallback to the default " + + "implementation. Additionally, refer to https://aka.ms/azsdk/java/docs/custom-xml to learn about writing " + + "your own implementation."; + + private static XmlProvider defaultProvider; + + static { + // Use as classloader to load provider-configuration files and provider classes the classloader + // that loaded this class. In most cases this will be the System classloader. + // But this choice here provides additional flexibility in managed environments that control + // classloading differently (OSGi, Spring and others) and don't/ depend on the + // System classloader to load HttpClientProvider classes. + ServiceLoader serviceLoader = ServiceLoader.load(XmlProvider.class, + XmlProvider.class.getClassLoader()); + // Use the first provider found in the service loader iterator. + Iterator it = serviceLoader.iterator(); + if (it.hasNext()) { + defaultProvider = it.next(); + } + + while (it.hasNext()) { + it.next(); + } + } + + private XmlProviders() { + // no-op + } + + /** + * Creates an instance of {@link XmlReader} that reads a {@code byte[]}. + *

+ * If a provider could not be found on the classpath this will use the default implementation, effectively the + * equivalent to {@link #createReader(byte[], boolean) createReader(xml, true)}. + * + * @param xml The XML represented as a {@code byte[]}. + * @return A new instance of {@link XmlReader}. + * @throws NullPointerException If {@code xml} is null. + */ + public static XmlReader createReader(byte[] xml) { + return createReader(xml, true); + } + + /** + * Creates an instance of {@link XmlReader} that reads a {@code byte[]}. + * + * @param xml The XML represented as a {@code byte[]}. + * @param useDefault Whether the default implementation should be used if one could not be found on the classpath. + * @return A new instance of {@link XmlReader}. + * @throws NullPointerException If {@code xml} is null. + * @throws IllegalStateException If a provider could not be found on the classpath and {@code useDefault} is false. + */ + public static XmlReader createReader(byte[] xml, boolean useDefault) { + if (defaultProvider == null) { + if (useDefault) { + return DefaultXmlReader.fromBytes(xml); + } else { + throw new IllegalStateException(CANNOT_FIND_XML); + } + } else { + return defaultProvider.createReader(xml); + } + } + + /** + * Creates an instance of {@link XmlReader} that reads a {@link String}. + *

+ * If a provider could not be found on the classpath this will use the default implementation, effectively the + * equivalent to {@link #createReader(String, boolean) createReader(xml, true)}. + * + * @param xml The XML represented as a {@link String}. + * @return A new instance of {@link XmlReader}. + * @throws NullPointerException If {@code xml} is null. + */ + public static XmlReader createReader(String xml) { + return createReader(xml, true); + } + + /** + * Creates an instance of {@link XmlReader} that reads a {@link String}. + * + * @param xml The XML represented as a {@link String}. + * @param useDefault Whether the default implementation should be used if one could not be found on the classpath. + * @return A new instance of {@link XmlReader}. + * @throws NullPointerException If {@code xml} is null. + * @throws IllegalStateException If a provider could not be found on the classpath and {@code useDefault} is false. + */ + public static XmlReader createReader(String xml, boolean useDefault) { + if (defaultProvider == null) { + if (useDefault) { + return DefaultXmlReader.fromString(xml); + } else { + throw new IllegalStateException(CANNOT_FIND_XML); + } + } else { + return defaultProvider.createReader(xml); + } + } + + /** + * Creates an instance of {@link XmlReader} that reads a {@link InputStream}. + *

+ * If a provider could not be found on the classpath this will use the default implementation, effectively the + * equivalent to {@link #createReader(InputStream, boolean) createReader(xml, true)}. + * + * @param xml The XML represented as a {@link InputStream}. + * @return A new instance of {@link XmlReader}. + * @throws NullPointerException If {@code xml} is null. + */ + public static XmlReader createReader(InputStream xml) { + return createReader(xml, true); + } + + /** + * Creates an instance of {@link XmlReader} that reads a {@link InputStream}. + * + * @param xml The XML represented as a {@link InputStream}. + * @param useDefault Whether the default implementation should be used if one could not be found on the classpath. + * @return A new instance of {@link XmlReader}. + * @throws NullPointerException If {@code xml} is null. + * @throws IllegalStateException If a provider could not be found on the classpath and {@code useDefault} is false. + */ + public static XmlReader createReader(InputStream xml, boolean useDefault) { + if (defaultProvider == null) { + if (useDefault) { + return DefaultXmlReader.fromStream(xml); + } else { + throw new IllegalStateException(CANNOT_FIND_XML); + } + } else { + return defaultProvider.createReader(xml); + } + } + + /** + * Creates an instance of {@link XmlReader} that reads a {@link Reader}. + *

+ * If a provider could not be found on the classpath this will use the default implementation, effectively the + * equivalent to {@link #createReader(Reader, boolean) createReader(xml, true)}. + * + * @param xml The XML represented as a {@link Reader}. + * @return A new instance of {@link XmlReader}. + * @throws NullPointerException If {@code xml} is null. + */ + public static XmlReader createReader(Reader xml) { + return createReader(xml, true); + } + + /** + * Creates an instance of {@link XmlReader} that reads a {@link Reader}. + * + * @param xml The XML represented as a {@link Reader}. + * @param useDefault Whether the default implementation should be used if one could not be found on the classpath. + * @return A new instance of {@link XmlReader}. + * @throws NullPointerException If {@code xml} is null. + * @throws IllegalStateException If a provider could not be found on the classpath and {@code useDefault} is false. + */ + public static XmlReader createReader(Reader xml, boolean useDefault) { + if (defaultProvider == null) { + if (useDefault) { + return DefaultXmlReader.fromReader(xml); + } else { + throw new IllegalStateException(CANNOT_FIND_XML); + } + } else { + return defaultProvider.createReader(xml); + } + } + + /** + * Creates an instance of {@link XmlWriter} that writes to an {@link OutputStream}. + *

+ * If a provider could not be found on the classpath this will use the default implementation, effectively the + * equivalent to {@link #createWriter(OutputStream, boolean) createWriter(xml, true)}. + * + * @param xml The XML represented as an {@link OutputStream}. + * @return A new instance of {@link XmlWriter}. + * @throws NullPointerException If {@code xml} is null. + */ + public static XmlWriter createWriter(OutputStream xml) { + return createWriter(xml, true); + } + + /** + * Creates an instance of {@link XmlWriter} that writes to an {@link OutputStream}. + * + * @param xml The XML represented as an {@link OutputStream}. + * @param useDefault Whether the default implementation should be used if one could not be found on the classpath. + * @return A new instance of {@link XmlWriter}. + * @throws NullPointerException If {@code xml} is null. + * @throws IllegalStateException If a provider could not be found on the classpath and {@code useDefault} is false. + */ + public static XmlWriter createWriter(OutputStream xml, boolean useDefault) { + if (defaultProvider == null) { + if (useDefault) { + return DefaultXmlWriter.toStream(xml); + } else { + throw new IllegalStateException(CANNOT_FIND_XML); + } + } else { + return defaultProvider.createWriter(xml); + } + } + + /** + * Creates an instance of {@link XmlWriter} that writes to an {@link Writer}. + *

+ * If a provider could not be found on the classpath this will use the default implementation, effectively the + * equivalent to {@link #createWriter(Writer, boolean) createWriter(xml, true)}. + * + * @param xml The XML represented as an {@link Writer}. + * @return A new instance of {@link XmlWriter}. + * @throws NullPointerException If {@code xml} is null. + */ + public static XmlWriter createWriter(Writer xml) { + return createWriter(xml, true); + } + + /** + * Creates an instance of {@link XmlWriter} that writes to an {@link Writer}. + * + * @param xml The XML represented as an {@link Writer}. + * @param useDefault Whether the default implementation should be used if one could not be found on the classpath. + * @return A new instance of {@link XmlWriter}. + * @throws NullPointerException If {@code xml} is null. + * @throws IllegalStateException If a provider could not be found on the classpath and {@code useDefault} is false. + */ + public static XmlWriter createWriter(Writer xml, boolean useDefault) { + if (defaultProvider == null) { + if (useDefault) { + return DefaultXmlWriter.toWriter(xml); + } else { + throw new IllegalStateException(CANNOT_FIND_XML); + } + } else { + return defaultProvider.createWriter(xml); + } + } +} diff --git a/sdk/core/azure-xml/src/main/java/com/azure/xml/DefaultXmlReader.java b/sdk/core/azure-xml/src/main/java/com/azure/xml/implementation/DefaultXmlReader.java similarity index 96% rename from sdk/core/azure-xml/src/main/java/com/azure/xml/DefaultXmlReader.java rename to sdk/core/azure-xml/src/main/java/com/azure/xml/implementation/DefaultXmlReader.java index d6d136b0f9cf6..8109472ef22ec 100644 --- a/sdk/core/azure-xml/src/main/java/com/azure/xml/DefaultXmlReader.java +++ b/sdk/core/azure-xml/src/main/java/com/azure/xml/implementation/DefaultXmlReader.java @@ -1,7 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.xml; +package com.azure.xml.implementation; + +import com.azure.xml.XmlReader; +import com.azure.xml.XmlToken; +import com.azure.xml.XmlWriter; import javax.xml.namespace.QName; import javax.xml.stream.XMLInputFactory; @@ -37,7 +41,7 @@ public final class DefaultXmlReader extends XmlReader { * @return A new {@link XmlReader} instance. */ public static XmlReader fromBytes(byte[] xml) { - return fromInputStream(new ByteArrayInputStream(xml)); + return fromStream(new ByteArrayInputStream(xml)); } /** @@ -57,7 +61,7 @@ public static XmlReader fromString(String xml) { * @return A new {@link XmlReader} instance. * @throws RuntimeException If an {@link XmlReader} cannot be instantiated. */ - public static XmlReader fromInputStream(InputStream xml) { + public static XmlReader fromStream(InputStream xml) { try { return new DefaultXmlReader(XML_INPUT_FACTORY.createXMLStreamReader(xml)); } catch (XMLStreamException e) { diff --git a/sdk/core/azure-xml/src/main/java/com/azure/xml/DefaultXmlWriter.java b/sdk/core/azure-xml/src/main/java/com/azure/xml/implementation/DefaultXmlWriter.java similarity index 86% rename from sdk/core/azure-xml/src/main/java/com/azure/xml/DefaultXmlWriter.java rename to sdk/core/azure-xml/src/main/java/com/azure/xml/implementation/DefaultXmlWriter.java index 019eaef65f670..662bd523d5fd4 100644 --- a/sdk/core/azure-xml/src/main/java/com/azure/xml/DefaultXmlWriter.java +++ b/sdk/core/azure-xml/src/main/java/com/azure/xml/implementation/DefaultXmlWriter.java @@ -1,7 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.xml; +package com.azure.xml.implementation; + +import com.azure.xml.XmlWriter; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; @@ -9,6 +11,7 @@ import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; +import java.io.Writer; import java.nio.charset.StandardCharsets; import java.util.Objects; @@ -29,7 +32,7 @@ public final class DefaultXmlWriter extends XmlWriter { * @return A new instance of {@link XmlWriter}. * @throws RuntimeException If an {@link XmlWriter} cannot be instantiated. */ - public static XmlWriter toOutputStream(OutputStream outputStream) { + public static XmlWriter toStream(OutputStream outputStream) { try { return new DefaultXmlWriter(XML_OUTPUT_FACTORY.createXMLStreamWriter( new OutputStreamWriter(outputStream, StandardCharsets.UTF_8))); @@ -38,6 +41,21 @@ public static XmlWriter toOutputStream(OutputStream outputStream) { } } + /** + * Creates an instance of {@link XmlWriter} that writes to the provided {@link Writer}. + * + * @param writer The {@link Writer} where content will be written. + * @return A new instance of {@link XmlWriter}. + * @throws RuntimeException If an {@link XmlWriter} cannot be instantiated. + */ + public static XmlWriter toWriter(Writer writer) { + try { + return new DefaultXmlWriter(XML_OUTPUT_FACTORY.createXMLStreamWriter(writer)); + } catch (XMLStreamException ex) { + throw new RuntimeException(ex); + } + } + private DefaultXmlWriter(XMLStreamWriter writer) { this.writer = writer; } diff --git a/sdk/core/azure-xml/src/main/java/module-info.java b/sdk/core/azure-xml/src/main/java/module-info.java index 9336476b78c5f..1a38d62f075d5 100644 --- a/sdk/core/azure-xml/src/main/java/module-info.java +++ b/sdk/core/azure-xml/src/main/java/module-info.java @@ -5,4 +5,7 @@ requires java.xml; exports com.azure.xml; + exports com.azure.xml.implementation; + + uses com.azure.xml.XmlProvider; } diff --git a/sdk/core/azure-xml/src/test/java/com/azure/xml/DefaultXmlReaderContractTests.java b/sdk/core/azure-xml/src/test/java/com/azure/xml/DefaultXmlReaderContractTests.java index 1525610f9ef0a..0fe58723e5a22 100644 --- a/sdk/core/azure-xml/src/test/java/com/azure/xml/DefaultXmlReaderContractTests.java +++ b/sdk/core/azure-xml/src/test/java/com/azure/xml/DefaultXmlReaderContractTests.java @@ -4,6 +4,7 @@ package com.azure.xml; import com.azure.xml.contract.XmlReaderContractTests; +import com.azure.xml.implementation.DefaultXmlReader; /** * Tests {@link DefaultXmlReader} against the contract required by {@link XmlReader}. diff --git a/sdk/core/azure-xml/src/test/java/com/azure/xml/DefaultXmlWriterContractTests.java b/sdk/core/azure-xml/src/test/java/com/azure/xml/DefaultXmlWriterContractTests.java index 1ce7ca0098715..1090b77641ff2 100644 --- a/sdk/core/azure-xml/src/test/java/com/azure/xml/DefaultXmlWriterContractTests.java +++ b/sdk/core/azure-xml/src/test/java/com/azure/xml/DefaultXmlWriterContractTests.java @@ -4,6 +4,7 @@ package com.azure.xml; import com.azure.xml.contract.XmlWriterContractTests; +import com.azure.xml.implementation.DefaultXmlWriter; import org.junit.jupiter.api.BeforeEach; import java.io.ByteArrayOutputStream; @@ -20,7 +21,7 @@ public final class DefaultXmlWriterContractTests extends XmlWriterContractTests @BeforeEach public void beforeEach() { this.outputStream = new ByteArrayOutputStream(); - this.writer = DefaultXmlWriter.toOutputStream(outputStream); + this.writer = DefaultXmlWriter.toStream(outputStream); } @Override diff --git a/sdk/core/azure-xml/src/test/java/com/azure/xml/PlaygroundTests.java b/sdk/core/azure-xml/src/test/java/com/azure/xml/PlaygroundTests.java index 3ed25abc3ff09..d4afc07f0ce38 100644 --- a/sdk/core/azure-xml/src/test/java/com/azure/xml/PlaygroundTests.java +++ b/sdk/core/azure-xml/src/test/java/com/azure/xml/PlaygroundTests.java @@ -3,6 +3,8 @@ package com.azure.xml; +import com.azure.xml.implementation.DefaultXmlReader; +import com.azure.xml.implementation.DefaultXmlWriter; import org.junit.jupiter.api.Test; import java.io.ByteArrayOutputStream; @@ -63,7 +65,7 @@ public void toXmlSimple() throws IOException { SignedIdentifiersWrapper wrapper = new SignedIdentifiersWrapper(Collections.singletonList(signedIdentifier)); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - try (XmlWriter xmlWriter = DefaultXmlWriter.toOutputStream(byteArrayOutputStream)) { + try (XmlWriter xmlWriter = DefaultXmlWriter.toStream(byteArrayOutputStream)) { xmlWriter.writeStartDocument(); wrapper.toXml(xmlWriter); } @@ -137,7 +139,7 @@ public void toXmlComplex() throws IOException { .setContent(namespacePropertiesEntryContent); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - try (XmlWriter xmlWriter = DefaultXmlWriter.toOutputStream(byteArrayOutputStream)) { + try (XmlWriter xmlWriter = DefaultXmlWriter.toStream(byteArrayOutputStream)) { xmlWriter.writeStartDocument(); namespacePropertiesEntry.toXml(xmlWriter); } diff --git a/sdk/core/azure-xml/src/test/java/com/azure/xml/storage/DeserializeListBlobsTests.java b/sdk/core/azure-xml/src/test/java/com/azure/xml/storage/DeserializeListBlobsTests.java index 5307ad073c3bf..ce07e4356be3b 100644 --- a/sdk/core/azure-xml/src/test/java/com/azure/xml/storage/DeserializeListBlobsTests.java +++ b/sdk/core/azure-xml/src/test/java/com/azure/xml/storage/DeserializeListBlobsTests.java @@ -3,7 +3,7 @@ package com.azure.xml.storage; -import com.azure.xml.DefaultXmlReader; +import com.azure.xml.implementation.DefaultXmlReader; import org.junit.jupiter.api.Test; import java.util.ArrayList; diff --git a/sdk/cosmos/azure-cosmos/CHANGELOG.md b/sdk/cosmos/azure-cosmos/CHANGELOG.md index 3030781b3dbbc..fbc3f8933cde4 100644 --- a/sdk/cosmos/azure-cosmos/CHANGELOG.md +++ b/sdk/cosmos/azure-cosmos/CHANGELOG.md @@ -11,6 +11,8 @@ #### Other Changes * Added system property to turn on replica validation - See [PR 29767](https://github.com/Azure/azure-sdk-for-java/pull/29767) * Added improvement to avoid retry on same replica that previously failed with 410, 408 and >= 500 status codes - See [PR 29767](https://github.com/Azure/azure-sdk-for-java/pull/29767) +* Improvement when `connectionEndpointRediscoveryEnabled` is enabled - See [PR 30281](https://github.com/Azure/azure-sdk-for-java/pull/30281) +* Added replica validation for Unknown status if `openConnectionsAndInitCaches` is used and replica validation is enabled - See [PR 30277](https://github.com/Azure/azure-sdk-for-java/pull/30277) ### 4.35.1 (2022-08-29) #### Other Changes diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/CosmosSchedulers.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/CosmosSchedulers.java index aa79b180ef0d0..e8016e1da4421 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/CosmosSchedulers.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/CosmosSchedulers.java @@ -11,6 +11,7 @@ public class CosmosSchedulers { private final static String TRANSPORT_RESPONSE_BOUNDED_ELASTIC_THREAD_NAME = "transport-response-bounded-elastic"; private final static String BULK_EXECUTOR_BOUNDED_ELASTIC_THREAD_NAME = "bulk-executor-bounded-elastic"; private final static String OPEN_CONNECTIONS_BOUNDED_ELASTIC_THREAD_NAME = "open-connections-bounded-elastic"; + private final static String ASYNC_CACHE_BACKGROUND_REFRESH_THREAD_NAME = "async-cache-background-refresh-bounded-elastic"; private final static int TTL_FOR_SCHEDULER_WORKER_IN_SECONDS = 60; // same as BoundedElasticScheduler.DEFAULT_TTL_SECONDS // Using a custom parallel scheduler to be able to schedule retries etc. @@ -47,4 +48,13 @@ public class CosmosSchedulers { TTL_FOR_SCHEDULER_WORKER_IN_SECONDS, true ); + + // Custom bounded elastic scheduler for async cache background refresh task + public final static Scheduler ASYNC_CACHE_BACKGROUND_REFRESH_BOUNDED_ELASTIC = Schedulers.newBoundedElastic( + Schedulers.DEFAULT_BOUNDED_ELASTIC_SIZE, + Schedulers.DEFAULT_BOUNDED_ELASTIC_QUEUESIZE, + ASYNC_CACHE_BACKGROUND_REFRESH_THREAD_NAME, + TTL_FOR_SCHEDULER_WORKER_IN_SECONDS, + true + ); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/DiagnosticsClientContext.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/DiagnosticsClientContext.java index ec6cb9f419c6c..485795c9fb6ac 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/DiagnosticsClientContext.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/DiagnosticsClientContext.java @@ -18,6 +18,7 @@ import java.io.IOException; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -53,6 +54,15 @@ public void serialize(DiagnosticsClientConfig clientConfig, JsonGenerator genera generator.writeStringField("machineId", ClientTelemetry.getMachineId(clientConfig)); generator.writeStringField("connectionMode", clientConfig.getConnectionMode().toString()); generator.writeNumberField("numberOfClients", clientConfig.getActiveClientsCount()); + generator.writeObjectFieldStart("clientEndpoints"); + for (Map.Entry entry: clientConfig.clientMap.entrySet()) { + try { + generator.writeNumberField(entry.getKey(), entry.getValue()); + } catch (Exception e) { + logger.debug("unexpected failure", e); + } + } + generator.writeEndObject(); generator.writeObjectFieldStart("connCfg"); try { generator.writeStringField("rntbd", clientConfig.rntbdConfig()); @@ -75,6 +85,7 @@ class DiagnosticsClientConfig { private AtomicInteger activeClientsCnt; private int clientId; + private Map clientMap; private ConsistencyLevel consistencyLevel; private boolean connectionSharingAcrossClientsEnabled; @@ -90,16 +101,24 @@ class DiagnosticsClientConfig { private String machineId; private boolean replicaValidationEnabled = Configs.isReplicaAddressValidationEnabled(); - public void withMachineId(String machineId) { + public DiagnosticsClientConfig withMachineId(String machineId) { this.machineId = machineId; + return this; } - public void withActiveClientCounter(AtomicInteger activeClientsCnt) { + public DiagnosticsClientConfig withActiveClientCounter(AtomicInteger activeClientsCnt) { this.activeClientsCnt = activeClientsCnt; + return this; } - public void withClientId(int clientId) { + public DiagnosticsClientConfig withClientId(int clientId) { this.clientId = clientId; + return this; + } + + public DiagnosticsClientConfig withClientMap(Map clientMap) { + this.clientMap = clientMap; + return this; } public DiagnosticsClientConfig withEndpointDiscoveryEnabled(boolean endpointDiscoveryEnabled) { diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentClientImpl.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentClientImpl.java index c38a9a6e2ec43..a1eb9f38447ac 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentClientImpl.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/RxDocumentClientImpl.java @@ -110,6 +110,7 @@ public class RxDocumentClientImpl implements AsyncDocumentClient, IAuthorization DiagnosticsClientContext { private static final String tempMachineId = "uuid:" + UUID.randomUUID(); private static final AtomicInteger activeClientsCnt = new AtomicInteger(0); + private static final Map clientMap = new ConcurrentHashMap<>(); private static final AtomicInteger clientIdGenerator = new AtomicInteger(0); private static final Range RANGE_INCLUDING_ALL_PARTITION_KEY_RANGES = new Range<>( PartitionKeyInternalHelper.MinimumInclusiveEffectivePartitionKey, @@ -332,9 +333,11 @@ private RxDocumentClientImpl(URI serviceEndpoint, activeClientsCnt.incrementAndGet(); this.clientId = clientIdGenerator.incrementAndGet(); + clientMap.put(serviceEndpoint.toString(), clientMap.getOrDefault(serviceEndpoint.toString(), 0) + 1); this.diagnosticsClientConfig = new DiagnosticsClientConfig(); this.diagnosticsClientConfig.withClientId(this.clientId); this.diagnosticsClientConfig.withActiveClientCounter(activeClientsCnt); + this.diagnosticsClientConfig.withClientMap(clientMap); this.diagnosticsClientConfig.withConnectionSharingAcrossClientsEnabled(connectionSharingAcrossClientsEnabled); this.diagnosticsClientConfig.withConsistency(consistencyLevel); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/caches/AsyncCacheNonBlocking.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/caches/AsyncCacheNonBlocking.java index 18304146a9302..5b86a8194fb5f 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/caches/AsyncCacheNonBlocking.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/caches/AsyncCacheNonBlocking.java @@ -3,6 +3,7 @@ package com.azure.cosmos.implementation.caches; import com.azure.cosmos.CosmosException; +import com.azure.cosmos.implementation.CosmosSchedulers; import com.azure.cosmos.implementation.Exceptions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -81,26 +82,26 @@ public Mono getAsync( return Mono.just(value); } - Mono refreshMono = initialLazyValue.createAndWaitForBackgroundRefreshTaskAsync(key, singleValueInitFunc); + Mono refreshMono = initialLazyValue.getOrCreateBackgroundRefreshTaskAsync(singleValueInitFunc); return refreshMono.onErrorResume( (exception) -> { - logger.debug("refresh cache [{}] resulted in error", key, exception); - // In some scenarios when a background failure occurs like a 404 the initial cache value should be removed. if (exception instanceof CosmosException && removeNotFoundFromCacheException((CosmosException) exception)) { if (initialLazyValue.shouldRemoveFromCache()) { this.remove(key); } } + + logger.debug("refresh cache [{}] resulted in error", key, exception); return Mono.error(exception); } ); }).onErrorResume((exception) -> { - logger.debug("cache[{}] resulted in error", key, exception); if (initialLazyValue.shouldRemoveFromCache()) { this.remove(key); } + logger.debug("cache[{}] resulted in error", key, exception); return Mono.error(exception); }); } @@ -115,16 +116,32 @@ public Mono getAsync( return result.getValueAsync().onErrorResume( (exception) -> { - logger.debug("cache[{}] resulted in error", key, exception); // Remove the failed task from the dictionary so future requests can send other calls. if (result.shouldRemoveFromCache()) { this.remove(key); } + logger.debug("cache[{}] resulted in error", key, exception); return Mono.error(exception); } ); } + public void refresh( + TKey key, + Function> singleValueInitFunc) { + + logger.debug("refreshing cache[{}]", key); + AsyncLazyWithRefresh initialLazyValue = values.get(key); + if (initialLazyValue != null) { + Mono backgroundRefreshTask = initialLazyValue.refresh(singleValueInitFunc); + if (backgroundRefreshTask != null) { + backgroundRefreshTask + .subscribeOn(CosmosSchedulers.ASYNC_CACHE_BACKGROUND_REFRESH_BOUNDED_ELASTIC) + .subscribe(); + } + } + } + public void set(TKey key, TValue value) { logger.debug("set cache[{}]={}", key, value); AsyncLazyWithRefresh updatedValue = new AsyncLazyWithRefresh(value); @@ -140,23 +157,21 @@ public void remove(TKey key) { * be used to update the value. This allows concurrent requests * to use the stale value while the refresh is occurring. */ - private class AsyncLazyWithRefresh { -// private final Function> createValueFunc; + private static class AsyncLazyWithRefresh { private final AtomicBoolean removeFromCache = new AtomicBoolean(false); private final AtomicReference> value; - private Mono refreshInProgress; - private final AtomicBoolean refreshInProgressCompleted = new AtomicBoolean(false); + private final AtomicReference> refreshInProgress; public AsyncLazyWithRefresh(TValue value) { this.value = new AtomicReference<>(); this.value.set(Mono.just(value)); - this.refreshInProgress = null; + this.refreshInProgress = new AtomicReference<>(null); } public AsyncLazyWithRefresh(Function> taskFactory) { this.value = new AtomicReference<>(); this.value.set(taskFactory.apply(null).cache()); - this.refreshInProgress = null; + this.refreshInProgress = new AtomicReference<>(null); } public Mono getValueAsync() { @@ -168,26 +183,59 @@ public Mono value() { return value.get(); } - @SuppressWarnings("unchecked") - public Mono createAndWaitForBackgroundRefreshTaskAsync(TKey key, Function> createRefreshFunction) { - Mono valueMono = this.value.get(); + public Mono getOrCreateBackgroundRefreshTaskAsync(Function> createRefreshFunction) { + Mono refreshInProgressSnapshot = this.refreshInProgress.updateAndGet(existingMono -> { + if (existingMono == null) { + logger.debug("Started a new background task"); + return this.createBackgroundRefreshTask(createRefreshFunction); + } else { + logger.debug("Background refresh task is already in progress"); + } + + return existingMono; + }); + return refreshInProgressSnapshot == null ? this.value.get() : refreshInProgressSnapshot; + } - return valueMono.flatMap(value -> { - if(this.refreshInProgressCompleted.compareAndSet(false, true)) { - this.refreshInProgress = createRefreshFunction.apply(value).cache(); - return this.refreshInProgress + private Mono createBackgroundRefreshTask(Function> createRefreshFunction) { + return this.value + .get() + .flatMap(createRefreshFunction) .flatMap(response -> { - this.value.set(Mono.just(response)); - this.refreshInProgressCompleted.set(false); - return this.value.get(); - }).doOnError(e -> this.refreshInProgressCompleted.set(false)); + this.refreshInProgress.set(null); + return this.value.updateAndGet(existingValue -> Mono.just(response)); + }) + .doOnError(throwable -> { + this.refreshInProgress.set(null); + logger.warn("Background refresh task failed", throwable); + }) + .cache(); + } - } - return this.refreshInProgress == null ? valueMono : refreshInProgress; - }); + /*** + * If there is no refresh in progress background task, then create a new one, else skip + * + * @param createRefreshFunction the createRefreshFunction + * @return if there is already a refreshInProgress task ongoing, then return Mono.empty, else return the newly created background refresh task + */ + public Mono refresh(Function> createRefreshFunction) { + if (this.refreshInProgress.compareAndSet(null, this.createBackgroundRefreshTask(createRefreshFunction))) { + logger.debug("Started a new background task"); + return this.refreshInProgress.get(); + } + + logger.debug("Background refresh task is already in progress, skip creating a new one"); + return null; } public boolean shouldRemoveFromCache() { + // Multiple threads could subscribe to the Mono, only one of them will be allowed to remove the Mono from the cache + // For example for the following scenario: + // Request1 -> getAsync -> Mono1 + // Request2 -> getAsync -> Mono1 + // Mono1 failed, and we decided to remove this entry from the cache. Request1 has removed the entry from the cache + // Request3 -> getAsync -> Mono2 + // without this check, request2 will end up removing the cache entry created by request3 return this.removeFromCache.compareAndSet(false, true); } } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/AddressResolver.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/AddressResolver.java index b7fd625564f7d..69ed8ba22337c 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/AddressResolver.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/AddressResolver.java @@ -9,9 +9,11 @@ import com.azure.cosmos.implementation.DocumentCollection; import com.azure.cosmos.implementation.HttpConstants; import com.azure.cosmos.implementation.ICollectionRoutingMapCache; +import com.azure.cosmos.implementation.IOpenConnectionsHandler; import com.azure.cosmos.implementation.InternalServerErrorException; import com.azure.cosmos.implementation.InvalidPartitionException; import com.azure.cosmos.implementation.NotFoundException; +import com.azure.cosmos.implementation.OpenConnectionResponse; import com.azure.cosmos.implementation.OperationType; import com.azure.cosmos.implementation.PartitionKeyRange; import com.azure.cosmos.implementation.PartitionKeyRangeGoneException; @@ -24,8 +26,6 @@ import com.azure.cosmos.implementation.apachecommons.lang.NotImplementedException; import com.azure.cosmos.implementation.apachecommons.lang.StringUtils; import com.azure.cosmos.implementation.caches.RxCollectionCache; -import com.azure.cosmos.implementation.IOpenConnectionsHandler; -import com.azure.cosmos.implementation.OpenConnectionResponse; import com.azure.cosmos.implementation.routing.CollectionRoutingMap; import com.azure.cosmos.implementation.routing.PartitionKeyInternal; import com.azure.cosmos.implementation.routing.PartitionKeyInternalHelper; @@ -35,7 +35,6 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import java.net.URI; import java.util.concurrent.Callable; import java.util.function.Function; @@ -87,11 +86,6 @@ public Mono resolveAsync( }); } - @Override - public int updateAddresses(URI serverKey) { - throw new NotImplementedException("updateAddresses() is not supported in AddressResolver"); - } - @Override public Flux openConnectionsAndInitCaches(String containerLink) { return Flux.empty(); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/GatewayAddressCache.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/GatewayAddressCache.java index 53d599b3d3a2e..0f0d24d6a9ee3 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/GatewayAddressCache.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/GatewayAddressCache.java @@ -63,10 +63,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; @@ -97,14 +95,12 @@ public class GatewayAddressCache implements IAddressCache { private volatile Pair masterPartitionAddressCache; private volatile Instant suboptimalMasterPartitionTimestamp; - private final ConcurrentHashMap> serverPartitionAddressToPkRangeIdMap; - private final boolean tcpConnectionEndpointRediscoveryEnabled; - private final ConcurrentHashMap lastForcedRefreshMap; private final GlobalEndpointManager globalEndpointManager; private IOpenConnectionsHandler openConnectionsHandler; private final ConnectionPolicy connectionPolicy; private final boolean replicaAddressValidationEnabled; + private final Set replicaValidationScopes; public GatewayAddressCache( DiagnosticsClientContext clientContext, @@ -114,7 +110,6 @@ public GatewayAddressCache( UserAgentContainer userAgent, HttpClient httpClient, long suboptimalPartitionForceRefreshIntervalInSeconds, - boolean tcpConnectionEndpointRediscoveryEnabled, ApiType apiType, GlobalEndpointManager globalEndpointManager, ConnectionPolicy connectionPolicy, @@ -156,13 +151,15 @@ public GatewayAddressCache( // Set requested API version header for version enforcement. defaultRequestHeaders.put(HttpConstants.HttpHeaders.VERSION, HttpConstants.Versions.CURRENT_VERSION); - this.serverPartitionAddressToPkRangeIdMap = new ConcurrentHashMap<>(); - this.tcpConnectionEndpointRediscoveryEnabled = tcpConnectionEndpointRediscoveryEnabled; this.lastForcedRefreshMap = new ConcurrentHashMap<>(); this.globalEndpointManager = globalEndpointManager; this.openConnectionsHandler = openConnectionsHandler; this.connectionPolicy = connectionPolicy; this.replicaAddressValidationEnabled = Configs.isReplicaAddressValidationEnabled(); + this.replicaValidationScopes = ConcurrentHashMap.newKeySet(); + if (this.replicaAddressValidationEnabled) { + this.replicaValidationScopes.add(Uri.HealthStatus.UnhealthyPending); + } } public GatewayAddressCache( @@ -172,7 +169,6 @@ public GatewayAddressCache( IAuthorizationTokenProvider tokenProvider, UserAgentContainer userAgent, HttpClient httpClient, - boolean tcpConnectionEndpointRediscoveryEnabled, ApiType apiType, GlobalEndpointManager globalEndpointManager, ConnectionPolicy connectionPolicy, @@ -184,42 +180,12 @@ public GatewayAddressCache( userAgent, httpClient, DefaultSuboptimalPartitionForceRefreshIntervalInSeconds, - tcpConnectionEndpointRediscoveryEnabled, apiType, globalEndpointManager, connectionPolicy, openConnectionsHandler); } - @Override - public int updateAddresses(final URI serverKey) { - - Objects.requireNonNull(serverKey, "expected non-null serverKey"); - - AtomicInteger updatedCacheEntryCount = new AtomicInteger(0); - - if (this.tcpConnectionEndpointRediscoveryEnabled) { - this.serverPartitionAddressToPkRangeIdMap.computeIfPresent(serverKey, (uri, partitionKeyRangeIdentitySet) -> { - - for (PartitionKeyRangeIdentity partitionKeyRangeIdentity : partitionKeyRangeIdentitySet) { - if (partitionKeyRangeIdentity.getPartitionKeyRangeId().equals(PartitionKeyRange.MASTER_PARTITION_KEY_RANGE_ID)) { - this.masterPartitionAddressCache = null; - } else { - this.serverPartitionAddressCache.remove(partitionKeyRangeIdentity); - } - - updatedCacheEntryCount.incrementAndGet(); - } - - return null; - }); - } else { - logger.warn("tcpConnectionEndpointRediscovery is not enabled, should not reach here."); - } - - return updatedCacheEntryCount.get(); - } - @Override public Mono> tryGetAddresses(RxDocumentServiceRequest request, PartitionKeyRangeIdentity partitionKeyRangeIdentity, @@ -289,8 +255,7 @@ public Mono> tryGetAddresses(RxDocumentS for (Uri failedEndpoints : request.requestContext.getFailedEndpoints()) { failedEndpoints.setUnhealthy(); } - return forceRefreshPartitionAddressesModified - || Arrays.stream(cachedAddresses).anyMatch(addressInformation -> addressInformation.getPhysicalUri().shouldRefreshHealthStatus()); + return forceRefreshPartitionAddressesModified; }) .map(Utils.ValueHolder::new); @@ -303,6 +268,20 @@ public Mono> tryGetAddresses(RxDocumentS this.suboptimalServerPartitionTimestamps.putIfAbsent(partitionKeyRangeIdentity, Instant.now()); } + // Refresh the cache if there was an address has been marked as unhealthy long enough and need to revalidate its status + // If you are curious about why we do not depend on 410 to force refresh the addresses, the reason being: + // When an address is marked as unhealthy, then the address enumerator will move it to the end of the list + // So it could happen that no request will use the unhealthy address for an extended period of time + // So the 410 -> forceRefresh workflow may not happen + if (Arrays + .stream(addressesValueHolder.v) + .anyMatch(addressInformation -> addressInformation.getPhysicalUri().shouldRefreshHealthStatus())) { + logger.info("refresh cache due to address uri in unhealthy status"); + this.serverPartitionAddressCache.refresh( + partitionKeyRangeIdentity, + cachedAddresses -> this.getAddressesForRangeId(request, partitionKeyRangeIdentity, true, cachedAddresses)); + } + return addressesValueHolder; }) .onErrorResume(ex -> { @@ -875,12 +854,24 @@ private void validateReplicaAddresses(AddressInformation[] addresses) { // By theory, when we reach here, the status of the address should be in one of the three status: Unknown, Connected, UnhealthyPending // using open connection to validate addresses in UnhealthyPending status // Could extend to also open connection for unknown in the future - List addressesNeedToValidation = - Arrays - .stream(addresses) - .map(address -> address.getPhysicalUri()) - .filter(addressUri -> addressUri.getHealthStatus() == Uri.HealthStatus.UnhealthyPending) - .collect(Collectors.toList()); + + List addressesNeedToValidation = new ArrayList<>(); + for (AddressInformation address : addresses) { + if (this.replicaValidationScopes.contains(address.getPhysicalUri().getHealthStatus())) { + switch (address.getPhysicalUri().getHealthStatus()) { + case UnhealthyPending: + // Generally, an unhealthyPending replica has more chances to fail the request compared to unknown replica + // so we want to put it at the head of the validation list + addressesNeedToValidation.add(0, address.getPhysicalUri()); + break; + case Unknown: + addressesNeedToValidation.add(address.getPhysicalUri()); + break; + default: + throw new IllegalStateException("Validate replica status is not support for status " + address.getPhysicalUri().getHealthStatus()); + } + } + } if (addressesNeedToValidation.size() > 0) { this.openConnectionsHandler @@ -905,26 +896,6 @@ private Pair toPartitionAddress .collect(Collectors.toList()) .toArray(new AddressInformation[addresses.size()]); - if (this.tcpConnectionEndpointRediscoveryEnabled) { - for (AddressInformation addressInfo : addressInfos) { - if (logger.isDebugEnabled()) { - logger.debug( - "Added address to serverPartitionAddressToPkRangeIdMap: ({\"partitionKeyRangeIdentity\":{},\"address\":{}})", - partitionKeyRangeIdentity, - addressInfo); - } - - this.serverPartitionAddressToPkRangeIdMap.compute(addressInfo.getServerKey(), (serverKey, partitionKeyRangeIdentitySet) -> { - if (partitionKeyRangeIdentitySet == null) { - partitionKeyRangeIdentitySet = ConcurrentHashMap.newKeySet(); - } - - partitionKeyRangeIdentitySet.add(partitionKeyRangeIdentity); - return partitionKeyRangeIdentitySet; - }); - } - } - return Pair.of(partitionKeyRangeIdentity, addressInfos); } @@ -946,6 +917,10 @@ public Flux openConnectionsAndInitCaches( JavaStreamUtils.toString(partitionKeyRangeIdentities, ",")); } + if (this.replicaAddressValidationEnabled) { + this.replicaValidationScopes.add(Uri.HealthStatus.Unknown); + } + List>> tasks = new ArrayList<>(); int batchSize = GatewayAddressCache.DefaultBatchSize; diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/GlobalAddressResolver.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/GlobalAddressResolver.java index 77eaf6c48188e..fd7302073f230 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/GlobalAddressResolver.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/GlobalAddressResolver.java @@ -31,9 +31,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkArgument; @@ -96,26 +94,6 @@ public GlobalAddressResolver( } } - @Override - public int updateAddresses(final URI serverKey) { - - Objects.requireNonNull(serverKey, "expected non-null serverKey"); - - AtomicInteger updatedCount = new AtomicInteger(0); - - if (this.tcpConnectionEndpointRediscoveryEnabled) { - for (EndpointCache endpointCache : this.addressCacheByEndpoint.values()) { - final GatewayAddressCache addressCache = endpointCache.addressCache; - - updatedCount.accumulateAndGet(addressCache.updateAddresses(serverKey), (oldValue, newValue) -> oldValue + newValue); - } - } else { - logger.warn("tcpConnectionEndpointRediscovery is not enabled, should not reach here."); - } - - return updatedCount.get(); - } - @Override public Flux openConnectionsAndInitCaches(String containerLink) { checkArgument(StringUtils.isNotEmpty(containerLink), "Argument 'containerLink' should not be null nor empty"); @@ -211,7 +189,6 @@ private EndpointCache getOrAddEndpoint(URI endpoint) { this.tokenProvider, this.userAgentContainer, this.httpClient, - this.tcpConnectionEndpointRediscoveryEnabled, this.apiType, this.endpointManager, this.connectionPolicy, diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/GoneAndRetryWithRetryPolicy.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/GoneAndRetryWithRetryPolicy.java index 1aae68b46dc43..c743ef28b0307 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/GoneAndRetryWithRetryPolicy.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/GoneAndRetryWithRetryPolicy.java @@ -46,8 +46,7 @@ public GoneAndRetryWithRetryPolicy(RxDocumentServiceRequest request, Integer wai waitTimeInSeconds, this.retryContext ); - this.retryWithRetryPolicy = new RetryWithRetryPolicy( - waitTimeInSeconds, this.retryContext); + this.retryWithRetryPolicy = new RetryWithRetryPolicy(waitTimeInSeconds, this.retryContext); this.start = Instant.now(); } diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/IAddressCache.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/IAddressCache.java index 8123db36fe31d..4a67cd86f4adf 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/IAddressCache.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/IAddressCache.java @@ -3,23 +3,14 @@ package com.azure.cosmos.implementation.directconnectivity; +import com.azure.cosmos.implementation.IOpenConnectionsHandler; import com.azure.cosmos.implementation.RxDocumentServiceRequest; import com.azure.cosmos.implementation.Utils; -import com.azure.cosmos.implementation.IOpenConnectionsHandler; import com.azure.cosmos.implementation.routing.PartitionKeyRangeIdentity; import reactor.core.publisher.Mono; -import java.net.URI; - public interface IAddressCache { - /** - * Update the physical address of the {@link PartitionKeyRangeIdentity partition key range identity} associated to the serverKey. - * - * - */ - int updateAddresses(URI serverKey); - /** * Resolves physical addresses by either PartitionKeyRangeIdentity. * diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/IAddressResolver.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/IAddressResolver.java index 0d70c26b60b3c..5fbcd28a139fe 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/IAddressResolver.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/IAddressResolver.java @@ -3,22 +3,18 @@ package com.azure.cosmos.implementation.directconnectivity; -import com.azure.cosmos.implementation.RxDocumentServiceRequest; import com.azure.cosmos.implementation.IOpenConnectionsHandler; import com.azure.cosmos.implementation.OpenConnectionResponse; +import com.azure.cosmos.implementation.RxDocumentServiceRequest; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import java.net.URI; - public interface IAddressResolver { Mono resolveAsync( RxDocumentServiceRequest request, boolean forceRefreshPartitionAddresses); - int updateAddresses(URI serverKey); - /*** * Warm up caches and open connections to all replicas of the container for the current read region. * diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/Uri.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/Uri.java index 86813b94abc75..02179a15454a6 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/Uri.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/Uri.java @@ -160,7 +160,7 @@ public HealthStatus getEffectiveHealthStatus() { public boolean shouldRefreshHealthStatus() { return this.healthStatus.get() == HealthStatus.Unhealthy - && Instant.now().compareTo(this.lastUnhealthyTimestamp.plusMillis(DEFAULT_NON_HEALTHY_RESET_TIME_IN_MILLISECONDS)) > 0; + && Instant.now().compareTo(this.lastUnhealthyTimestamp.plusMillis(DEFAULT_NON_HEALTHY_RESET_TIME_IN_MILLISECONDS)) >= 0; } public String getHealthStatusDiagnosticString() { @@ -195,10 +195,10 @@ public String toString() { *

*/ public enum HealthStatus { - Connected(0), - Unknown(1), - UnhealthyPending(2), - Unhealthy(3); + Connected(100), + Unknown(200), + UnhealthyPending(300), + Unhealthy(400); private int priority; HealthStatus(int priority) { diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdConnectionStateListener.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdConnectionStateListener.java index 105040b0d286a..448471667b46a 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdConnectionStateListener.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdConnectionStateListener.java @@ -3,13 +3,15 @@ package com.azure.cosmos.implementation.directconnectivity.rntbd; -import com.azure.cosmos.implementation.directconnectivity.IAddressResolver; +import com.azure.cosmos.implementation.directconnectivity.Uri; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.nio.channels.ClosedChannelException; import java.time.Instant; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkNotNull; @@ -18,24 +20,29 @@ public class RntbdConnectionStateListener { private static final Logger logger = LoggerFactory.getLogger(RntbdConnectionStateListener.class); - private final IAddressResolver addressResolver; private final RntbdEndpoint endpoint; private final RntbdConnectionStateListenerMetrics metrics; + private final Set addressUris; // endregion // region Constructors - public RntbdConnectionStateListener(final IAddressResolver addressResolver, final RntbdEndpoint endpoint) { - this.addressResolver = checkNotNull(addressResolver, "expected non-null addressResolver"); + public RntbdConnectionStateListener(final RntbdEndpoint endpoint) { this.endpoint = checkNotNull(endpoint, "expected non-null endpoint"); this.metrics = new RntbdConnectionStateListenerMetrics(); + this.addressUris = ConcurrentHashMap.newKeySet(); } // endregion // region Methods + public void onBeforeSendRequest(Uri addressUri) { + checkNotNull(addressUri, "Argument 'addressUri' should not be null"); + this.addressUris.add(addressUri); + } + public void onException(Throwable exception) { checkNotNull(exception, "expect non-null exception"); @@ -81,7 +88,12 @@ private int onConnectionEvent(final RntbdConnectionEvent event, final Throwable RntbdObjectMapper.toJson(exception)); } - return this.addressResolver.updateAddresses(this.endpoint.serverKey()); + for (Uri addressUri : this.addressUris) { + addressUri.setUnhealthy(); + } + + return addressUris.size(); + } else { if (logger.isDebugEnabled()) { logger.debug("Endpoint closed while onConnectionEvent: {}", this.endpoint); diff --git a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdServiceEndpoint.java b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdServiceEndpoint.java index 432dcfb7e531c..9b5def28f2e25 100644 --- a/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdServiceEndpoint.java +++ b/sdk/cosmos/azure-cosmos/src/main/java/com/azure/cosmos/implementation/directconnectivity/rntbd/RntbdServiceEndpoint.java @@ -123,8 +123,7 @@ private RntbdServiceEndpoint( this.maxConcurrentRequests = config.maxConcurrentRequestsPerEndpoint(); this.connectionStateListener = this.provider.addressResolver != null && config.isConnectionEndpointRediscoveryEnabled() - ? new RntbdConnectionStateListener(this.provider.addressResolver, this) - : null; + ? new RntbdConnectionStateListener(this) : null; this.channelPool = new RntbdClientChannelPool(this, bootstrap, config, clientTelemetry, this.connectionStateListener); this.clientTelemetry = clientTelemetry; @@ -270,6 +269,10 @@ public RntbdRequestRecord request(final RntbdRequestArgs args) { int concurrentRequestSnapshot = this.concurrentRequests.incrementAndGet(); + if (this.connectionStateListener != null) { + this.connectionStateListener.onBeforeSendRequest(args.physicalAddressUri()); + } + RntbdEndpointStatistics stat = endpointMetricsSnapshot(concurrentRequestSnapshot); if (concurrentRequestSnapshot > this.maxConcurrentRequests) { @@ -307,6 +310,10 @@ public OpenConnectionRntbdRequestRecord openConnection(Uri addressUri) { this.throwIfClosed(); + if (this.connectionStateListener != null) { + this.connectionStateListener.onBeforeSendRequest(addressUri); + } + OpenConnectionRntbdRequestRecord requestRecord = new OpenConnectionRntbdRequestRecord(addressUri); final Future openChannelFuture = this.channelPool.acquire(requestRecord); diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/CosmosDiagnosticsTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/CosmosDiagnosticsTest.java index 2753528f5eede..221d3e7c2e5e5 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/CosmosDiagnosticsTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/CosmosDiagnosticsTest.java @@ -383,6 +383,65 @@ public void requestSessionTokenDiagnostics() { } } + @Test(groups = {"simple"}) + public void databaseAccountToClients() { + CosmosClient testClient = null; + try { + testClient = new CosmosClientBuilder() + .endpoint(TestConfigurations.HOST) + .key(TestConfigurations.MASTER_KEY) + .contentResponseOnWriteEnabled(true) + .directMode() + .buildClient(); + CosmosContainer cosmosContainer = + testClient.getDatabase(cosmosAsyncContainer.getDatabase().getId()).getContainer(cosmosAsyncContainer.getId()); + InternalObjectNode internalObjectNode = getInternalObjectNode(); + CosmosItemResponse createResponse = cosmosContainer.createItem(internalObjectNode); + String diagnostics = createResponse.getDiagnostics().toString(); + + // assert diagnostics shows the correct format for tracking client instances + assertThat(diagnostics).contains(String.format("\"clientEndpoints\"" + + ":{\"%s\"", TestConfigurations.HOST)); + // track number of clients currently mapped to account + int clientsIndex = diagnostics.indexOf("\"clientEndpoints\":"); + // we do end at +120 to ensure we grab the bracket even if the account is very long or if + // we have hundreds of clients (triple digit ints) running at once in the pipelines + String[] substrings = diagnostics.substring(clientsIndex, clientsIndex + 120) + .split("}")[0].split(":"); + String intString = substrings[substrings.length-1]; + int intValue = Integer.parseInt(intString); + + + CosmosClient testClient2 = new CosmosClientBuilder() + .endpoint(TestConfigurations.HOST) + .key(TestConfigurations.MASTER_KEY) + .contentResponseOnWriteEnabled(true) + .directMode() + .buildClient(); + + internalObjectNode = getInternalObjectNode(); + createResponse = cosmosContainer.createItem(internalObjectNode); + diagnostics = createResponse.getDiagnostics().toString(); + // assert diagnostics shows the correct format for tracking client instances + assertThat(diagnostics).contains(String.format("\"clientEndpoints\"" + + ":{\"%s\"", TestConfigurations.HOST)); + // grab new value and assert one additional client is mapped to the same account used previously + clientsIndex = diagnostics.indexOf("\"clientEndpoints\":"); + substrings = diagnostics.substring(clientsIndex, clientsIndex + 120) + .split("}")[0].split(":"); + intString = substrings[substrings.length-1]; + assertThat(Integer.parseInt(intString)).isEqualTo(intValue+1); + + //close second client + testClient2.close(); + + } finally { + if (testClient != null) { + testClient.close(); + } + } + } + @Test(groups = {"simple"}, timeOut = TIMEOUT) public void queryPlanDiagnostics() throws JsonProcessingException { CosmosContainer cosmosContainer = directClient.getDatabase(cosmosAsyncContainer.getDatabase().getId()).getContainer(cosmosAsyncContainer.getId()); diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/ClientConfigDiagnosticsTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/ClientConfigDiagnosticsTest.java index 50f639b5973ec..65148bafcb8c9 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/ClientConfigDiagnosticsTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/ClientConfigDiagnosticsTest.java @@ -17,6 +17,7 @@ import java.io.StringWriter; import java.time.Duration; +import java.util.HashMap; import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; @@ -35,6 +36,7 @@ public void bareMinimum() throws Exception { diagnosticsClientConfig.withClientId(1); diagnosticsClientConfig.withConnectionMode(ConnectionMode.DIRECT); diagnosticsClientConfig.withActiveClientCounter(new AtomicInteger(2)); + diagnosticsClientConfig.withClientMap(new HashMap<>()); Mockito.doReturn(diagnosticsClientConfig).when(clientContext).getConfig(); @@ -67,6 +69,7 @@ public void rntbd() throws Exception { diagnosticsClientConfig.withActiveClientCounter(new AtomicInteger(2)); diagnosticsClientConfig.withRntbdOptions( new RntbdTransportClient.Options.Builder(ConnectionPolicy.getDefaultPolicy()).build().toDiagnosticsString()); diagnosticsClientConfig.withGatewayHttpClientConfig(new HttpClientConfig(new Configs()).toDiagnosticsString()); + diagnosticsClientConfig.withClientMap(new HashMap<>()); Mockito.doReturn(diagnosticsClientConfig).when(clientContext).getConfig(); @@ -101,6 +104,7 @@ public void gw() throws Exception { httpConfig.withMaxIdleConnectionTimeout(Duration.ofSeconds(17)); httpConfig.withNetworkRequestTimeout(Duration.ofSeconds(18)); diagnosticsClientConfig.withGatewayHttpClientConfig(httpConfig.toDiagnosticsString()); + diagnosticsClientConfig.withClientMap(new HashMap<>()); Mockito.doReturn(diagnosticsClientConfig).when(clientContext).getConfig(); @@ -139,6 +143,7 @@ public void full() throws Exception { diagnosticsClientConfig.withPreferredRegions(ImmutableList.of("west us 1", "west us 2")); diagnosticsClientConfig.withConnectionSharingAcrossClientsEnabled(true); diagnosticsClientConfig.withEndpointDiscoveryEnabled(true); + diagnosticsClientConfig.withClientMap(new HashMap<>()); Mockito.doReturn(diagnosticsClientConfig).when(clientContext).getConfig(); diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/caches/AsyncCacheNonBlockingTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/caches/AsyncCacheNonBlockingTest.java index c905b63dd3f51..ef246c9cd7b7a 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/caches/AsyncCacheNonBlockingTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/caches/AsyncCacheNonBlockingTest.java @@ -7,6 +7,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.time.Duration; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; @@ -15,7 +16,7 @@ import static org.assertj.core.api.Assertions.assertThat; public class AsyncCacheNonBlockingTest { - private static final int TIMEOUT = 2000; + private static final int TIMEOUT = 20000; @Test(groups = {"unit"}, timeOut = TIMEOUT) public void getAsync() { @@ -80,6 +81,40 @@ public void getAsync() { assertThat(numberOfCacheRefreshes.get()).isEqualTo(20); // verify that we still have the old value in the cache assertThat(cache.getAsync(2, value -> refreshFunc2.apply(2), forceRefresh -> false).block()).isEqualTo(5); + } + + @Test(groups = {"unit"}, timeOut = TIMEOUT) + public void refreshAsync() throws InterruptedException { + AtomicInteger numberOfCacheRefreshes = new AtomicInteger(0); + final Function> refreshFunc = key -> { + return Mono.just(key * 2) + .doOnNext(t -> { + numberOfCacheRefreshes.incrementAndGet(); + }); + }; + + AsyncCacheNonBlocking cache = new AsyncCacheNonBlocking<>(); + // populate the cache + int cacheKey = 1; + cache.getAsync(cacheKey, value -> refreshFunc.apply(cacheKey), forceRefresh -> false).block(); + assertThat(numberOfCacheRefreshes.get()).isEqualTo(1); + + // refresh the cache, since there is no refresh in progress, it will start a new one + Function> refreshFuncWithDelay = key -> { + return Mono.just(key * 2) + .doOnNext(t -> numberOfCacheRefreshes.incrementAndGet()) + .delayElement(Duration.ofMinutes(5)); + }; + + cache.refresh(cacheKey, refreshFuncWithDelay); + //since the refresh happens asynchronously, so wait for sometime + Thread.sleep(100); + assertThat(numberOfCacheRefreshes.get()).isEqualTo(2); + // start another refresh, since there is a refresh in progress, so it will not start a new one + cache.refresh(cacheKey, refreshFunc); + //since the refresh happens asynchronously, so wait for sometime + Thread.sleep(100); + assertThat(numberOfCacheRefreshes.get()).isEqualTo(2); } } diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/directconnectivity/ConnectionStateListenerTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/directconnectivity/ConnectionStateListenerTest.java index b9bddc9e8b819..b8ee6a722b4cb 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/directconnectivity/ConnectionStateListenerTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/directconnectivity/ConnectionStateListenerTest.java @@ -11,10 +11,10 @@ import com.azure.cosmos.implementation.ResourceType; import com.azure.cosmos.implementation.RxDocumentServiceRequest; import com.azure.cosmos.implementation.UserAgentContainer; -import com.azure.cosmos.implementation.directconnectivity.TcpServerMock.TcpServerFactory; -import com.azure.cosmos.implementation.directconnectivity.TcpServerMock.TcpServer; import com.azure.cosmos.implementation.directconnectivity.TcpServerMock.RequestResponseType; import com.azure.cosmos.implementation.directconnectivity.TcpServerMock.SslContextUtils; +import com.azure.cosmos.implementation.directconnectivity.TcpServerMock.TcpServer; +import com.azure.cosmos.implementation.directconnectivity.TcpServerMock.TcpServerFactory; import com.azure.cosmos.implementation.routing.PartitionKeyRangeIdentity; import io.netty.handler.ssl.SslContext; import org.mockito.Mockito; @@ -30,6 +30,7 @@ import java.util.concurrent.atomic.AtomicInteger; import static com.azure.cosmos.implementation.TestUtils.mockDiagnosticsClientContext; +import static org.assertj.core.api.Assertions.assertThat; public class ConnectionStateListenerTest { private static final Logger logger = LoggerFactory.getLogger(ConnectionStateListenerTest.class); @@ -42,13 +43,13 @@ public class ConnectionStateListenerTest { @DataProvider(name = "connectionStateListenerConfigProvider") public Object[][] connectionStateListenerConfigProvider() { return new Object[][]{ - // isTcpConnectionEndpointRediscoveryEnabled, serverResponseType, updateAddresses() called times on request, updateAddresses() called times when server shutdown - {true, RequestResponseType.CHANNEL_FIN, 1, 0}, - {false, RequestResponseType.CHANNEL_FIN, 0, 0}, - {true, RequestResponseType.CHANNEL_RST, 0, 0}, - {false, RequestResponseType.CHANNEL_RST, 0, 0}, - {true, RequestResponseType.NONE, 0, 1}, // the request will be timed out, but the connection will be active. When tcp server shutdown, the connection will be closed gracefully - {false, RequestResponseType.NONE, 0, 0}, + // isTcpConnectionEndpointRediscoveryEnabled, serverResponseType, replicaStatusUpdated, replicaStatusUpdated when server shutdown + {true, RequestResponseType.CHANNEL_FIN, true, false}, + {false, RequestResponseType.CHANNEL_FIN, false, false}, + {true, RequestResponseType.CHANNEL_RST, false, false}, + {false, RequestResponseType.CHANNEL_RST, false, false}, + {true, RequestResponseType.NONE, false, true}, // the request will be timed out, but the connection will be active. When tcp server shutdown, the connection will be closed gracefully + {false, RequestResponseType.NONE, false, false}, }; } @@ -56,8 +57,8 @@ public Object[][] connectionStateListenerConfigProvider() { public void connectionStateListener_OnConnectionEvent( boolean isTcpConnectionEndpointRediscoveryEnabled, RequestResponseType responseType, - int timesOnRequest, - int timesOnServerShutdown) throws ExecutionException, InterruptedException { + boolean markUnhealthy, + boolean markUnhealthyWhenServerShutdown) throws ExecutionException, InterruptedException { // using a random generated server port int serverPort = port + randomPort.getAndIncrement(); @@ -96,12 +97,21 @@ public void connectionStateListener_OnConnectionEvent( logger.info("expected failed request with reason {}", e); } - Mockito.verify(addressResolver, Mockito.times(timesOnRequest)).updateAddresses(Mockito.any()); + if (markUnhealthy) { + assertThat(targetUri.getHealthStatus()).isEqualTo(Uri.HealthStatus.Unhealthy); + TcpServerFactory.shutdownRntbdServer(server); + assertThat(targetUri.getHealthStatus()).isEqualTo(Uri.HealthStatus.Unhealthy); - Mockito.clearInvocations(addressResolver); + } else { + assertThat(targetUri.getHealthStatus()).isEqualTo(Uri.HealthStatus.Connected); - TcpServerFactory.shutdownRntbdServer(server); - Mockito.verify(addressResolver, Mockito.times(timesOnServerShutdown)).updateAddresses(Mockito.any()); + TcpServerFactory.shutdownRntbdServer(server); + if (markUnhealthyWhenServerShutdown) { + assertThat(targetUri.getHealthStatus()).isEqualTo(Uri.HealthStatus.Unhealthy); + } else { + assertThat(targetUri.getHealthStatus()).isEqualTo(Uri.HealthStatus.Connected); + } + } } private Document getDocumentDefinition() { diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/directconnectivity/GatewayAddressCacheTest.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/directconnectivity/GatewayAddressCacheTest.java index 1bab56dc0df5d..a6f6f6ddae92a 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/directconnectivity/GatewayAddressCacheTest.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/directconnectivity/GatewayAddressCacheTest.java @@ -55,6 +55,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; +import java.util.Set; import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -64,6 +65,7 @@ import static com.azure.cosmos.implementation.TestUtils.mockDiagnosticsClientContext; import static com.azure.cosmos.implementation.directconnectivity.Uri.HealthStatus.Connected; import static com.azure.cosmos.implementation.directconnectivity.Uri.HealthStatus.UnhealthyPending; +import static com.azure.cosmos.implementation.directconnectivity.Uri.HealthStatus.Unknown; import static org.assertj.core.api.Assertions.assertThat; public class GatewayAddressCacheTest extends TestSuiteBase { @@ -105,9 +107,11 @@ public Object[][] protocolProvider() { @DataProvider(name = "replicaValidationArgsProvider") public Object[][] replicaValidationArgsProvider() { return new Object[][]{ - // replica validation is enabled - { false }, - { true }, + // replicaValidationIsEnabled, openConnectionsAndInitCaches + { false, false }, + { false, true }, + { true, false }, + { true, true }, }; } @@ -126,7 +130,6 @@ public void getServerAddressesViaGateway(List partitionKeyRangeIds, authorizationTokenProvider, null, getHttpClient(configs), - false, null, null, ConnectionPolicy.getDefaultPolicy(), @@ -164,7 +167,6 @@ public void getMasterAddressesViaGatewayAsync(Protocol protocol) throws Exceptio authorizationTokenProvider, null, getHttpClient(configs), - false, null, null, ConnectionPolicy.getDefaultPolicy(), @@ -213,7 +215,6 @@ public void tryGetAddresses_ForDataPartitions(String partitionKeyRangeId, String authorizationTokenProvider, null, getHttpClient(configs), - false, null, null, ConnectionPolicy.getDefaultPolicy(), @@ -240,63 +241,6 @@ public void tryGetAddresses_ForDataPartitions(String partitionKeyRangeId, String assertSameAs(addressInfosFromCache, expectedAddresses); } - @Test(groups = { "direct" }, dataProvider = "targetPartitionsKeyRangeAndCollectionLinkParams", timeOut = TIMEOUT) - public void tryGetAddress_OnConnectionEvent_Refresh(String partitionKeyRangeId, String collectionLink, Protocol protocol) throws Exception { - - Configs configs = ConfigsBuilder.instance().withProtocol(protocol).build(); - URI serviceEndpoint = new URI(TestConfigurations.HOST); - IAuthorizationTokenProvider authorizationTokenProvider = (RxDocumentClientImpl) client; - HttpClientUnderTestWrapper httpClientWrapper = getHttpClientUnderTestWrapper(configs); - - GatewayAddressCache cache = new GatewayAddressCache( - mockDiagnosticsClientContext(), - serviceEndpoint, - protocol, - authorizationTokenProvider, - null, - httpClientWrapper.getSpyHttpClient(), - true, - null, - null, - ConnectionPolicy.getDefaultPolicy(), - null); - - RxDocumentServiceRequest req = - RxDocumentServiceRequest.create(mockDiagnosticsClientContext(), OperationType.Create, ResourceType.Document, - collectionLink, - new Database(), new HashMap<>()); - - PartitionKeyRangeIdentity partitionKeyRangeIdentity = new PartitionKeyRangeIdentity(createdCollection.getResourceId(), partitionKeyRangeId); - boolean forceRefreshPartitionAddresses = false; - - Mono> addressesInfosFromCacheObs = - cache.tryGetAddresses(req, partitionKeyRangeIdentity, forceRefreshPartitionAddresses); - - ArrayList addressInfosFromCache = - Lists.newArrayList(getSuccessResult(addressesInfosFromCacheObs, TIMEOUT).v); - - assertThat(httpClientWrapper.capturedRequests) - .describedAs("getAddress will read addresses from gateway") - .asList().hasSize(1); - - httpClientWrapper.capturedRequests.clear(); - - // for the second request with the same partitionkeyRangeIdentity, the address result should be fetched from the cache - getSuccessResult(cache.tryGetAddresses(req, partitionKeyRangeIdentity, forceRefreshPartitionAddresses), TIMEOUT); - assertThat(httpClientWrapper.capturedRequests) - .describedAs("getAddress should read from cache") - .asList().hasSize(0); - - httpClientWrapper.capturedRequests.clear(); - - // Now emulate onConnectionEvent happened, and the address should be removed from the cache - cache.updateAddresses(addressInfosFromCache.get(0).getServerKey()); - getSuccessResult(cache.tryGetAddresses(req, partitionKeyRangeIdentity, forceRefreshPartitionAddresses), TIMEOUT); - assertThat(httpClientWrapper.capturedRequests) - .describedAs("getAddress will read addresses from gateway after onConnectionEvent") - .asList().hasSize(1); - } - @DataProvider(name = "openAsyncTargetAndTargetPartitionsKeyRangeAndCollectionLinkParams") public Object[][] openAsyncTargetAndPartitionsKeyRangeTargetAndCollectionLinkParams() { return new Object[][] { @@ -329,7 +273,6 @@ public void tryGetAddresses_ForDataPartitions_AddressCachedByOpenAsync_NoHttpReq authorizationTokenProvider, null, httpClientWrapper.getSpyHttpClient(), - false, null, null, ConnectionPolicy.getDefaultPolicy(), @@ -394,7 +337,6 @@ public void tryGetAddresses_ForDataPartitions_ForceRefresh( authorizationTokenProvider, null, httpClientWrapper.getSpyHttpClient(), - false, null, null, ConnectionPolicy.getDefaultPolicy(), @@ -462,7 +404,6 @@ public void tryGetAddresses_ForDataPartitions_Suboptimal_Refresh( null, httpClientWrapper.getSpyHttpClient(), suboptimalRefreshTime, - false, null, null, ConnectionPolicy.getDefaultPolicy(), @@ -576,7 +517,6 @@ public void tryGetAddresses_ForMasterPartition(Protocol protocol) throws Excepti authorizationTokenProvider, null, getHttpClient(configs), - false, null, null, ConnectionPolicy.getDefaultPolicy(), @@ -628,7 +568,6 @@ public void tryGetAddresses_ForMasterPartition_MasterPartitionAddressAlreadyCach null, clientWrapper.getSpyHttpClient(), suboptimalPartitionForceRefreshIntervalInSeconds, - false, null, null, ConnectionPolicy.getDefaultPolicy(), @@ -679,7 +618,6 @@ public void tryGetAddresses_ForMasterPartition_ForceRefresh() throws Exception { authorizationTokenProvider, null, clientWrapper.getSpyHttpClient(), - false, null, null, ConnectionPolicy.getDefaultPolicy(), @@ -737,7 +675,6 @@ public void tryGetAddresses_SuboptimalMasterPartition_NotStaleEnough_NoRefresh() null, clientWrapper.getSpyHttpClient(), refreshPeriodInSeconds, - false, ApiType.SQL, null, ConnectionPolicy.getDefaultPolicy(), @@ -835,7 +772,6 @@ public void tryGetAddresses_SuboptimalMasterPartition_Stale_DoRefresh() throws E null, clientWrapper.getSpyHttpClient(), refreshPeriodInSeconds, - false, null, null, ConnectionPolicy.getDefaultPolicy(), @@ -928,7 +864,7 @@ public Mono> answer(InvocationOnMock invocationOnMock) throws Thro @SuppressWarnings("unchecked") @Test(groups = { "direct" }, dataProvider = "replicaValidationArgsProvider", timeOut = TIMEOUT) - public void tryGetAddress_replicaValidationTests(boolean replicaValidationEnabled) throws Exception { + public void tryGetAddress_replicaValidationTests(boolean replicaValidationEnabled, boolean openConnectionAndInitCaches) throws Exception { Configs configs = ConfigsBuilder.instance().withProtocol(Protocol.TCP).build(); URI serviceEndpoint = new URI(TestConfigurations.HOST); IAuthorizationTokenProvider authorizationTokenProvider = (RxDocumentClientImpl) client; @@ -951,7 +887,6 @@ public void tryGetAddress_replicaValidationTests(boolean replicaValidationEnable authorizationTokenProvider, null, httpClientWrapper.getSpyHttpClient(), - true, null, null, ConnectionPolicy.getDefaultPolicy(), @@ -966,8 +901,15 @@ public void tryGetAddress_replicaValidationTests(boolean replicaValidationEnable new Database(), new HashMap<>()); + if (openConnectionAndInitCaches) { + List pkriList = Arrays.asList(new PartitionKeyRangeIdentity("0")); + cache.openConnectionsAndInitCaches(createdCollection, pkriList).blockLast(); + Mockito.clearInvocations(openConnectionsHandlerMock); + httpClientWrapper.capturedRequests.clear(); + } + PartitionKeyRangeIdentity partitionKeyRangeIdentity = new PartitionKeyRangeIdentity(createdCollection.getResourceId(), "0"); - boolean forceRefreshPartitionAddresses = false; + boolean forceRefreshPartitionAddresses = true; Mono> addressesInfosFromCacheObs = cache.tryGetAddresses(req, partitionKeyRangeIdentity, forceRefreshPartitionAddresses); @@ -982,21 +924,38 @@ public void tryGetAddress_replicaValidationTests(boolean replicaValidationEnable if (replicaValidationEnabled) { ArgumentCaptor> openConnectionArguments = ArgumentCaptor.forClass(List.class); - // Open connection will only be called for unhealthyPending status address - Mockito.verify(openConnectionsHandlerMock, Mockito.times(0)).openConnections(openConnectionArguments.capture()); + if (openConnectionAndInitCaches) { + // If openConnectionAndInitCaches is called, then replica validation will also include for unknown status + Mockito.verify(openConnectionsHandlerMock, Mockito.times(1)).openConnections(openConnectionArguments.capture()); + assertThat(openConnectionArguments.getValue()).hasSize(addressInfosFromCache.size()); + } else { + // Open connection will only be called for unhealthyPending status address + Mockito.verify(openConnectionsHandlerMock, Mockito.times(0)).openConnections(openConnectionArguments.capture()); + } } else { Mockito.verify(openConnectionsHandlerMock, Mockito.never()).openConnections(Mockito.any()); } - // Mark one of the uri as unhealthy, others as connected - // and then force refresh the addresses again, make sure the health status of the uri is reserved httpClientWrapper.capturedRequests.clear(); Mockito.clearInvocations(openConnectionsHandlerMock); - for (AddressInformation address : addressInfosFromCache) { - address.getPhysicalUri().setConnected(); + + // Mark one of the uri as unhealthy, one as unknown, others as connected + // and then force refresh the addresses again, make sure the health status of the uri is reserved + assertThat(addressInfosFromCache.size()).isGreaterThan(2); + Uri unknownAddressUri = null; + Uri unhealthyAddressUri = null; + for (int i = 0; i < addressInfosFromCache.size(); i++) { + if (i == 0) { + unknownAddressUri = addressInfosFromCache.get(0).getPhysicalUri(); + continue; + } + if (i == 1) { + unhealthyAddressUri = addressInfosFromCache.get(1).getPhysicalUri(); + unhealthyAddressUri.setUnhealthy(); + } else { + addressInfosFromCache.get(i).getPhysicalUri().setConnected(); + } } - Uri unhealthyAddressUri = addressInfosFromCache.get(0).getPhysicalUri(); - unhealthyAddressUri.setUnhealthy(); ArrayList refreshedAddresses = Lists.newArrayList(getSuccessResult(cache.tryGetAddresses(req, partitionKeyRangeIdentity, true), TIMEOUT).v); @@ -1007,9 +966,12 @@ public void tryGetAddress_replicaValidationTests(boolean replicaValidationEnable // validate connected status will be reserved // validate unhealthy status will change into unhealthyPending status - // validate openConnection will only be called for addresses not in connected status + // Validate openConnection will be called for addresses in unhealthyPending status + // Validate openConnection will be called for addresses in unknown status if openConnectionAndInitCaches is called for (AddressInformation addressInformation : refreshedAddresses) { - if (addressInformation.getPhysicalUri().equals(unhealthyAddressUri)) { + if (addressInformation.getPhysicalUri().equals(unknownAddressUri)) { + assertThat(addressInformation.getPhysicalUri().getHealthStatus()).isEqualTo(Unknown); + } else if (addressInformation.getPhysicalUri().equals(unhealthyAddressUri)) { assertThat(addressInformation.getPhysicalUri().getHealthStatus()).isEqualTo(UnhealthyPending); } else { assertThat(addressInformation.getPhysicalUri().getHealthStatus()).isEqualTo(Connected); @@ -1019,8 +981,12 @@ public void tryGetAddress_replicaValidationTests(boolean replicaValidationEnable if (replicaValidationEnabled) { ArgumentCaptor> openConnectionArguments = ArgumentCaptor.forClass(List.class); Mockito.verify(openConnectionsHandlerMock, Mockito.times(1)).openConnections(openConnectionArguments.capture()); + if (openConnectionAndInitCaches) { + assertThat(openConnectionArguments.getValue()).containsExactlyElementsOf(Arrays.asList(unhealthyAddressUri, unknownAddressUri)); + } else { + assertThat(openConnectionArguments.getValue()).containsExactly(unhealthyAddressUri); + } - assertThat(openConnectionArguments.getValue()).hasSize(1).containsExactly(unhealthyAddressUri); } else { Mockito.verify(openConnectionsHandlerMock, Mockito.never()).openConnections(Mockito.any()); } @@ -1044,7 +1010,6 @@ public void tryGetAddress_failedEndpointTests() throws Exception { authorizationTokenProvider, null, httpClientWrapper.getSpyHttpClient(), - true, null, null, ConnectionPolicy.getDefaultPolicy(), @@ -1107,7 +1072,6 @@ public void tryGetAddress_unhealthyStatus_forceRefresh() throws Exception { authorizationTokenProvider, null, httpClientWrapper.getSpyHttpClient(), - true, null, null, ConnectionPolicy.getDefaultPolicy(), @@ -1151,6 +1115,9 @@ public void tryGetAddress_unhealthyStatus_forceRefresh() throws Exception { ArrayList cachedAddresses = Lists.newArrayList(getSuccessResult(cache.tryGetAddresses(req, partitionKeyRangeIdentity, false), TIMEOUT).v); + // since the refresh will happen asynchronously in the background, wait here some time for it to happen + Thread.sleep(500); + // validate the cache will be refreshed assertThat(httpClientWrapper.capturedRequests) .describedAs("getAddress will read addresses from gateway") @@ -1175,7 +1142,6 @@ public void validateReplicaAddressesTests() throws URISyntaxException, NoSuchMet authorizationTokenProvider, null, httpClientWrapper.getSpyHttpClient(), - true, null, null, ConnectionPolicy.getDefaultPolicy(), @@ -1188,7 +1154,7 @@ public void validateReplicaAddressesTests() throws URISyntaxException, NoSuchMet AddressInformation address1 = new AddressInformation(true, true, "rntbd://127.0.0.1:1", Protocol.TCP); address1.getPhysicalUri().setConnected(); - // remain in unknwon status + // remain in unknown status AddressInformation address2 = new AddressInformation(true, false, "rntbd://127.0.0.1:2", Protocol.TCP); // unhealthy status @@ -1200,14 +1166,19 @@ public void validateReplicaAddressesTests() throws URISyntaxException, NoSuchMet AtomicReference healthStatus = ReflectionUtils.getHealthStatus(address4.getPhysicalUri()); healthStatus.set(UnhealthyPending); + // Set the replica validation scope + Set replicaValidationScopes = ReflectionUtils.getReplicaValidationScopes(cache); + replicaValidationScopes.add(Unknown); + replicaValidationScopes.add(UnhealthyPending); + validateReplicaAddressesMethod.invoke(cache, new Object[]{ new AddressInformation[]{ address1, address2, address3, address4 }}) ; // Validate openConnection will only be called for address in unhealthyPending status ArgumentCaptor> openConnectionArguments = ArgumentCaptor.forClass(List.class); Mockito.verify(openConnectionsHandlerMock, Mockito.times(1)).openConnections(openConnectionArguments.capture()); - assertThat(openConnectionArguments.getValue()).hasSize(1).containsExactlyElementsOf( - Arrays.asList(address4) + assertThat(openConnectionArguments.getValue()).containsExactlyElementsOf( + Arrays.asList(address4, address2) .stream() .map(addressInformation -> addressInformation.getPhysicalUri()) .collect(Collectors.toList())); @@ -1230,7 +1201,6 @@ public void mergeAddressesTests() throws URISyntaxException, NoSuchMethodExcepti authorizationTokenProvider, null, httpClientWrapper.getSpyHttpClient(), - true, null, null, ConnectionPolicy.getDefaultPolicy(), diff --git a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/directconnectivity/ReflectionUtils.java b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/directconnectivity/ReflectionUtils.java index 0c66981c0e618..56dcd9b11160a 100644 --- a/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/directconnectivity/ReflectionUtils.java +++ b/sdk/cosmos/azure-cosmos/src/test/java/com/azure/cosmos/implementation/directconnectivity/ReflectionUtils.java @@ -49,6 +49,7 @@ import java.lang.reflect.Method; import java.time.Duration; import java.util.List; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; @@ -396,4 +397,9 @@ public static void setClientTelemetryMetadataHttpClient(ClientTelemetry clientTe public static AtomicReference getHealthStatus(Uri uri) { return get(AtomicReference.class, uri, "healthStatus"); } + + @SuppressWarnings("unchecked") + public static Set getReplicaValidationScopes(GatewayAddressCache gatewayAddressCache) { + return get(Set.class, gatewayAddressCache, "replicaValidationScopes"); + } } diff --git a/sdk/e2e/pom.xml b/sdk/e2e/pom.xml index b530f81560a3d..8c8104cf6ed2e 100644 --- a/sdk/e2e/pom.xml +++ b/sdk/e2e/pom.xml @@ -29,12 +29,12 @@ com.azure azure-core - 1.32.0-beta.1 + 1.32.0 com.azure azure-core-http-netty - 1.13.0-beta.1 + 1.12.5 com.azure @@ -70,7 +70,7 @@ com.azure azure-core-test - 1.12.0-beta.1 + 1.12.0 test diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobContainerAsyncClient.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobContainerAsyncClient.java index 0f3b5221ae664..a87c44140b1d1 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobContainerAsyncClient.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobContainerAsyncClient.java @@ -44,7 +44,6 @@ import com.azure.storage.blob.models.TaggedBlobItem; import com.azure.storage.blob.models.UserDelegationKey; import com.azure.storage.blob.options.BlobContainerCreateOptions; -import com.azure.storage.blob.options.BlobContainerRenameOptions; import com.azure.storage.blob.options.FindBlobsOptions; import com.azure.storage.blob.sas.BlobServiceSasSignatureValues; import com.azure.storage.common.StorageSharedKeyCredential; @@ -1538,80 +1537,44 @@ Mono> getAccountInfoWithResponse(Context context) { }); } - /** - * Renames an existing blob container. - * - *

Code Samples

- * - * - *
-     * BlobContainerAsyncClient blobContainerAsyncClient =
-     *     client.rename("newContainerName")
-     *         .block();
-     * 
- * - * - * @param destinationContainerName The new name of the container. - * @return A {@link Mono} containing a {@link BlobContainerAsyncClient} used to interact with the renamed container. - */ - @ServiceMethod(returns = ReturnType.SINGLE) - public Mono rename(String destinationContainerName) { - return renameWithResponse(new BlobContainerRenameOptions(destinationContainerName)).flatMap(FluxUtil::toMono); - } - - /** - * Renames an existing blob container. - * - *

Code Samples

- * - * - *
-     * BlobRequestConditions requestConditions = new BlobRequestConditions().setLeaseId("lease-id");
-     * BlobContainerAsyncClient containerClient =
-     *     client.renameWithResponse(new BlobContainerRenameOptions("newContainerName")
-     *         .setRequestConditions(requestConditions)).block().getValue();
-     * 
- * - * - * @param options {@link BlobContainerRenameOptions} - * @return A {@link Mono} containing a {@link Response} whose {@link Response#getValue() value} contains a - * {@link BlobContainerAsyncClient} used to interact with the renamed container. - */ - @ServiceMethod(returns = ReturnType.SINGLE) - public Mono> renameWithResponse(BlobContainerRenameOptions options) { - try { - return withContext(context -> this.renameWithResponse(options, context)); - } catch (RuntimeException ex) { - return monoError(LOGGER, ex); - } - } - - Mono> renameWithResponse(BlobContainerRenameOptions options, Context context) { - // TODO (gapra) : Change this when we have migrated to new generator. There will be a cleaner way to do this by - // calling the container constructor directly instead of needing to do URI surgery - BlobContainerAsyncClient destinationContainerClient = getServiceAsyncClient() - .getBlobContainerAsyncClient(options.getDestinationContainerName()); - return destinationContainerClient.renameWithResponseHelper(this.getBlobContainerName(), options, context); - } - - Mono> renameWithResponseHelper(String sourceContainerName, - BlobContainerRenameOptions options, Context context) { - StorageImplUtils.assertNotNull("options", options); - BlobRequestConditions requestConditions = options.getRequestConditions() == null ? new BlobRequestConditions() - : options.getRequestConditions(); - context = context == null ? Context.NONE : context; - - if (!validateNoETag(requestConditions) || !validateNoTime(requestConditions) - || requestConditions.getTagsConditions() != null) { - throw LOGGER.logExceptionAsError(new UnsupportedOperationException( - "Lease-Id is the only HTTP access condition supported for this API")); - } - - return this.azureBlobStorage.getContainers().renameWithResponseAsync(containerName, - sourceContainerName, null, null, requestConditions.getLeaseId(), - context.addData(AZ_TRACING_NAMESPACE_KEY, STORAGE_TRACING_NAMESPACE_VALUE)) - .map(response -> new SimpleResponse<>(response, this)); - } + // TODO: Reintroduce this API once service starts supporting it. +// Mono rename(String destinationContainerName) { +// return renameWithResponse(new BlobContainerRenameOptions(destinationContainerName)).flatMap(FluxUtil::toMono); +// } + + // TODO: Reintroduce this API once service starts supporting it. +// Mono> renameWithResponse(BlobContainerRenameOptions options) { +// try { +// return withContext(context -> this.renameWithResponse(options, context)); +// } catch (RuntimeException ex) { +// return monoError(LOGGER, ex); +// } +// } + +// Mono> renameWithResponse(BlobContainerRenameOptions options, Context context) { +// BlobContainerAsyncClient destinationContainerClient = getServiceAsyncClient() +// .getBlobContainerAsyncClient(options.getDestinationContainerName()); +// return destinationContainerClient.renameWithResponseHelper(this.getBlobContainerName(), options, context); +// } + +// Mono> renameWithResponseHelper(String sourceContainerName, +// BlobContainerRenameOptions options, Context context) { +// StorageImplUtils.assertNotNull("options", options); +// BlobRequestConditions requestConditions = options.getRequestConditions() == null ? new BlobRequestConditions() +// : options.getRequestConditions(); +// context = context == null ? Context.NONE : context; +// +// if (!validateNoETag(requestConditions) || !validateNoTime(requestConditions) +// || requestConditions.getTagsConditions() != null) { +// throw LOGGER.logExceptionAsError(new UnsupportedOperationException( +// "Lease-Id is the only HTTP access condition supported for this API")); +// } +// +// return this.azureBlobStorage.getContainers().renameWithResponseAsync(containerName, +// sourceContainerName, null, null, requestConditions.getLeaseId(), +// context.addData(AZ_TRACING_NAMESPACE_KEY, STORAGE_TRACING_NAMESPACE_VALUE)) +// .map(response -> new SimpleResponse<>(response, this)); +// } /** * Generates a user delegation SAS for the container using the specified {@link BlobServiceSasSignatureValues}. @@ -1741,11 +1704,11 @@ private static boolean validateNoETag(BlobRequestConditions modifiedRequestCondi return modifiedRequestConditions.getIfMatch() == null && modifiedRequestConditions.getIfNoneMatch() == null; } - private boolean validateNoTime(BlobRequestConditions modifiedRequestConditions) { - if (modifiedRequestConditions == null) { - return true; - } - return modifiedRequestConditions.getIfModifiedSince() == null - && modifiedRequestConditions.getIfUnmodifiedSince() == null; - } +// private boolean validateNoTime(BlobRequestConditions modifiedRequestConditions) { +// if (modifiedRequestConditions == null) { +// return true; +// } +// return modifiedRequestConditions.getIfModifiedSince() == null +// && modifiedRequestConditions.getIfUnmodifiedSince() == null; +// } } diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobContainerClient.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobContainerClient.java index 1e602eb290fcf..711ccdd6f7cb9 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobContainerClient.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobContainerClient.java @@ -9,7 +9,6 @@ import com.azure.core.http.HttpPipeline; import com.azure.core.http.rest.PagedIterable; import com.azure.core.http.rest.Response; -import com.azure.core.http.rest.SimpleResponse; import com.azure.core.util.Context; import com.azure.storage.blob.models.BlobContainerAccessPolicies; import com.azure.storage.blob.models.BlobContainerProperties; @@ -23,7 +22,6 @@ import com.azure.storage.blob.models.TaggedBlobItem; import com.azure.storage.blob.models.UserDelegationKey; import com.azure.storage.blob.options.BlobContainerCreateOptions; -import com.azure.storage.blob.options.BlobContainerRenameOptions; import com.azure.storage.blob.options.FindBlobsOptions; import com.azure.storage.blob.sas.BlobServiceSasSignatureValues; import com.azure.storage.common.StorageSharedKeyCredential; @@ -1053,58 +1051,20 @@ public Response getAccountInfoWithResponse(Duration timeout, return blockWithOptionalTimeout(response, timeout); } - /** - * Renames an existing blob container. - * - *

Code Samples

- * - * - *
-     * BlobContainerClient blobContainerClient = client.rename("newContainerName");
-     * 
- * - * - * @param destinationContainerName The new name of the container. - * @return A {@link BlobContainerClient} used to interact with the renamed container. - */ - @ServiceMethod(returns = ReturnType.SINGLE) - public BlobContainerClient rename(String destinationContainerName) { - return renameWithResponse(new BlobContainerRenameOptions(destinationContainerName - ), null, Context.NONE).getValue(); - } - - /** - * Renames an existing blob container. - * - *

Code Samples

- * - * - *
-     * BlobRequestConditions requestConditions = new BlobRequestConditions().setLeaseId("lease-id");
-     * Context context = new Context("Key", "Value");
-     *
-     * BlobContainerClient blobContainerClient = client.renameWithResponse(
-     *     new BlobContainerRenameOptions("newContainerName")
-     *         .setRequestConditions(requestConditions),
-     *     Duration.ofSeconds(1),
-     *     context).getValue();
-     * 
- * - * - * @param options {@link BlobContainerRenameOptions} - * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. - * @param context Additional context that is passed through the Http pipeline during the service call. - * @return A {@link Response} whose {@link Response#getValue() value} contains a - * {@link BlobContainerClient} used to interact with the renamed container. - */ - @ServiceMethod(returns = ReturnType.SINGLE) - public Response renameWithResponse(BlobContainerRenameOptions options, Duration timeout, - Context context) { - Mono> response = this.client.renameWithResponse(options, context) - .map(r -> new SimpleResponse<>(r, new BlobContainerClient(r.getValue()))); + // TODO: Reintroduce this API once service starts supporting it. +// BlobContainerClient rename(String destinationContainerName) { +// return renameWithResponse(new BlobContainerRenameOptions(destinationContainerName +// ), null, Context.NONE).getValue(); +// } - return StorageImplUtils.blockWithOptionalTimeout(response, timeout); - } + // TODO: Reintroduce this API once service starts supporting it. +// Response renameWithResponse(BlobContainerRenameOptions options, Duration timeout, +// Context context) { +// Mono> response = this.client.renameWithResponse(options, context) +// .map(r -> new SimpleResponse<>(r, new BlobContainerClient(r.getValue()))); +// +// return StorageImplUtils.blockWithOptionalTimeout(response, timeout); +// } /** * Generates a user delegation SAS for the container using the specified {@link BlobServiceSasSignatureValues}. diff --git a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BlobContainerAsyncClientJavaDocCodeSnippets.java b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BlobContainerAsyncClientJavaDocCodeSnippets.java index c6f2644a4ab96..07fab9945be48 100644 --- a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BlobContainerAsyncClientJavaDocCodeSnippets.java +++ b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BlobContainerAsyncClientJavaDocCodeSnippets.java @@ -12,7 +12,6 @@ import com.azure.storage.blob.models.PublicAccessType; import com.azure.storage.blob.models.UserDelegationKey; import com.azure.storage.blob.options.BlobContainerCreateOptions; -import com.azure.storage.blob.options.BlobContainerRenameOptions; import com.azure.storage.blob.options.FindBlobsOptions; import com.azure.storage.blob.sas.BlobContainerSasPermission; import com.azure.storage.blob.sas.BlobServiceSasSignatureValues; @@ -492,26 +491,26 @@ public void deleteIfExistsCodeSnippets() { // END: com.azure.storage.blob.BlobContainerAsyncClient.deleteIfExistsWithResponse#BlobRequestConditions } - /** - * Code snippet for {@link BlobContainerAsyncClient#rename(String)} - */ - public void renameContainer() { - // BEGIN: com.azure.storage.blob.BlobContainerAsyncClient.rename#String - BlobContainerAsyncClient blobContainerAsyncClient = - client.rename("newContainerName") - .block(); - // END: com.azure.storage.blob.BlobContainerAsyncClient.rename#String - } - - /** - * Code snippet for {@link BlobContainerAsyncClient#renameWithResponse(BlobContainerRenameOptions)} - */ - public void renameContainerWithResponse() { - // BEGIN: com.azure.storage.blob.BlobContainerAsyncClient.renameWithResponse#BlobContainerRenameOptions - BlobRequestConditions requestConditions = new BlobRequestConditions().setLeaseId("lease-id"); - BlobContainerAsyncClient containerClient = - client.renameWithResponse(new BlobContainerRenameOptions("newContainerName") - .setRequestConditions(requestConditions)).block().getValue(); - // END: com.azure.storage.blob.BlobContainerAsyncClient.renameWithResponse#BlobContainerRenameOptions - } +// /** +// * Code snippet for {@link BlobContainerAsyncClient#rename(String)} +// */ +// public void renameContainer() { +// // BEGIN: com.azure.storage.blob.BlobContainerAsyncClient.rename#String +// BlobContainerAsyncClient blobContainerAsyncClient = +// client.rename("newContainerName") +// .block(); +// // END: com.azure.storage.blob.BlobContainerAsyncClient.rename#String +// } +// +// /** +// * Code snippet for {@link BlobContainerAsyncClient#renameWithResponse(BlobContainerRenameOptions)} +// */ +// public void renameContainerWithResponse() { +// // BEGIN: com.azure.storage.blob.BlobContainerAsyncClient.renameWithResponse#BlobContainerRenameOptions +// BlobRequestConditions requestConditions = new BlobRequestConditions().setLeaseId("lease-id"); +// BlobContainerAsyncClient containerClient = +// client.renameWithResponse(new BlobContainerRenameOptions("newContainerName") +// .setRequestConditions(requestConditions)).block().getValue(); +// // END: com.azure.storage.blob.BlobContainerAsyncClient.renameWithResponse#BlobContainerRenameOptions +// } } diff --git a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BlobContainerClientJavaDocCodeSnippets.java b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BlobContainerClientJavaDocCodeSnippets.java index 5974a696d31c3..874bb9b6d688d 100644 --- a/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BlobContainerClientJavaDocCodeSnippets.java +++ b/sdk/storage/azure-storage-blob/src/samples/java/com/azure/storage/blob/BlobContainerClientJavaDocCodeSnippets.java @@ -18,7 +18,6 @@ import com.azure.storage.blob.models.StorageAccountInfo; import com.azure.storage.blob.models.UserDelegationKey; import com.azure.storage.blob.options.BlobContainerCreateOptions; -import com.azure.storage.blob.options.BlobContainerRenameOptions; import com.azure.storage.blob.options.FindBlobsOptions; import com.azure.storage.blob.sas.BlobContainerSasPermission; import com.azure.storage.blob.sas.BlobServiceSasSignatureValues; @@ -511,28 +510,28 @@ public void deleteIfExistsCodeSnippets() { // END: com.azure.storage.blob.BlobContainerClient.deleteIfExistsWithResponse#BlobRequestConditions-Duration-Context } - /** - * Code snippet for {@link BlobContainerClient#rename(String)} - */ - public void renameContainer() { - // BEGIN: com.azure.storage.blob.BlobContainerClient.rename#String - BlobContainerClient blobContainerClient = client.rename("newContainerName"); - // END: com.azure.storage.blob.BlobContainerClient.rename#String - } - - /** - * Code snippet for {@link BlobContainerClient#renameWithResponse(BlobContainerRenameOptions, Duration, Context)} - */ - public void renameContainerWithResponse() { - // BEGIN: com.azure.storage.blob.BlobContainerClient.renameWithResponse#BlobContainerRenameOptions-Duration-Context - BlobRequestConditions requestConditions = new BlobRequestConditions().setLeaseId("lease-id"); - Context context = new Context("Key", "Value"); - - BlobContainerClient blobContainerClient = client.renameWithResponse( - new BlobContainerRenameOptions("newContainerName") - .setRequestConditions(requestConditions), - Duration.ofSeconds(1), - context).getValue(); - // END: com.azure.storage.blob.BlobContainerClient.renameWithResponse#BlobContainerRenameOptions-Duration-Context - } +// /** +// * Code snippet for {@link BlobContainerClient#rename(String)} +// */ +// public void renameContainer() { +// // BEGIN: com.azure.storage.blob.BlobContainerClient.rename#String +// BlobContainerClient blobContainerClient = client.rename("newContainerName"); +// // END: com.azure.storage.blob.BlobContainerClient.rename#String +// } +// +// /** +// * Code snippet for {@link BlobContainerClient#renameWithResponse(BlobContainerRenameOptions, Duration, Context)} +// */ +// public void renameContainerWithResponse() { +// // BEGIN: com.azure.storage.blob.BlobContainerClient.renameWithResponse#BlobContainerRenameOptions-Duration-Context +// BlobRequestConditions requestConditions = new BlobRequestConditions().setLeaseId("lease-id"); +// Context context = new Context("Key", "Value"); +// +// BlobContainerClient blobContainerClient = client.renameWithResponse( +// new BlobContainerRenameOptions("newContainerName") +// .setRequestConditions(requestConditions), +// Duration.ofSeconds(1), +// context).getValue(); +// // END: com.azure.storage.blob.BlobContainerClient.renameWithResponse#BlobContainerRenameOptions-Duration-Context +// } } diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ContainerAPITest.groovy b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ContainerAPITest.groovy index 1e9822fbe83fd..e47710166b7b5 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ContainerAPITest.groovy +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/ContainerAPITest.groovy @@ -28,7 +28,6 @@ import com.azure.storage.blob.models.ObjectReplicationStatus import com.azure.storage.blob.models.PublicAccessType import com.azure.storage.blob.models.RehydratePriority import com.azure.storage.blob.options.BlobContainerCreateOptions -import com.azure.storage.blob.options.BlobContainerRenameOptions import com.azure.storage.blob.options.BlobParallelUploadOptions import com.azure.storage.blob.options.BlobSetAccessTierOptions import com.azure.storage.blob.options.FindBlobsOptions @@ -36,10 +35,6 @@ import com.azure.storage.blob.options.PageBlobCreateOptions import com.azure.storage.blob.specialized.AppendBlobClient import com.azure.storage.blob.specialized.BlobClientBase import com.azure.storage.common.Utility -import com.azure.storage.common.sas.AccountSasPermission -import com.azure.storage.common.sas.AccountSasResourceType -import com.azure.storage.common.sas.AccountSasService -import com.azure.storage.common.sas.AccountSasSignatureValues import com.azure.storage.common.test.shared.extensions.PlaybackOnly import com.azure.storage.common.test.shared.extensions.RequiredServiceVersion import reactor.test.StepVerifier @@ -2213,115 +2208,117 @@ class ContainerAPITest extends APISpec { response.getHeaders().getValue("x-ms-version") == "2017-11-09" } - def "Rename"() { - setup: - def newName = generateContainerName() - - when: - def renamedContainer = cc.rename(newName) - - then: - renamedContainer.getPropertiesWithResponse(null, null, null).getStatusCode() == 200 - - cleanup: - renamedContainer.delete() - } - - def "Rename sas"() { - setup: - def newName = generateContainerName() - def service = new AccountSasService() - .setBlobAccess(true) - def resourceType = new AccountSasResourceType() - .setContainer(true) - .setService(true) - .setObject(true) - def expiryTime = namer.getUtcNow().plusDays(1) - def permissions = new AccountSasPermission() - .setReadPermission(true) - .setWritePermission(true) - .setCreatePermission(true) - .setDeletePermission(true) - - def sasValues = new AccountSasSignatureValues(expiryTime, permissions, service, resourceType) - def sas = primaryBlobServiceClient.generateAccountSas(sasValues) - def sasClient = getContainerClient(sas, cc.getBlobContainerUrl()) - - when: - def renamedContainer = sasClient.rename(newName) - - then: - renamedContainer.getPropertiesWithResponse(null, null, null).getStatusCode() == 200 - - cleanup: - renamedContainer.delete() - } - - @Unroll - def "Rename AC"() { - setup: - leaseID = setupContainerLeaseCondition(cc, leaseID) - def cac = new BlobRequestConditions() - .setLeaseId(leaseID) - - expect: - cc.renameWithResponse(new BlobContainerRenameOptions(generateContainerName()).setRequestConditions(cac), - null, null).getStatusCode() == 200 - - where: - leaseID || _ - null || _ - receivedLeaseID || _ - } - - @Unroll - def "Rename AC fail"() { - setup: - def cac = new BlobRequestConditions() - .setLeaseId(leaseID) - - when: - cc.renameWithResponse(new BlobContainerRenameOptions(generateContainerName()).setRequestConditions(cac), - null, null) - - then: - thrown(BlobStorageException) - - where: - leaseID || _ - garbageLeaseID || _ - } - - @Unroll - def "Rename AC illegal"() { - setup: - def ac = new BlobRequestConditions().setIfMatch(match).setIfNoneMatch(noneMatch).setIfModifiedSince(modified).setIfUnmodifiedSince(unmodified).setTagsConditions(tags) - - when: - cc.renameWithResponse(new BlobContainerRenameOptions(generateContainerName()).setRequestConditions(ac), - null, null) - - then: - thrown(UnsupportedOperationException) - - where: - modified | unmodified | match | noneMatch | tags - oldDate | null | null | null | null - null | newDate | null | null | null - null | null | receivedEtag | null | null - null | null | null | garbageEtag | null - null | null | null | null | "tags" - } - - def "Rename error"() { - setup: - cc = primaryBlobServiceClient.getBlobContainerClient(generateContainerName()) - def newName = generateContainerName() - - when: - cc.rename(newName) - - then: - thrown(BlobStorageException) - } +// TODO: Reintroduce these tests once service starts supporting it. + +// def "Rename"() { +// setup: +// def newName = generateContainerName() +// +// when: +// def renamedContainer = cc.rename(newName) +// +// then: +// renamedContainer.getPropertiesWithResponse(null, null, null).getStatusCode() == 200 +// +// cleanup: +// renamedContainer.delete() +// } + +// def "Rename sas"() { +// setup: +// def newName = generateContainerName() +// def service = new AccountSasService() +// .setBlobAccess(true) +// def resourceType = new AccountSasResourceType() +// .setContainer(true) +// .setService(true) +// .setObject(true) +// def expiryTime = namer.getUtcNow().plusDays(1) +// def permissions = new AccountSasPermission() +// .setReadPermission(true) +// .setWritePermission(true) +// .setCreatePermission(true) +// .setDeletePermission(true) +// +// def sasValues = new AccountSasSignatureValues(expiryTime, permissions, service, resourceType) +// def sas = primaryBlobServiceClient.generateAccountSas(sasValues) +// def sasClient = getContainerClient(sas, cc.getBlobContainerUrl()) +// +// when: +// def renamedContainer = sasClient.rename(newName) +// +// then: +// renamedContainer.getPropertiesWithResponse(null, null, null).getStatusCode() == 200 +// +// cleanup: +// renamedContainer.delete() +// } + +// @Unroll +// def "Rename AC"() { +// setup: +// leaseID = setupContainerLeaseCondition(cc, leaseID) +// def cac = new BlobRequestConditions() +// .setLeaseId(leaseID) +// +// expect: +// cc.renameWithResponse(new BlobContainerRenameOptions(generateContainerName()).setRequestConditions(cac), +// null, null).getStatusCode() == 200 +// +// where: +// leaseID || _ +// null || _ +// receivedLeaseID || _ +// } + +// @Unroll +// def "Rename AC fail"() { +// setup: +// def cac = new BlobRequestConditions() +// .setLeaseId(leaseID) +// +// when: +// cc.renameWithResponse(new BlobContainerRenameOptions(generateContainerName()).setRequestConditions(cac), +// null, null) +// +// then: +// thrown(BlobStorageException) +// +// where: +// leaseID || _ +// garbageLeaseID || _ +// } + +// @Unroll +// def "Rename AC illegal"() { +// setup: +// def ac = new BlobRequestConditions().setIfMatch(match).setIfNoneMatch(noneMatch).setIfModifiedSince(modified).setIfUnmodifiedSince(unmodified).setTagsConditions(tags) +// +// when: +// cc.renameWithResponse(new BlobContainerRenameOptions(generateContainerName()).setRequestConditions(ac), +// null, null) +// +// then: +// thrown(UnsupportedOperationException) +// +// where: +// modified | unmodified | match | noneMatch | tags +// oldDate | null | null | null | null +// null | newDate | null | null | null +// null | null | receivedEtag | null | null +// null | null | null | garbageEtag | null +// null | null | null | null | "tags" +// } + +// def "Rename error"() { +// setup: +// cc = primaryBlobServiceClient.getBlobContainerClient(generateContainerName()) +// def newName = generateContainerName() +// +// when: +// cc.rename(newName) +// +// then: +// thrown(BlobStorageException) +// } } diff --git a/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRename.json b/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRename.json deleted file mode 100644 index 8c5bf40ace576..0000000000000 --- a/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRename.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "networkCallRecords" : [ { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/a8add0010a8add001465681847902c7aef6aa4e9485f?restype=container", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "da39f7eb-1379-43cc-92f4-6ea363fd9817" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "eTag" : "0x8DA89F78B793EFC", - "Last-Modified" : "Mon, 29 Aug 2022 19:49:11 GMT", - "retry-after" : "0", - "StatusCode" : "201", - "x-ms-request-id" : "40eba2c6-901e-0054-39e0-bb9595000000", - "x-ms-client-request-id" : "da39f7eb-1379-43cc-92f4-6ea363fd9817", - "Date" : "Mon, 29 Aug 2022 19:49:11 GMT" - }, - "Exception" : null - }, { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/a8add0011a8add00146583374b15a2496fafa4095ac0?restype=container&comp=rename", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "d07b77cb-a0d4-4b40-850c-ac3e7848c68c" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "retry-after" : "0", - "StatusCode" : "200", - "x-ms-request-id" : "40eba385-901e-0054-69e0-bb9595000000", - "x-ms-client-request-id" : "d07b77cb-a0d4-4b40-850c-ac3e7848c68c", - "Date" : "Mon, 29 Aug 2022 19:49:12 GMT" - }, - "Exception" : null - }, { - "Method" : "GET", - "Uri" : "https://REDACTED.blob.core.windows.net/a8add0011a8add00146583374b15a2496fafa4095ac0?restype=container", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "84775690-4b2a-4f5e-8d78-fa1d3ccde52a" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "x-ms-lease-status" : "unlocked", - "x-ms-immutable-storage-with-versioning-enabled" : "false", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-lease-state" : "available", - "x-ms-deny-encryption-scope-override" : "false", - "Last-Modified" : "Mon, 29 Aug 2022 19:49:12 GMT", - "retry-after" : "0", - "StatusCode" : "200", - "x-ms-has-legal-hold" : "false", - "Date" : "Mon, 29 Aug 2022 19:49:13 GMT", - "x-ms-default-encryption-scope" : "$account-encryption-key", - "x-ms-has-immutability-policy" : "false", - "eTag" : "0x8DA89F78C30FDBF", - "x-ms-request-id" : "40eba74f-901e-0054-50e0-bb9595000000", - "x-ms-client-request-id" : "84775690-4b2a-4f5e-8d78-fa1d3ccde52a" - }, - "Exception" : null - }, { - "Method" : "DELETE", - "Uri" : "https://REDACTED.blob.core.windows.net/a8add0011a8add00146583374b15a2496fafa4095ac0?restype=container", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "4a14c824-34f2-4dde-bd11-3321667ef171" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "retry-after" : "0", - "StatusCode" : "202", - "x-ms-request-id" : "40eba781-901e-0054-7fe0-bb9595000000", - "x-ms-client-request-id" : "4a14c824-34f2-4dde-bd11-3321667ef171", - "Date" : "Mon, 29 Aug 2022 19:49:13 GMT" - }, - "Exception" : null - } ], - "variables" : [ "a8add0010a8add001465681847902c7aef6aa4e9485f", "a8add00196773d1a", "a8add0018736921c", "a8add0011a8add00146583374b15a2496fafa4095ac0" ] -} \ No newline at end of file diff --git a/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameACFail[0].json b/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameACFail[0].json deleted file mode 100644 index 1b20c271967cd..0000000000000 --- a/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameACFail[0].json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "networkCallRecords" : [ { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/e1739e460e1739e46f6a20124f2a009559ba24c118e3?restype=container", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "f1afb546-0129-4556-aede-65e8542c9427" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "eTag" : "0x8DA89F7D4C4F21C", - "Last-Modified" : "Mon, 29 Aug 2022 19:51:14 GMT", - "retry-after" : "0", - "StatusCode" : "201", - "x-ms-request-id" : "49584001-301e-003f-16e0-bb1261000000", - "x-ms-client-request-id" : "f1afb546-0129-4556-aede-65e8542c9427", - "Date" : "Mon, 29 Aug 2022 19:51:15 GMT" - }, - "Exception" : null - }, { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/e1739e461e1739e46f6a68928b9f5802ee2a94ef3884?restype=container&comp=rename", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "47f3b163-0709-4b5e-91fd-dde35c31ef65" - }, - "Response" : { - "content-length" : "252", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-error-code" : "LeaseNotPresentWithContainerOperation", - "retry-after" : "0", - "StatusCode" : "412", - "x-ms-request-id" : "495840cb-301e-003f-36e0-bb1261000000", - "Body" : "\nLeaseNotPresentWithContainerOperationThere is currently no lease on the container.\nRequestId:495840cb-301e-003f-36e0-bb1261000000\nTime:2022-08-29T19:51:17.4254504Z", - "x-ms-client-request-id" : "47f3b163-0709-4b5e-91fd-dde35c31ef65", - "Date" : "Mon, 29 Aug 2022 19:51:17 GMT", - "Content-Type" : "application/xml" - }, - "Exception" : null - } ], - "variables" : [ "e1739e460e1739e46f6a20124f2a009559ba24c118e3", "e1739e46687434be", "e1739e46019199c3", "e1739e461e1739e46f6a68928b9f5802ee2a94ef3884" ] -} \ No newline at end of file diff --git a/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameACIllegal[0].json b/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameACIllegal[0].json deleted file mode 100644 index f446d35fb924e..0000000000000 --- a/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameACIllegal[0].json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "networkCallRecords" : [ { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/e48d3c7c0e48d3c7c54034732b9742ec71b5b446dad3?restype=container", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "5f92eb6c-227a-456d-9531-1dd3d2fda3e6" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "eTag" : "0x8DA89F7D4C3C64F", - "Last-Modified" : "Mon, 29 Aug 2022 19:51:14 GMT", - "retry-after" : "0", - "StatusCode" : "201", - "x-ms-request-id" : "c77786da-a01e-0002-07e0-bb647a000000", - "x-ms-client-request-id" : "5f92eb6c-227a-456d-9531-1dd3d2fda3e6", - "Date" : "Mon, 29 Aug 2022 19:51:14 GMT" - }, - "Exception" : null - } ], - "variables" : [ "e48d3c7c0e48d3c7c54034732b9742ec71b5b446dad3", "e48d3c7c29513451", "e48d3c7c12559103", "e48d3c7c1e48d3c7c54021240e228b8d81f16446eaf7" ] -} \ No newline at end of file diff --git a/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameACIllegal[1].json b/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameACIllegal[1].json deleted file mode 100644 index e3b2ace2dc900..0000000000000 --- a/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameACIllegal[1].json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "networkCallRecords" : [ { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/fd960d3d0fd960d3dab945527178fc6c447424ecabe9?restype=container", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "74f7f5b7-6a1e-4ca5-bc4e-ebc56c9006bd" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "eTag" : "0x8DA89F7D4C3ED62", - "Last-Modified" : "Mon, 29 Aug 2022 19:51:14 GMT", - "retry-after" : "0", - "StatusCode" : "201", - "x-ms-request-id" : "eccdd303-801e-0067-80e0-bbca3e000000", - "x-ms-client-request-id" : "74f7f5b7-6a1e-4ca5-bc4e-ebc56c9006bd", - "Date" : "Mon, 29 Aug 2022 19:51:14 GMT" - }, - "Exception" : null - } ], - "variables" : [ "fd960d3d0fd960d3dab945527178fc6c447424ecabe9", "fd960d3d308567c6", "fd960d3d44482204", "fd960d3d1fd960d3dab98453818432faf67164e3f80e" ] -} \ No newline at end of file diff --git a/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameACIllegal[2].json b/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameACIllegal[2].json deleted file mode 100644 index dcc4ce1980d9e..0000000000000 --- a/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameACIllegal[2].json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "networkCallRecords" : [ { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/d6bb5efe0d6bb5efe94992631adbb430a9d2c4683a55?restype=container", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "f6d97dcb-c0bb-40b5-80d1-65faa0f85cd0" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "eTag" : "0x8DA89F7D4C2F424", - "Last-Modified" : "Mon, 29 Aug 2022 19:51:14 GMT", - "retry-after" : "0", - "StatusCode" : "201", - "x-ms-request-id" : "1a3b0a3f-f01e-000f-08e0-bbacae000000", - "x-ms-client-request-id" : "f6d97dcb-c0bb-40b5-80d1-65faa0f85cd0", - "Date" : "Mon, 29 Aug 2022 19:51:13 GMT" - }, - "Exception" : null - } ], - "variables" : [ "d6bb5efe0d6bb5efe94992631adbb430a9d2c4683a55", "d6bb5efe14150977", "d6bb5efe35806eb5", "d6bb5efe1d6bb5efe949391467cc9c61778064d3cb3a" ] -} \ No newline at end of file diff --git a/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameACIllegal[3].json b/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameACIllegal[3].json deleted file mode 100644 index 62d672a0cce0e..0000000000000 --- a/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameACIllegal[3].json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "networkCallRecords" : [ { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/cfa06fbf0cfa06fbfd8277294c66bf650caef46918d7?restype=container", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "545215e2-1b5f-4e82-aa30-51c218392d26" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "eTag" : "0x8DA89F7D4C4102E", - "Last-Modified" : "Mon, 29 Aug 2022 19:51:14 GMT", - "retry-after" : "0", - "StatusCode" : "201", - "x-ms-request-id" : "4579b2c7-601e-008b-62e0-bbdeaf000000", - "x-ms-client-request-id" : "545215e2-1b5f-4e82-aa30-51c218392d26", - "Date" : "Mon, 29 Aug 2022 19:51:14 GMT" - }, - "Exception" : null - } ], - "variables" : [ "cfa06fbf0cfa06fbfd8277294c66bf650caef46918d7", "cfa06fbf691968c8", "cfa06fbf04998792", "cfa06fbf1cfa06fbfd8258540e2de39e7674042b9826" ] -} \ No newline at end of file diff --git a/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameACIllegal[4].json b/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameACIllegal[4].json deleted file mode 100644 index df6a7598b76a9..0000000000000 --- a/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameACIllegal[4].json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "networkCallRecords" : [ { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/80e1f978080e1f97806056264cad307a9de8d4f0e99a?restype=container", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "bbd62cbe-6055-4b6a-987a-91091676999b" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "eTag" : "0x8DA89F7D4C413FD", - "Last-Modified" : "Mon, 29 Aug 2022 19:51:14 GMT", - "retry-after" : "0", - "StatusCode" : "201", - "x-ms-request-id" : "c54c4322-a01e-003d-2de0-bbacd9000000", - "x-ms-client-request-id" : "bbd62cbe-6055-4b6a-987a-91091676999b", - "Date" : "Mon, 29 Aug 2022 19:51:14 GMT" - }, - "Exception" : null - } ], - "variables" : [ "80e1f978080e1f97806056264cad307a9de8d4f0e99a", "80e1f978099053bf", "80e1f978722964a2", "80e1f978180e1f97806096226deecfc84ca99461d915" ] -} \ No newline at end of file diff --git a/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameAC[0].json b/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameAC[0].json deleted file mode 100644 index 01b00d6bb7998..0000000000000 --- a/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameAC[0].json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "networkCallRecords" : [ { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/2c2fc32702c2fc327dc736183d62b4440e1c54b439de?restype=container", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "8bb42b43-cc26-4f42-a53e-de0a0f8ba584" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "eTag" : "0x8DA89F7D4C3A47F", - "Last-Modified" : "Mon, 29 Aug 2022 19:51:14 GMT", - "retry-after" : "0", - "StatusCode" : "201", - "x-ms-request-id" : "58f34824-301e-0000-1fe0-bbdac2000000", - "x-ms-client-request-id" : "8bb42b43-cc26-4f42-a53e-de0a0f8ba584", - "Date" : "Mon, 29 Aug 2022 19:51:14 GMT" - }, - "Exception" : null - }, { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/2c2fc32712c2fc327dc784778337cb2624df2465c8f5?restype=container&comp=rename", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "610228cd-6a3a-44f0-b710-3cb4dce63439" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "retry-after" : "0", - "StatusCode" : "200", - "x-ms-request-id" : "c7778896-a01e-0002-0ee0-bb647a000000", - "x-ms-client-request-id" : "610228cd-6a3a-44f0-b710-3cb4dce63439", - "Date" : "Mon, 29 Aug 2022 19:51:15 GMT" - }, - "Exception" : null - } ], - "variables" : [ "2c2fc32702c2fc327dc736183d62b4440e1c54b439de", "2c2fc32772671c9f", "2c2fc327877896e6", "2c2fc32712c2fc327dc784778337cb2624df2465c8f5" ] -} \ No newline at end of file diff --git a/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameAC[1].json b/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameAC[1].json deleted file mode 100644 index 40fb43af719fd..0000000000000 --- a/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameAC[1].json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "networkCallRecords" : [ { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/3534f26603534f266c6435788e51b653de38046a3afa?restype=container", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "d6ef9566-f2df-449b-bde7-51f097b7eba7" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "eTag" : "0x8DA89F7D4C3A118", - "Last-Modified" : "Mon, 29 Aug 2022 19:51:14 GMT", - "retry-after" : "0", - "StatusCode" : "201", - "x-ms-request-id" : "ce33008c-f01e-0042-13e0-bb6342000000", - "x-ms-client-request-id" : "d6ef9566-f2df-449b-bde7-51f097b7eba7", - "Date" : "Mon, 29 Aug 2022 19:51:14 GMT" - }, - "Exception" : null - }, { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/3534f26603534f266c6435788e51b653de38046a3afa?comp=lease&restype=container", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "d787e447-7b49-4958-acd0-d94c2cefc9be" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-lease-id" : "908812c1-aaea-4748-9833-27de801c96e7", - "eTag" : "0x8DA89F7D4C3A118", - "Last-Modified" : "Mon, 29 Aug 2022 19:51:14 GMT", - "retry-after" : "0", - "StatusCode" : "201", - "x-ms-request-id" : "eccdd3ef-801e-0067-4ce0-bbca3e000000", - "x-ms-client-request-id" : "d787e447-7b49-4958-acd0-d94c2cefc9be", - "Date" : "Mon, 29 Aug 2022 19:51:15 GMT" - }, - "Exception" : null - }, { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/3534f26613534f266c64412191a2c6f3a22714879a01?restype=container&comp=rename", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "84da3438-db6c-4bcc-9bd3-ecfb07a012fe" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "retry-after" : "0", - "StatusCode" : "200", - "x-ms-request-id" : "eccdd44d-801e-0067-1ee0-bbca3e000000", - "x-ms-client-request-id" : "84da3438-db6c-4bcc-9bd3-ecfb07a012fe", - "Date" : "Mon, 29 Aug 2022 19:51:16 GMT" - }, - "Exception" : null - } ], - "variables" : [ "3534f26603534f266c6435788e51b653de38046a3afa", "3534f26699302dfd", "3534f2660645320f", "3534f26613534f266c64412191a2c6f3a22714879a01" ] -} \ No newline at end of file diff --git a/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameError.json b/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameError.json deleted file mode 100644 index f0fc5cfff2f29..0000000000000 --- a/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameError.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "networkCallRecords" : [ { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/3056fb8e03056fb8e56136005aff852f09ea14c0fa29?restype=container", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "fe124576-4647-4e5c-b363-a4bb3773d8bd" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "eTag" : "0x8DA89F7D4C39C7F", - "Last-Modified" : "Mon, 29 Aug 2022 19:51:14 GMT", - "retry-after" : "0", - "StatusCode" : "201", - "x-ms-request-id" : "620b392b-201e-0023-45e0-bb4001000000", - "x-ms-client-request-id" : "fe124576-4647-4e5c-b363-a4bb3773d8bd", - "Date" : "Mon, 29 Aug 2022 19:51:14 GMT" - }, - "Exception" : null - }, { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/3056fb8e23056fb8e5618743307b87fa6e18540c7982?restype=container&comp=rename", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "55a2d59c-1a5f-4247-83ab-d9fcadd0aa60" - }, - "Response" : { - "content-length" : "226", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-error-code" : "ContainerNotFound", - "retry-after" : "0", - "StatusCode" : "404", - "x-ms-request-id" : "844526a0-501e-0074-5de0-bbee32000000", - "Body" : "\nContainerNotFoundThe specified container does not exist.\nRequestId:844526a0-501e-0074-5de0-bbee32000000\nTime:2022-08-29T19:51:18.7662387Z", - "x-ms-client-request-id" : "55a2d59c-1a5f-4247-83ab-d9fcadd0aa60", - "Date" : "Mon, 29 Aug 2022 19:51:18 GMT", - "Content-Type" : "application/xml" - }, - "Exception" : null - } ], - "variables" : [ "3056fb8e03056fb8e56136005aff852f09ea14c0fa29", "3056fb8e075034fd", "3056fb8e3479411b", "3056fb8e13056fb8e5617510951a330f78dec4a569da", "3056fb8e23056fb8e5618743307b87fa6e18540c7982" ] -} \ No newline at end of file diff --git a/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameSas.json b/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameSas.json deleted file mode 100644 index 6f0644478d3ef..0000000000000 --- a/sdk/storage/azure-storage-blob/src/test/resources/session-records/ContainerAPITestRenameSas.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "networkCallRecords" : [ { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/0ccc434e00ccc434ea0d50026d7c4613270524eb49ea?restype=container", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "35d978a5-4fb9-4603-8098-866ded17cc5c" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "eTag" : "0x8DA8A18272D604A", - "Last-Modified" : "Mon, 29 Aug 2022 23:42:36 GMT", - "retry-after" : "0", - "StatusCode" : "201", - "x-ms-request-id" : "dd0da0d3-401e-0035-0201-bcb6d6000000", - "x-ms-client-request-id" : "35d978a5-4fb9-4603-8098-866ded17cc5c", - "Date" : "Mon, 29 Aug 2022 23:42:35 GMT" - }, - "Exception" : null - }, { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/0ccc434e10ccc434ea0d78544028d98c6ad5e489ba9a?restype=container&comp=rename&sv=2021-10-04&ss=b&srt=sco&se=2022-08-30T23%3A42%3A36Z&sp=rwdc&sig=REDACTED", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "04c30745-a7c3-49ab-82ac-d8cf7c3a2749" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "retry-after" : "0", - "StatusCode" : "200", - "x-ms-request-id" : "dd0da10c-401e-0035-3001-bcb6d6000000", - "x-ms-client-request-id" : "04c30745-a7c3-49ab-82ac-d8cf7c3a2749", - "Date" : "Mon, 29 Aug 2022 23:42:37 GMT" - }, - "Exception" : null - }, { - "Method" : "GET", - "Uri" : "https://REDACTED.blob.core.windows.net/0ccc434e10ccc434ea0d78544028d98c6ad5e489ba9a?restype=container&sv=2021-10-04&ss=b&srt=sco&se=2022-08-30T23%3A42%3A36Z&sp=rwdc&sig=REDACTED", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "d83058c5-c2dd-4b0c-be49-d6bdf3b979b3" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "x-ms-lease-status" : "unlocked", - "x-ms-immutable-storage-with-versioning-enabled" : "false", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-lease-state" : "available", - "x-ms-deny-encryption-scope-override" : "false", - "Last-Modified" : "Mon, 29 Aug 2022 23:42:38 GMT", - "retry-after" : "0", - "StatusCode" : "200", - "x-ms-has-legal-hold" : "false", - "Date" : "Mon, 29 Aug 2022 23:42:37 GMT", - "x-ms-default-encryption-scope" : "$account-encryption-key", - "x-ms-has-immutability-policy" : "false", - "eTag" : "0x8DA8A1827F7DED2", - "x-ms-request-id" : "dd0da303-401e-0035-6d01-bcb6d6000000", - "x-ms-client-request-id" : "d83058c5-c2dd-4b0c-be49-d6bdf3b979b3" - }, - "Exception" : null - }, { - "Method" : "DELETE", - "Uri" : "https://REDACTED.blob.core.windows.net/0ccc434e10ccc434ea0d78544028d98c6ad5e489ba9a?restype=container&sv=2021-10-04&ss=b&srt=sco&se=2022-08-30T23%3A42%3A36Z&sp=rwdc&sig=REDACTED", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "82d23a08-26cc-479a-8601-cbc24c81ecbb" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "retry-after" : "0", - "StatusCode" : "202", - "x-ms-request-id" : "dd0da32c-401e-0035-1401-bcb6d6000000", - "x-ms-client-request-id" : "82d23a08-26cc-479a-8601-cbc24c81ecbb", - "Date" : "Mon, 29 Aug 2022 23:42:37 GMT" - }, - "Exception" : null - } ], - "variables" : [ "0ccc434e00ccc434ea0d50026d7c4613270524eb49ea", "0ccc434e9681811d", "0ccc434e24942fc5", "0ccc434e10ccc434ea0d78544028d98c6ad5e489ba9a", "2022-08-29T23:42:36.790068500Z" ] -} \ No newline at end of file diff --git a/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/DataLakeFileSystemAsyncClient.java b/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/DataLakeFileSystemAsyncClient.java index 9bb6799af106d..7362a727c98c8 100644 --- a/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/DataLakeFileSystemAsyncClient.java +++ b/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/DataLakeFileSystemAsyncClient.java @@ -53,7 +53,6 @@ import com.azure.storage.file.datalake.models.UserDelegationKey; import com.azure.storage.file.datalake.options.DataLakePathCreateOptions; import com.azure.storage.file.datalake.options.DataLakePathDeleteOptions; -import com.azure.storage.file.datalake.options.FileSystemRenameOptions; import com.azure.storage.file.datalake.sas.DataLakeServiceSasSignatureValues; import reactor.core.publisher.Mono; @@ -1825,73 +1824,39 @@ public Mono> getAccessPolicyWithResponse(Stri Transforms.toFileSystemAccessPolicies(response.getValue()))); } - /** - * Renames an existing file system. - * - *

Code Samples

- * - * - *
-     * DataLakeFileSystemAsyncClient fileSystemAsyncClient =
-     *     client.rename("newFileSystemName")
-     *         .block();
-     * 
- * - * - * @param destinationContainerName The new name of the file system. - * @return A {@link Mono} containing a {@link DataLakeFileSystemAsyncClient} used to interact with the renamed file system. - */ - @ServiceMethod(returns = ReturnType.SINGLE) - public Mono rename(String destinationContainerName) { - return renameWithResponse(new FileSystemRenameOptions(destinationContainerName)).flatMap(FluxUtil::toMono); - } - - /** - * Renames an existing file system. - * - *

Code Samples

- * - * - *
-     * DataLakeRequestConditions requestConditions = new DataLakeRequestConditions().setLeaseId("lease-id");
-     * DataLakeFileSystemAsyncClient fileSystemAsyncClient = client
-     *     .renameWithResponse(new FileSystemRenameOptions( "newFileSystemName")
-     *         .setRequestConditions(requestConditions)).block().getValue();
-     * 
- * - * - * @param options {@link FileSystemRenameOptions} - * @return A {@link Mono} containing a {@link Response} whose {@link Response#getValue() value} contains a - * {@link DataLakeFileSystemAsyncClient} used to interact with the renamed file system. - */ - @ServiceMethod(returns = ReturnType.SINGLE) - public Mono> renameWithResponse(FileSystemRenameOptions options) { - try { - return blobContainerAsyncClient.renameWithResponse(Transforms.toBlobContainerRenameOptions(options)) - .onErrorMap(DataLakeImplUtils::transformBlobStorageException) - .map(response -> new SimpleResponse<>(response, - this.getFileSystemAsyncClient(options.getDestinationFileSystemName()))); - } catch (RuntimeException ex) { - return monoError(LOGGER, ex); - } - } - - /** - * Takes in a destination and creates a DataLakeFileSystemAsyncClient with a new path - * @param destinationFileSystem The destination file system - * @return A DataLakeFileSystemAsyncClient - */ - DataLakeFileSystemAsyncClient getFileSystemAsyncClient(String destinationFileSystem) { - if (CoreUtils.isNullOrEmpty(destinationFileSystem)) { - throw LOGGER.logExceptionAsError(new IllegalArgumentException("'destinationFileSystem' can not be set to null")); - } - // Get current Datalake URL and replace current filesystem with user provided filesystem - String newDfsEndpoint = BlobUrlParts.parse(getFileSystemUrl()) - .setContainerName(destinationFileSystem).toUrl().toString(); - - return new DataLakeFileSystemAsyncClient(getHttpPipeline(), newDfsEndpoint, serviceVersion, accountName, - destinationFileSystem, prepareBuilderReplacePath(destinationFileSystem).buildAsyncClient(), sasToken); - } + // TODO: Reintroduce this API once service starts supporting it. +// Mono rename(String destinationContainerName) { +// return renameWithResponse(new FileSystemRenameOptions(destinationContainerName)).flatMap(FluxUtil::toMono); +// } + + // TODO: Reintroduce this API once service starts supporting it. +// Mono> renameWithResponse(FileSystemRenameOptions options) { +// try { +// return blobContainerAsyncClient.renameWithResponse(Transforms.toBlobContainerRenameOptions(options)) +// .onErrorMap(DataLakeImplUtils::transformBlobStorageException) +// .map(response -> new SimpleResponse<>(response, +// this.getFileSystemAsyncClient(options.getDestinationFileSystemName()))); +// } catch (RuntimeException ex) { +// return monoError(LOGGER, ex); +// } +// } + +// /** +// * Takes in a destination and creates a DataLakeFileSystemAsyncClient with a new path +// * @param destinationFileSystem The destination file system +// * @return A DataLakeFileSystemAsyncClient +// */ +// DataLakeFileSystemAsyncClient getFileSystemAsyncClient(String destinationFileSystem) { +// if (CoreUtils.isNullOrEmpty(destinationFileSystem)) { +// throw LOGGER.logExceptionAsError(new IllegalArgumentException("'destinationFileSystem' can not be set to null")); +// } +// // Get current Datalake URL and replace current filesystem with user provided filesystem +// String newDfsEndpoint = BlobUrlParts.parse(getFileSystemUrl()) +// .setContainerName(destinationFileSystem).toUrl().toString(); +// +// return new DataLakeFileSystemAsyncClient(getHttpPipeline(), newDfsEndpoint, serviceVersion, accountName, +// destinationFileSystem, prepareBuilderReplacePath(destinationFileSystem).buildAsyncClient(), sasToken); +// } /** * Takes in a destination path and creates a ContainerClientBuilder with a new path name @@ -1912,9 +1877,9 @@ BlobContainerClientBuilder prepareBuilderReplacePath(String destinationFileSyste .serviceVersion(TransformUtils.toBlobServiceVersion(getServiceVersion())); } - BlobContainerAsyncClient getBlobContainerAsyncClient() { - return blobContainerAsyncClient; - } +// BlobContainerAsyncClient getBlobContainerAsyncClient() { +// return blobContainerAsyncClient; +// } /** * Generates a user delegation SAS for the file system using the specified diff --git a/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/DataLakeFileSystemClient.java b/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/DataLakeFileSystemClient.java index 8e7931b44b5db..a854c28ed4ad5 100644 --- a/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/DataLakeFileSystemClient.java +++ b/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/DataLakeFileSystemClient.java @@ -34,7 +34,6 @@ import com.azure.storage.file.datalake.models.UserDelegationKey; import com.azure.storage.file.datalake.options.DataLakePathCreateOptions; import com.azure.storage.file.datalake.options.DataLakePathDeleteOptions; -import com.azure.storage.file.datalake.options.FileSystemRenameOptions; import com.azure.storage.file.datalake.sas.DataLakeServiceSasSignatureValues; import reactor.core.publisher.Mono; @@ -1617,64 +1616,24 @@ public Response setAccessPolicyWithResponse(PublicAccessType accessType, timeout, context), LOGGER); } - /** - * Renames an existing file system. - * - *

Code Samples

- * - * - *
-     * DataLakeFileSystemClient fileSystemClient = client.rename("newFileSystemName");
-     * 
- * - * - * @param destinationFileSystemName The new name of the file system. - * @return A {@link DataLakeFileSystemClient} used to interact with the renamed file system. - */ - @ServiceMethod(returns = ReturnType.SINGLE) - public DataLakeFileSystemClient rename(String destinationFileSystemName) { - return this.renameWithResponse(new FileSystemRenameOptions(destinationFileSystemName), null, Context.NONE).getValue(); - } - - /** - * Renames an existing file system. - * - *

Code Samples

- * - * - *
-     * DataLakeRequestConditions requestConditions = new DataLakeRequestConditions().setLeaseId("lease-id");
-     * Context context = new Context("Key", "Value");
-     *
-     * DataLakeFileSystemClient fileSystemClient = client.renameWithResponse(
-     *     new FileSystemRenameOptions("newFileSystemName")
-     *         .setRequestConditions(requestConditions),
-     *     Duration.ofSeconds(1),
-     *     context).getValue();
-     * 
- * - * - * @param options {@link FileSystemRenameOptions} - * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. - * @param context Additional context that is passed through the Http pipeline during the service call. - * @return A {@link Response} whose {@link Response#getValue() value} contains a - * {@link DataLakeFileSystemClient} used to interact with the renamed file system. - */ - @ServiceMethod(returns = ReturnType.SINGLE) - public Response renameWithResponse(FileSystemRenameOptions options, - Duration timeout, Context context) { - return DataLakeImplUtils.returnOrConvertException(() -> { - Response response = blobContainerClient - .renameWithResponse(Transforms.toBlobContainerRenameOptions(options), timeout, context); - return new SimpleResponse<>(response, getFileSystemClient(options.getDestinationFileSystemName())); - }, LOGGER); - } - - private DataLakeFileSystemClient getFileSystemClient(String destinationFileSystem) { - return new DataLakeFileSystemClient( - dataLakeFileSystemAsyncClient.getFileSystemAsyncClient(destinationFileSystem), - dataLakeFileSystemAsyncClient.prepareBuilderReplacePath(destinationFileSystem).buildClient()); - } +// DataLakeFileSystemClient rename(String destinationFileSystemName) { +// return this.renameWithResponse(new FileSystemRenameOptions(destinationFileSystemName), null, Context.NONE).getValue(); +// } + +// Response renameWithResponse(FileSystemRenameOptions options, +// Duration timeout, Context context) { +// return DataLakeImplUtils.returnOrConvertException(() -> { +// Response response = blobContainerClient +// .renameWithResponse(Transforms.toBlobContainerRenameOptions(options), timeout, context); +// return new SimpleResponse<>(response, getFileSystemClient(options.getDestinationFileSystemName())); +// }, LOGGER); +// } + +// private DataLakeFileSystemClient getFileSystemClient(String destinationFileSystem) { +// return new DataLakeFileSystemClient( +// dataLakeFileSystemAsyncClient.getFileSystemAsyncClient(destinationFileSystem), +// dataLakeFileSystemAsyncClient.prepareBuilderReplacePath(destinationFileSystem).buildClient()); +// } BlobContainerClient getBlobContainerClient() { return blobContainerClient; diff --git a/sdk/storage/azure-storage-file-datalake/src/samples/java/com/azure/storage/file/datalake/FileSystemAsyncClientJavaDocCodeSamples.java b/sdk/storage/azure-storage-file-datalake/src/samples/java/com/azure/storage/file/datalake/FileSystemAsyncClientJavaDocCodeSamples.java index 21bd00816a1a7..ae8d456ee7772 100644 --- a/sdk/storage/azure-storage-file-datalake/src/samples/java/com/azure/storage/file/datalake/FileSystemAsyncClientJavaDocCodeSamples.java +++ b/sdk/storage/azure-storage-file-datalake/src/samples/java/com/azure/storage/file/datalake/FileSystemAsyncClientJavaDocCodeSamples.java @@ -14,7 +14,6 @@ import com.azure.storage.file.datalake.models.UserDelegationKey; import com.azure.storage.file.datalake.options.DataLakePathCreateOptions; import com.azure.storage.file.datalake.options.DataLakePathDeleteOptions; -import com.azure.storage.file.datalake.options.FileSystemRenameOptions; import com.azure.storage.file.datalake.sas.DataLakeServiceSasSignatureValues; import com.azure.storage.file.datalake.sas.FileSystemSasPermission; import reactor.core.publisher.Mono; @@ -724,27 +723,27 @@ public void deleteDirectoryIfExistsCodeSnippets() { // END: com.azure.storage.file.datalake.DataLakeFileSystemAsyncClient.deleteDirectoryIfExistsWithResponse#String-DataLakePathDeleteOptions } - /** - * Code snippet for {@link DataLakeFileSystemAsyncClient#rename(String)} - */ - public void renameFileSystem() { - // BEGIN: com.azure.storage.file.datalake.DataLakeFileSystemAsyncClient.rename#String - DataLakeFileSystemAsyncClient fileSystemAsyncClient = - client.rename("newFileSystemName") - .block(); - // END: com.azure.storage.file.datalake.DataLakeFileSystemAsyncClient.rename#String - } - - /** - * Code snippet for {@link DataLakeFileSystemAsyncClient#renameWithResponse(FileSystemRenameOptions)} - */ - public void renameFileSystemWithResponse() { - // BEGIN: com.azure.storage.file.datalake.DataLakeFileSystemAsyncClient.renameWithResponse#FileSystemRenameOptions - DataLakeRequestConditions requestConditions = new DataLakeRequestConditions().setLeaseId("lease-id"); - DataLakeFileSystemAsyncClient fileSystemAsyncClient = client - .renameWithResponse(new FileSystemRenameOptions("newFileSystemName") - .setRequestConditions(requestConditions)).block().getValue(); - // END: com.azure.storage.file.datalake.DataLakeFileSystemAsyncClient.renameWithResponse#FileSystemRenameOptions - } +// /** +// * Code snippet for {@link DataLakeFileSystemAsyncClient#rename(String)} +// */ +// public void renameFileSystem() { +// // BEGIN: com.azure.storage.file.datalake.DataLakeFileSystemAsyncClient.rename#String +// DataLakeFileSystemAsyncClient fileSystemAsyncClient = +// client.rename("newFileSystemName") +// .block(); +// // END: com.azure.storage.file.datalake.DataLakeFileSystemAsyncClient.rename#String +// } + +// /** +// * Code snippet for {@link DataLakeFileSystemAsyncClient#renameWithResponse(FileSystemRenameOptions)} +// */ +// public void renameFileSystemWithResponse() { +// // BEGIN: com.azure.storage.file.datalake.DataLakeFileSystemAsyncClient.renameWithResponse#FileSystemRenameOptions +// DataLakeRequestConditions requestConditions = new DataLakeRequestConditions().setLeaseId("lease-id"); +// DataLakeFileSystemAsyncClient fileSystemAsyncClient = client +// .renameWithResponse(new FileSystemRenameOptions("newFileSystemName") +// .setRequestConditions(requestConditions)).block().getValue(); +// // END: com.azure.storage.file.datalake.DataLakeFileSystemAsyncClient.renameWithResponse#FileSystemRenameOptions +// } } diff --git a/sdk/storage/azure-storage-file-datalake/src/samples/java/com/azure/storage/file/datalake/FileSystemClientJavaDocCodeSamples.java b/sdk/storage/azure-storage-file-datalake/src/samples/java/com/azure/storage/file/datalake/FileSystemClientJavaDocCodeSamples.java index e02dfdc9a270e..508cf5d2ebb2b 100644 --- a/sdk/storage/azure-storage-file-datalake/src/samples/java/com/azure/storage/file/datalake/FileSystemClientJavaDocCodeSamples.java +++ b/sdk/storage/azure-storage-file-datalake/src/samples/java/com/azure/storage/file/datalake/FileSystemClientJavaDocCodeSamples.java @@ -18,7 +18,6 @@ import com.azure.storage.file.datalake.models.UserDelegationKey; import com.azure.storage.file.datalake.options.DataLakePathCreateOptions; import com.azure.storage.file.datalake.options.DataLakePathDeleteOptions; -import com.azure.storage.file.datalake.options.FileSystemRenameOptions; import com.azure.storage.file.datalake.sas.DataLakeServiceSasSignatureValues; import com.azure.storage.file.datalake.sas.FileSystemSasPermission; @@ -742,29 +741,29 @@ public void deleteDirectoryIfExistsCodeSnippets() { // END: com.azure.storage.file.datalake.DataLakeFileSystemClient.deleteDirectoryIfExistsWithResponse#String-DataLakePathDeleteOptions-Duration-Context } - /** - * Code snippet for {@link DataLakeFileSystemClient#rename(String)} - */ - public void renameContainer() { - // BEGIN: com.azure.storage.file.datalake.DataLakeFileSystemClient.rename#String - DataLakeFileSystemClient fileSystemClient = client.rename("newFileSystemName"); - // END: com.azure.storage.file.datalake.DataLakeFileSystemClient.rename#String - } - - /** - * Code snippet for {@link DataLakeFileSystemClient#renameWithResponse(FileSystemRenameOptions, Duration, Context)} - */ - public void renameContainerWithResponse() { - // BEGIN: com.azure.storage.file.datalake.DataLakeFileSystemClient.renameWithResponse#FileSystemRenameOptions-Duration-Context - DataLakeRequestConditions requestConditions = new DataLakeRequestConditions().setLeaseId("lease-id"); - Context context = new Context("Key", "Value"); - - DataLakeFileSystemClient fileSystemClient = client.renameWithResponse( - new FileSystemRenameOptions("newFileSystemName") - .setRequestConditions(requestConditions), - Duration.ofSeconds(1), - context).getValue(); - // END: com.azure.storage.file.datalake.DataLakeFileSystemClient.renameWithResponse#FileSystemRenameOptions-Duration-Context - } +// /** +// * Code snippet for {@link DataLakeFileSystemClient#rename(String)} +// */ +// public void renameContainer() { +// // BEGIN: com.azure.storage.file.datalake.DataLakeFileSystemClient.rename#String +// DataLakeFileSystemClient fileSystemClient = client.rename("newFileSystemName"); +// // END: com.azure.storage.file.datalake.DataLakeFileSystemClient.rename#String +// } + +// /** +// * Code snippet for {@link DataLakeFileSystemClient#renameWithResponse(FileSystemRenameOptions, Duration, Context)} +// */ +// public void renameContainerWithResponse() { +// // BEGIN: com.azure.storage.file.datalake.DataLakeFileSystemClient.renameWithResponse#FileSystemRenameOptions-Duration-Context +// DataLakeRequestConditions requestConditions = new DataLakeRequestConditions().setLeaseId("lease-id"); +// Context context = new Context("Key", "Value"); +// +// DataLakeFileSystemClient fileSystemClient = client.renameWithResponse( +// new FileSystemRenameOptions("newFileSystemName") +// .setRequestConditions(requestConditions), +// Duration.ofSeconds(1), +// context).getValue(); +// // END: com.azure.storage.file.datalake.DataLakeFileSystemClient.renameWithResponse#FileSystemRenameOptions-Duration-Context +// } } diff --git a/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/FileSystemAPITest.groovy b/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/FileSystemAPITest.groovy index 186c9eefbd832..534751906fa25 100644 --- a/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/FileSystemAPITest.groovy +++ b/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/FileSystemAPITest.groovy @@ -5,10 +5,6 @@ import com.azure.identity.DefaultAzureCredentialBuilder import com.azure.storage.blob.BlobUrlParts import com.azure.storage.blob.models.BlobErrorCode import com.azure.storage.common.Utility -import com.azure.storage.common.sas.AccountSasPermission -import com.azure.storage.common.sas.AccountSasResourceType -import com.azure.storage.common.sas.AccountSasService -import com.azure.storage.common.sas.AccountSasSignatureValues import com.azure.storage.common.test.shared.extensions.RequiredServiceVersion import com.azure.storage.common.test.shared.extensions.PlaybackOnly import com.azure.storage.file.datalake.models.DataLakeAccessPolicy @@ -2759,115 +2755,115 @@ class FileSystemAPITest extends APISpec { response.getHeaders().getValue("x-ms-version") == "2019-02-02" } - def "Rename"() { - setup: - def newName = generateFileSystemName() - - when: - def renamedContainer = fsc.rename(newName) - - then: - renamedContainer.getPropertiesWithResponse(null, null, null).getStatusCode() == 200 - - cleanup: - renamedContainer.delete() - } - - def "Rename sas"() { - setup: - def service = new AccountSasService() - .setBlobAccess(true) - def resourceType = new AccountSasResourceType() - .setContainer(true) - .setService(true) - .setObject(true) - def permissions = new AccountSasPermission() - .setReadPermission(true) - .setCreatePermission(true) - .setWritePermission(true) - .setDeletePermission(true) - def expiryTime = namer.getUtcNow().plusDays(1) - - def newName = generateFileSystemName() - def sasValues = new AccountSasSignatureValues(expiryTime, permissions, service, resourceType) - def sas = primaryDataLakeServiceClient.generateAccountSas(sasValues) - def sasClient = getFileSystemClient(sas, fsc.getFileSystemUrl()) - - when: - def renamedContainer = sasClient.rename(newName) - - then: - renamedContainer.getPropertiesWithResponse(null, null, null).getStatusCode() == 200 - - cleanup: - renamedContainer.delete() - } - - @Unroll - def "Rename AC"() { - setup: - leaseID = setupFileSystemLeaseCondition(fsc, leaseID) - def cac = new DataLakeRequestConditions() - .setLeaseId(leaseID) - - expect: - fsc.renameWithResponse(new FileSystemRenameOptions(generateFileSystemName()).setRequestConditions(cac), - null, null).getStatusCode() == 200 - - where: - leaseID || _ - null || _ - receivedLeaseID || _ - } - - @Unroll - def "Rename AC fail"() { - setup: - def cac = new DataLakeRequestConditions() - .setLeaseId(leaseID) - - when: - fsc.renameWithResponse(new FileSystemRenameOptions(generateFileSystemName()).setRequestConditions(cac), - null, null) - - then: - thrown(DataLakeStorageException) - - where: - leaseID || _ - garbageLeaseID || _ - } - - @Unroll - def "Rename AC illegal"() { - setup: - def ac = new DataLakeRequestConditions().setIfMatch(match).setIfNoneMatch(noneMatch).setIfModifiedSince(modified).setIfUnmodifiedSince(unmodified) - - when: - fsc.renameWithResponse(new FileSystemRenameOptions(generateFileSystemName()).setRequestConditions(ac), - null, null) - - then: - thrown(UnsupportedOperationException) - - where: - modified | unmodified | match | noneMatch - oldDate | null | null | null - null | newDate | null | null - null | null | receivedEtag | null - null | null | null | garbageEtag - } - - def "Rename error"() { - setup: - fsc = primaryDataLakeServiceClient.getFileSystemClient(generateFileSystemName()) - def newName = generateFileSystemName() - - when: - fsc.rename(newName) - - then: - thrown(DataLakeStorageException) - } +// def "Rename"() { +// setup: +// def newName = generateFileSystemName() +// +// when: +// def renamedContainer = fsc.rename(newName) +// +// then: +// renamedContainer.getPropertiesWithResponse(null, null, null).getStatusCode() == 200 +// +// cleanup: +// renamedContainer.delete() +// } + +// def "Rename sas"() { +// setup: +// def service = new AccountSasService() +// .setBlobAccess(true) +// def resourceType = new AccountSasResourceType() +// .setContainer(true) +// .setService(true) +// .setObject(true) +// def permissions = new AccountSasPermission() +// .setReadPermission(true) +// .setCreatePermission(true) +// .setWritePermission(true) +// .setDeletePermission(true) +// def expiryTime = namer.getUtcNow().plusDays(1) +// +// def newName = generateFileSystemName() +// def sasValues = new AccountSasSignatureValues(expiryTime, permissions, service, resourceType) +// def sas = primaryDataLakeServiceClient.generateAccountSas(sasValues) +// def sasClient = getFileSystemClient(sas, fsc.getFileSystemUrl()) +// +// when: +// def renamedContainer = sasClient.rename(newName) +// +// then: +// renamedContainer.getPropertiesWithResponse(null, null, null).getStatusCode() == 200 +// +// cleanup: +// renamedContainer.delete() +// } + +// @Unroll +// def "Rename AC"() { +// setup: +// leaseID = setupFileSystemLeaseCondition(fsc, leaseID) +// def cac = new DataLakeRequestConditions() +// .setLeaseId(leaseID) +// +// expect: +// fsc.renameWithResponse(new FileSystemRenameOptions(generateFileSystemName()).setRequestConditions(cac), +// null, null).getStatusCode() == 200 +// +// where: +// leaseID || _ +// null || _ +// receivedLeaseID || _ +// } + +// @Unroll +// def "Rename AC fail"() { +// setup: +// def cac = new DataLakeRequestConditions() +// .setLeaseId(leaseID) +// +// when: +// fsc.renameWithResponse(new FileSystemRenameOptions(generateFileSystemName()).setRequestConditions(cac), +// null, null) +// +// then: +// thrown(DataLakeStorageException) +// +// where: +// leaseID || _ +// garbageLeaseID || _ +// } + +// @Unroll +// def "Rename AC illegal"() { +// setup: +// def ac = new DataLakeRequestConditions().setIfMatch(match).setIfNoneMatch(noneMatch).setIfModifiedSince(modified).setIfUnmodifiedSince(unmodified) +// +// when: +// fsc.renameWithResponse(new FileSystemRenameOptions(generateFileSystemName()).setRequestConditions(ac), +// null, null) +// +// then: +// thrown(UnsupportedOperationException) +// +// where: +// modified | unmodified | match | noneMatch +// oldDate | null | null | null +// null | newDate | null | null +// null | null | receivedEtag | null +// null | null | null | garbageEtag +// } + +// def "Rename error"() { +// setup: +// fsc = primaryDataLakeServiceClient.getFileSystemClient(generateFileSystemName()) +// def newName = generateFileSystemName() +// +// when: +// fsc.rename(newName) +// +// then: +// thrown(DataLakeStorageException) +// } } diff --git a/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRename.json b/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRename.json deleted file mode 100644 index 52608581eab0c..0000000000000 --- a/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRename.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "networkCallRecords" : [ { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/9e430f7009e430f7062c13438e2b13aaba587429a97a?restype=container", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 azsdk-java-azure-storage-file-datalake/12.13.0-beta.1 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "d7e6dddb-b64a-4336-9b3c-31e9c304eac2" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "eTag" : "0x8DA89F8AE8027B5", - "Last-Modified" : "Mon, 29 Aug 2022 19:57:19 GMT", - "retry-after" : "0", - "StatusCode" : "201", - "x-ms-request-id" : "8ae425fc-701e-0011-4be1-bb4076000000", - "x-ms-client-request-id" : "d7e6dddb-b64a-4336-9b3c-31e9c304eac2", - "Date" : "Mon, 29 Aug 2022 19:57:19 GMT" - }, - "Exception" : null - }, { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/9e430f7019e430f7062c05162298f0d55004b47fdba3?restype=container&comp=rename", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 azsdk-java-azure-storage-file-datalake/12.13.0-beta.1 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "bb07a887-9bb8-4984-a12f-ab46c757d68c" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "retry-after" : "0", - "StatusCode" : "200", - "x-ms-request-id" : "6a71dfd4-001e-0079-49e1-bb26e6000000", - "x-ms-client-request-id" : "bb07a887-9bb8-4984-a12f-ab46c757d68c", - "Date" : "Mon, 29 Aug 2022 19:57:21 GMT" - }, - "Exception" : null - }, { - "Method" : "GET", - "Uri" : "https://REDACTED.blob.core.windows.net/9e430f7019e430f7062c05162298f0d55004b47fdba3?restype=container", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-file-datalake/12.13.0-beta.1 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "88b42515-ce1b-4c48-9e9d-9d08d5c05a13" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "x-ms-lease-status" : "unlocked", - "x-ms-immutable-storage-with-versioning-enabled" : "false", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-lease-state" : "available", - "x-ms-deny-encryption-scope-override" : "false", - "Last-Modified" : "Mon, 29 Aug 2022 19:57:21 GMT", - "retry-after" : "0", - "StatusCode" : "200", - "x-ms-has-legal-hold" : "false", - "Date" : "Mon, 29 Aug 2022 19:57:21 GMT", - "x-ms-default-encryption-scope" : "$account-encryption-key", - "x-ms-has-immutability-policy" : "false", - "eTag" : "0x8DA89F8AF358579", - "x-ms-request-id" : "6a71e309-001e-0079-79e1-bb26e6000000", - "x-ms-client-request-id" : "88b42515-ce1b-4c48-9e9d-9d08d5c05a13" - }, - "Exception" : null - }, { - "Method" : "DELETE", - "Uri" : "https://REDACTED.blob.core.windows.net/9e430f7019e430f7062c05162298f0d55004b47fdba3?restype=container", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-file-datalake/12.13.0-beta.1 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "e2c8a93a-b503-478a-bab8-2a4c491acad0" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "retry-after" : "0", - "StatusCode" : "202", - "x-ms-request-id" : "6a71e337-001e-0079-1be1-bb26e6000000", - "x-ms-client-request-id" : "e2c8a93a-b503-478a-bab8-2a4c491acad0", - "Date" : "Mon, 29 Aug 2022 19:57:21 GMT" - }, - "Exception" : null - } ], - "variables" : [ "9e430f7009e430f7062c13438e2b13aaba587429a97a", "9e430f7019e430f7062c05162298f0d55004b47fdba3" ] -} \ No newline at end of file diff --git a/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRenameACFail[0].json b/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRenameACFail[0].json deleted file mode 100644 index 3203dc7d6d1c6..0000000000000 --- a/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRenameACFail[0].json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "networkCallRecords" : [ { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/582a149a0582a149ae9a09141ec1291250ed549048ed?restype=container", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 azsdk-java-azure-storage-file-datalake/12.13.0-beta.2 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "064aec13-cd7f-4430-8968-4ea551494c29" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "eTag" : "0x8DA8A1C4D90F554", - "Last-Modified" : "Tue, 30 Aug 2022 00:12:19 GMT", - "retry-after" : "0", - "StatusCode" : "201", - "x-ms-request-id" : "33a2b645-301e-0096-7105-bcd313000000", - "x-ms-client-request-id" : "064aec13-cd7f-4430-8968-4ea551494c29", - "Date" : "Tue, 30 Aug 2022 00:12:18 GMT" - }, - "Exception" : null - }, { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/582a149a1582a149ae9a9787432ca1a15b6eb44348bb?restype=container&comp=rename", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 azsdk-java-azure-storage-file-datalake/12.13.0-beta.2 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "878a8ef4-2add-4e7b-bcef-625d7b2d480e" - }, - "Response" : { - "content-length" : "252", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-error-code" : "LeaseNotPresentWithContainerOperation", - "retry-after" : "0", - "StatusCode" : "412", - "x-ms-request-id" : "33a2b6b1-301e-0096-4905-bcd313000000", - "Body" : "\nLeaseNotPresentWithContainerOperationThere is currently no lease on the container.\nRequestId:33a2b6b1-301e-0096-4905-bcd313000000\nTime:2022-08-30T00:12:20.6460978Z", - "x-ms-client-request-id" : "878a8ef4-2add-4e7b-bcef-625d7b2d480e", - "Date" : "Tue, 30 Aug 2022 00:12:19 GMT", - "Content-Type" : "application/xml" - }, - "Exception" : null - } ], - "variables" : [ "582a149a0582a149ae9a09141ec1291250ed549048ed", "582a149a1582a149ae9a9787432ca1a15b6eb44348bb" ] -} \ No newline at end of file diff --git a/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRenameACIllegal[0].json b/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRenameACIllegal[0].json deleted file mode 100644 index 49b483c3b266f..0000000000000 --- a/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRenameACIllegal[0].json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "networkCallRecords" : [ { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/b3c569000b3c569009b71630094cc6c53ccfd4b2a887?restype=container", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 azsdk-java-azure-storage-file-datalake/12.13.0-beta.1 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "b6cdb4d7-8aac-407c-8e0c-f62e61798eb8" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "eTag" : "0x8DA8A04E18C3184", - "Last-Modified" : "Mon, 29 Aug 2022 21:24:39 GMT", - "retry-after" : "0", - "StatusCode" : "201", - "x-ms-request-id" : "80c97e31-101e-0091-06ed-bbbf70000000", - "x-ms-client-request-id" : "b6cdb4d7-8aac-407c-8e0c-f62e61798eb8", - "Date" : "Mon, 29 Aug 2022 21:24:39 GMT" - }, - "Exception" : null - } ], - "variables" : [ "b3c569000b3c569009b71630094cc6c53ccfd4b2a887", "b3c569001b3c569009b766375bc10d7920b9f4c4daff" ] -} \ No newline at end of file diff --git a/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRenameACIllegal[1].json b/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRenameACIllegal[1].json deleted file mode 100644 index a62a5a0f4b831..0000000000000 --- a/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRenameACIllegal[1].json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "networkCallRecords" : [ { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/aade58410aade5841bad13201c3238934911f4b43a64?restype=container", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 azsdk-java-azure-storage-file-datalake/12.13.0-beta.1 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "ebd06352-6172-4afa-ba40-944bc54cd8ee" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "eTag" : "0x8DA8A04E18CB241", - "Last-Modified" : "Mon, 29 Aug 2022 21:24:39 GMT", - "retry-after" : "0", - "StatusCode" : "201", - "x-ms-request-id" : "4edfc84e-801e-0048-32ed-bbc7f5000000", - "x-ms-client-request-id" : "ebd06352-6172-4afa-ba40-944bc54cd8ee", - "Date" : "Mon, 29 Aug 2022 21:24:39 GMT" - }, - "Exception" : null - } ], - "variables" : [ "aade58410aade5841bad13201c3238934911f4b43a64", "aade58411aade5841bad822999176775eb90446079ff" ] -} \ No newline at end of file diff --git a/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRenameACIllegal[2].json b/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRenameACIllegal[2].json deleted file mode 100644 index 97edd1ed4e827..0000000000000 --- a/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRenameACIllegal[2].json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "networkCallRecords" : [ { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/81f30b82081f30b82e0853448a1e20400c02c403585d?restype=container", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 azsdk-java-azure-storage-file-datalake/12.13.0-beta.1 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "a76d8114-dc79-41e5-a08c-bc1c18620e69" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "eTag" : "0x8DA8A04E18C8B09", - "Last-Modified" : "Mon, 29 Aug 2022 21:24:39 GMT", - "retry-after" : "0", - "StatusCode" : "201", - "x-ms-request-id" : "01ba6878-b01e-007c-63ed-bbf43d000000", - "x-ms-client-request-id" : "a76d8114-dc79-41e5-a08c-bc1c18620e69", - "Date" : "Mon, 29 Aug 2022 21:24:39 GMT" - }, - "Exception" : null - } ], - "variables" : [ "81f30b82081f30b82e0853448a1e20400c02c403585d", "81f30b82181f30b82e08106528c67c05289b747dd8b6" ] -} \ No newline at end of file diff --git a/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRenameACIllegal[3].json b/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRenameACIllegal[3].json deleted file mode 100644 index 4810fae19a298..0000000000000 --- a/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRenameACIllegal[3].json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "networkCallRecords" : [ { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/98e83ac3098e83ac311134268f5d73c90094b45d7ad8?restype=container", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 azsdk-java-azure-storage-file-datalake/12.13.0-beta.1 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "5d4bbcce-fc3d-4d9b-bf23-7534b3a21a19" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "eTag" : "0x8DA8A04E18C9FD2", - "Last-Modified" : "Mon, 29 Aug 2022 21:24:39 GMT", - "retry-after" : "0", - "StatusCode" : "201", - "x-ms-request-id" : "c7a6e2c4-a01e-0002-50ed-bb647a000000", - "x-ms-client-request-id" : "5d4bbcce-fc3d-4d9b-bf23-7534b3a21a19", - "Date" : "Mon, 29 Aug 2022 21:24:38 GMT" - }, - "Exception" : null - } ], - "variables" : [ "98e83ac3098e83ac311134268f5d73c90094b45d7ad8", "98e83ac3198e83ac3111104925f2c3c4c4a9d403aaa7" ] -} \ No newline at end of file diff --git a/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRenameAC[0].json b/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRenameAC[0].json deleted file mode 100644 index 24d6099f34ed8..0000000000000 --- a/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRenameAC[0].json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "networkCallRecords" : [ { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/bccacf480bccacf48c0e7029900d3ce1aea314eccb54?restype=container", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 azsdk-java-azure-storage-file-datalake/12.13.0-beta.1 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "b5536b22-7ffc-4903-9d15-19239202371b" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "eTag" : "0x8DA89F8AE8019A5", - "Last-Modified" : "Mon, 29 Aug 2022 19:57:19 GMT", - "retry-after" : "0", - "StatusCode" : "201", - "x-ms-request-id" : "25c29c90-401e-0078-1ce1-bb793a000000", - "x-ms-client-request-id" : "b5536b22-7ffc-4903-9d15-19239202371b", - "Date" : "Mon, 29 Aug 2022 19:57:19 GMT" - }, - "Exception" : null - }, { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/bccacf481bccacf48c0e66951a2e9942b11af46909bf?restype=container&comp=rename", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 azsdk-java-azure-storage-file-datalake/12.13.0-beta.1 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "9e0ff522-7300-45bb-afe0-4c2531affd9b" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "retry-after" : "0", - "StatusCode" : "200", - "x-ms-request-id" : "8ae42624-701e-0011-6de1-bb4076000000", - "x-ms-client-request-id" : "9e0ff522-7300-45bb-afe0-4c2531affd9b", - "Date" : "Mon, 29 Aug 2022 19:57:22 GMT" - }, - "Exception" : null - } ], - "variables" : [ "bccacf480bccacf48c0e7029900d3ce1aea314eccb54", "bccacf481bccacf48c0e66951a2e9942b11af46909bf" ] -} \ No newline at end of file diff --git a/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRenameAC[1].json b/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRenameAC[1].json deleted file mode 100644 index 34710ac1eb0be..0000000000000 --- a/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRenameAC[1].json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "networkCallRecords" : [ { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/a5d1fe090a5d1fe092eb94985f0f908a9a3e341dab89?restype=container", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 azsdk-java-azure-storage-file-datalake/12.13.0-beta.1 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "4904ca6b-88e7-4786-bf29-71ad24f68c07" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "eTag" : "0x8DA89F8AE801998", - "Last-Modified" : "Mon, 29 Aug 2022 19:57:19 GMT", - "retry-after" : "0", - "StatusCode" : "201", - "x-ms-request-id" : "e7c5ceb7-001e-0024-17e1-bb2c62000000", - "x-ms-client-request-id" : "4904ca6b-88e7-4786-bf29-71ad24f68c07", - "Date" : "Mon, 29 Aug 2022 19:57:19 GMT" - }, - "Exception" : null - }, { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/a5d1fe090a5d1fe092eb94985f0f908a9a3e341dab89?comp=lease&restype=container", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-file-datalake/12.13.0-beta.1 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "7f245f37-4ee1-48ed-bc12-428b0e8584a1" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-lease-id" : "30d82a3e-9c3e-450a-80b0-de27fa647c9e", - "eTag" : "0x8DA89F8AE801998", - "Last-Modified" : "Mon, 29 Aug 2022 19:57:19 GMT", - "retry-after" : "0", - "StatusCode" : "201", - "x-ms-request-id" : "25c29d47-401e-0078-43e1-bb793a000000", - "x-ms-client-request-id" : "7f245f37-4ee1-48ed-bc12-428b0e8584a1", - "Date" : "Mon, 29 Aug 2022 19:57:19 GMT" - }, - "Exception" : null - }, { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/a5d1fe091a5d1fe092eb62165abedde9166b0495793f?restype=container&comp=rename", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 azsdk-java-azure-storage-file-datalake/12.13.0-beta.1 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "76838022-df18-4ecc-85a1-dc9ac8014645" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "retry-after" : "0", - "StatusCode" : "200", - "x-ms-request-id" : "25c29d84-401e-0078-7ee1-bb793a000000", - "x-ms-client-request-id" : "76838022-df18-4ecc-85a1-dc9ac8014645", - "Date" : "Mon, 29 Aug 2022 19:57:21 GMT" - }, - "Exception" : null - } ], - "variables" : [ "a5d1fe090a5d1fe092eb94985f0f908a9a3e341dab89", "a5d1fe091a5d1fe092eb62165abedde9166b0495793f" ] -} \ No newline at end of file diff --git a/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRenameError.json b/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRenameError.json deleted file mode 100644 index c829cc5621499..0000000000000 --- a/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRenameError.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "networkCallRecords" : [ { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/a0b3f7e10a0b3f7e16fc3973528e758338af7497abe3?restype=container", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 azsdk-java-azure-storage-file-datalake/12.13.0-beta.1 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "1727a741-3f26-4daa-8c71-eacc4c2c1280" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "eTag" : "0x8DA8A00390B9876", - "Last-Modified" : "Mon, 29 Aug 2022 20:51:18 GMT", - "retry-after" : "0", - "StatusCode" : "201", - "x-ms-request-id" : "77b6774d-901e-006b-24e9-bb5d36000000", - "x-ms-client-request-id" : "1727a741-3f26-4daa-8c71-eacc4c2c1280", - "Date" : "Mon, 29 Aug 2022 20:51:18 GMT" - }, - "Exception" : null - }, { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/a0b3f7e12a0b3f7e16fc3454491209e95887d4124829?restype=container&comp=rename", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 azsdk-java-azure-storage-file-datalake/12.13.0-beta.1 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "ecb76597-553c-4b06-a32d-1c1cbecaf40a" - }, - "Response" : { - "content-length" : "226", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-error-code" : "ContainerNotFound", - "retry-after" : "0", - "StatusCode" : "404", - "x-ms-request-id" : "77b677b7-901e-006b-01e9-bb5d36000000", - "Body" : "\nContainerNotFoundThe specified container does not exist.\nRequestId:77b677b7-901e-006b-01e9-bb5d36000000\nTime:2022-08-29T20:51:21.5794976Z", - "x-ms-client-request-id" : "ecb76597-553c-4b06-a32d-1c1cbecaf40a", - "Date" : "Mon, 29 Aug 2022 20:51:20 GMT", - "Content-Type" : "application/xml" - }, - "Exception" : null - } ], - "variables" : [ "a0b3f7e10a0b3f7e16fc3973528e758338af7497abe3", "a0b3f7e11a0b3f7e16fc78352d6b2504480e14e35b4c", "a0b3f7e12a0b3f7e16fc3454491209e95887d4124829" ] -} \ No newline at end of file diff --git a/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRenameSas.json b/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRenameSas.json deleted file mode 100644 index 2fd92f0082cf3..0000000000000 --- a/sdk/storage/azure-storage-file-datalake/src/test/resources/session-records/FileSystemAPITestRenameSas.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "networkCallRecords" : [ { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/18ed57b0018ed57b0ae592810fa6a3ff132ea4d68a50?restype=container", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 azsdk-java-azure-storage-file-datalake/12.13.0-beta.1 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "1f494353-a756-4a73-a78f-17104a9e5c5e" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "eTag" : "0x8DA89F8AE82713C", - "Last-Modified" : "Mon, 29 Aug 2022 19:57:19 GMT", - "retry-after" : "0", - "StatusCode" : "201", - "x-ms-request-id" : "6a71df75-001e-0079-7ee1-bb26e6000000", - "x-ms-client-request-id" : "1f494353-a756-4a73-a78f-17104a9e5c5e", - "Date" : "Mon, 29 Aug 2022 19:57:19 GMT" - }, - "Exception" : null - }, { - "Method" : "PUT", - "Uri" : "https://REDACTED.blob.core.windows.net/18ed57b0118ed57b0ae595216958861d123b24f579cb?restype=container&comp=rename&sv=2021-10-04&ss=b&srt=sco&se=2022-08-30T19%3A57%3A19Z&sp=rwdc&sig=REDACTED", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-blob/12.20.0-beta.2 azsdk-java-azure-storage-file-datalake/12.13.0-beta.1 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "0f1780e2-ff86-4006-8e74-fa0b20feba2d" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "retry-after" : "0", - "StatusCode" : "200", - "x-ms-request-id" : "e7c5cf02-001e-0024-55e1-bb2c62000000", - "x-ms-client-request-id" : "0f1780e2-ff86-4006-8e74-fa0b20feba2d", - "Date" : "Mon, 29 Aug 2022 19:57:20 GMT" - }, - "Exception" : null - }, { - "Method" : "GET", - "Uri" : "https://REDACTED.blob.core.windows.net/18ed57b0118ed57b0ae595216958861d123b24f579cb?restype=container&sv=2021-10-04&ss=b&srt=sco&se=2022-08-30T19%3A57%3A19Z&sp=rwdc&sig=REDACTED", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-file-datalake/12.13.0-beta.1 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "46ca0b66-7c1d-4bc8-88e8-7f8e0e252c40" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "x-ms-lease-status" : "unlocked", - "x-ms-immutable-storage-with-versioning-enabled" : "false", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "x-ms-lease-state" : "available", - "x-ms-deny-encryption-scope-override" : "false", - "Last-Modified" : "Mon, 29 Aug 2022 19:57:20 GMT", - "retry-after" : "0", - "StatusCode" : "200", - "x-ms-has-legal-hold" : "false", - "Date" : "Mon, 29 Aug 2022 19:57:20 GMT", - "x-ms-default-encryption-scope" : "$account-encryption-key", - "x-ms-has-immutability-policy" : "false", - "eTag" : "0x8DA89F8AEB89E96", - "x-ms-request-id" : "e7c5cfa2-001e-0024-63e1-bb2c62000000", - "x-ms-client-request-id" : "46ca0b66-7c1d-4bc8-88e8-7f8e0e252c40" - }, - "Exception" : null - }, { - "Method" : "DELETE", - "Uri" : "https://REDACTED.blob.core.windows.net/18ed57b0118ed57b0ae595216958861d123b24f579cb?restype=container&sv=2021-10-04&ss=b&srt=sco&se=2022-08-30T19%3A57%3A19Z&sp=rwdc&sig=REDACTED", - "Headers" : { - "x-ms-version" : "2021-10-04", - "User-Agent" : "azsdk-java-azure-storage-file-datalake/12.13.0-beta.1 (11.0.14; Windows 10; 10.0)", - "x-ms-client-request-id" : "34939e24-622d-4c61-91e7-bacb34f20cf5" - }, - "Response" : { - "content-length" : "0", - "x-ms-version" : "2021-10-04", - "Server" : "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", - "retry-after" : "0", - "StatusCode" : "202", - "x-ms-request-id" : "e7c5cfc2-001e-0024-7ee1-bb2c62000000", - "x-ms-client-request-id" : "34939e24-622d-4c61-91e7-bacb34f20cf5", - "Date" : "Mon, 29 Aug 2022 19:57:20 GMT" - }, - "Exception" : null - } ], - "variables" : [ "18ed57b0018ed57b0ae592810fa6a3ff132ea4d68a50", "2022-08-29T19:57:19.965086800Z", "18ed57b0118ed57b0ae595216958861d123b24f579cb" ] -} \ No newline at end of file diff --git a/sdk/textanalytics/azure-ai-textanalytics/CHANGELOG.md b/sdk/textanalytics/azure-ai-textanalytics/CHANGELOG.md index 5ddeb0ec44496..d6e511c23e679 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/CHANGELOG.md +++ b/sdk/textanalytics/azure-ai-textanalytics/CHANGELOG.md @@ -3,6 +3,16 @@ ## 5.2.0-beta.5 (Unreleased) ### Features Added +- Added `displayName` property which is the name of long-running operation, to the following classes to + set the optional display name: + - `AnalyzeHealthcareEntitiesOptions` + - `MultiLabelClassifyOptions` + - `RecognizeCustomEntitiesOptions` + - `SingleLabelClassifyOptions` +- Added `displayName` property to the following operations to read the optional display name set on options classes above: + - `AnalyzeHealthcareEntitiesOperationDetail` from `AnalyzeHealthcareEntitiesOptions` + - `ClassifyDocumentOperationDetail` from `MultiLabelClassifyOptions` and `SingleLabelClassifyOptions` + - `RecognizeCustomEntitiesOperationDetail` from `RecognizeCustomEntitiesOptions` ### Breaking Changes diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/AnalyzeActionsAsyncClient.java b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/AnalyzeActionsAsyncClient.java index 3717d10565caa..ec8089916f2db 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/AnalyzeActionsAsyncClient.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/AnalyzeActionsAsyncClient.java @@ -134,9 +134,11 @@ import static com.azure.ai.textanalytics.TextAnalyticsAsyncClient.COGNITIVE_TRACING_NAMESPACE_VALUE; import static com.azure.ai.textanalytics.implementation.Utility.DEFAULT_POLL_INTERVAL; +import static com.azure.ai.textanalytics.implementation.Utility.getUnsupportedServiceApiVersionMessage; import static com.azure.ai.textanalytics.implementation.Utility.inputDocumentsValidation; import static com.azure.ai.textanalytics.implementation.Utility.parseNextLink; import static com.azure.ai.textanalytics.implementation.Utility.parseOperationId; +import static com.azure.ai.textanalytics.implementation.Utility.throwIfTargetServiceVersionFound; import static com.azure.ai.textanalytics.implementation.Utility.toAnalyzeHealthcareEntitiesResultCollection; import static com.azure.ai.textanalytics.implementation.Utility.toAnalyzeSentimentResultCollection; import static com.azure.ai.textanalytics.implementation.Utility.toCategoriesFilter; @@ -174,19 +176,24 @@ class AnalyzeActionsAsyncClient { private final ClientLogger logger = new ClientLogger(AnalyzeActionsAsyncClient.class); private final TextAnalyticsClientImpl legacyService; private final AnalyzeTextsImpl service; + + private final TextAnalyticsServiceVersion serviceVersion; + private static final Pattern PATTERN; static { PATTERN = Pattern.compile(REGEX_ACTION_ERROR_TARGET, Pattern.MULTILINE); } - AnalyzeActionsAsyncClient(TextAnalyticsClientImpl legacyService) { + AnalyzeActionsAsyncClient(TextAnalyticsClientImpl legacyService, TextAnalyticsServiceVersion serviceVersion) { this.legacyService = legacyService; this.service = null; + this.serviceVersion = serviceVersion; } - AnalyzeActionsAsyncClient(AnalyzeTextsImpl service) { + AnalyzeActionsAsyncClient(AnalyzeTextsImpl service, TextAnalyticsServiceVersion serviceVersion) { this.legacyService = null; this.service = service; + this.serviceVersion = serviceVersion; } PollerFlux beginAnalyzeActions( @@ -194,6 +201,9 @@ PollerFlux beginAn Context context) { try { Objects.requireNonNull(actions, "'actions' cannot be null."); + throwIfTargetServiceVersionFound(this.serviceVersion, Arrays.asList(TextAnalyticsServiceVersion.V3_0), + getUnsupportedServiceApiVersionMessage("beginAnalyzeActions", serviceVersion, + TextAnalyticsServiceVersion.V3_1)); inputDocumentsValidation(documents); options = getNotNullAnalyzeActionsOptions(options); final Context finalContext = getNotNullContext(context) @@ -229,6 +239,8 @@ PollerFlux beginAn ); } + throwIfTargetServiceVersionFoundForActions(this.serviceVersion, + Arrays.asList(TextAnalyticsServiceVersion.V3_0, TextAnalyticsServiceVersion.V3_1), actions); final AnalyzeBatchInput analyzeBatchInput = new AnalyzeBatchInput() .setAnalysisInput(new MultiLanguageBatchInput().setDocuments(toMultiLanguageInput(documents))) @@ -263,6 +275,9 @@ PollerFlux beg Context context) { try { Objects.requireNonNull(actions, "'actions' cannot be null."); + throwIfTargetServiceVersionFound(this.serviceVersion, Arrays.asList(TextAnalyticsServiceVersion.V3_0), + getUnsupportedServiceApiVersionMessage("beginAnalyzeActions", serviceVersion, + TextAnalyticsServiceVersion.V3_1)); inputDocumentsValidation(documents); options = getNotNullAnalyzeActionsOptions(options); final Context finalContext = getNotNullContext(context) @@ -301,6 +316,8 @@ PollerFlux beg ); } + throwIfTargetServiceVersionFoundForActions(this.serviceVersion, + Arrays.asList(TextAnalyticsServiceVersion.V3_0, TextAnalyticsServiceVersion.V3_1), actions); return new PollerFlux<>( DEFAULT_POLL_INTERVAL, activationOperation( @@ -1284,4 +1301,31 @@ private String[] parseActionErrorTarget(String targetReference, String errorMess } return taskNameIdPair; } + + private void throwIfTargetServiceVersionFoundForActions(TextAnalyticsServiceVersion sourceVersion, + List targetVersions, TextAnalyticsActions actions) { + if (actions.getMultiLabelClassifyActions() != null) { + throwIfTargetServiceVersionFound(sourceVersion, targetVersions, + getUnsupportedServiceApiVersionMessage("MultiLabelClassifyAction", serviceVersion, + TextAnalyticsServiceVersion.V2022_05_01)); + } + + if (actions.getSingleLabelClassifyActions() != null) { + throwIfTargetServiceVersionFound(sourceVersion, targetVersions, + getUnsupportedServiceApiVersionMessage("SingleLabelClassifyAction", serviceVersion, + TextAnalyticsServiceVersion.V2022_05_01)); + } + + if (actions.getRecognizeCustomEntitiesActions() != null) { + throwIfTargetServiceVersionFound(sourceVersion, targetVersions, + getUnsupportedServiceApiVersionMessage("RecognizeCustomEntitiesAction", serviceVersion, + TextAnalyticsServiceVersion.V2022_05_01)); + } + + if (actions.getAnalyzeHealthcareEntitiesActions() != null) { + throwIfTargetServiceVersionFound(sourceVersion, targetVersions, + getUnsupportedServiceApiVersionMessage("AnalyzeHealthcareEntitiesAction", serviceVersion, + TextAnalyticsServiceVersion.V2022_05_01)); + } + } } diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/AnalyzeHealthcareEntityAsyncClient.java b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/AnalyzeHealthcareEntityAsyncClient.java index 3e216d0172a8a..9183799bae480 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/AnalyzeHealthcareEntityAsyncClient.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/AnalyzeHealthcareEntityAsyncClient.java @@ -58,9 +58,11 @@ import static com.azure.ai.textanalytics.TextAnalyticsAsyncClient.COGNITIVE_TRACING_NAMESPACE_VALUE; import static com.azure.ai.textanalytics.implementation.Utility.DEFAULT_POLL_INTERVAL; import static com.azure.ai.textanalytics.implementation.Utility.getNotNullContext; +import static com.azure.ai.textanalytics.implementation.Utility.getUnsupportedServiceApiVersionMessage; import static com.azure.ai.textanalytics.implementation.Utility.inputDocumentsValidation; import static com.azure.ai.textanalytics.implementation.Utility.parseNextLink; import static com.azure.ai.textanalytics.implementation.Utility.parseOperationId; +import static com.azure.ai.textanalytics.implementation.Utility.throwIfTargetServiceVersionFound; import static com.azure.ai.textanalytics.implementation.Utility.toAnalyzeHealthcareEntitiesResultCollection; import static com.azure.ai.textanalytics.implementation.Utility.toMultiLanguageInput; import static com.azure.ai.textanalytics.implementation.models.State.CANCELLED; @@ -75,20 +77,30 @@ class AnalyzeHealthcareEntityAsyncClient { private final TextAnalyticsClientImpl legacyService; private final AnalyzeTextsImpl service; - AnalyzeHealthcareEntityAsyncClient(TextAnalyticsClientImpl legacyService) { + private final TextAnalyticsServiceVersion serviceVersion; + + AnalyzeHealthcareEntityAsyncClient(TextAnalyticsClientImpl legacyService, + TextAnalyticsServiceVersion serviceVersion) { this.legacyService = legacyService; this.service = null; + this.serviceVersion = serviceVersion; } - AnalyzeHealthcareEntityAsyncClient(AnalyzeTextsImpl service) { + AnalyzeHealthcareEntityAsyncClient(AnalyzeTextsImpl service, TextAnalyticsServiceVersion serviceVersion) { this.legacyService = null; this.service = service; + this.serviceVersion = serviceVersion; } PollerFlux beginAnalyzeHealthcareEntities(Iterable documents, AnalyzeHealthcareEntitiesOptions options, Context context) { try { + throwIfTargetServiceVersionFound(this.serviceVersion, + Arrays.asList(TextAnalyticsServiceVersion.V3_0), + getUnsupportedServiceApiVersionMessage("beginAnalyzeHealthcareEntities", serviceVersion, + TextAnalyticsServiceVersion.V3_1)); + throwIfCallingNotAvailableFeatureInOptions(options); inputDocumentsValidation(documents); options = getNotNullAnalyzeHealthcareEntitiesOptions(options); final Context finalContext = getNotNullContext(context) @@ -99,11 +111,13 @@ class AnalyzeHealthcareEntityAsyncClient { final boolean finalLoggingOptOut = options.isServiceLogsDisabled(); if (service != null) { + final String displayName = options.getDisplayName(); return new PollerFlux<>( DEFAULT_POLL_INTERVAL, activationOperation( service.submitJobWithResponseAsync( new AnalyzeTextJobsInput() + .setDisplayName(displayName) .setAnalysisInput( new MultiLanguageAnalysisInput().setDocuments(toMultiLanguageInput(documents))) .setTasks(Arrays.asList( @@ -162,6 +176,11 @@ class AnalyzeHealthcareEntityAsyncClient { beginAnalyzeHealthcarePagedIterable(Iterable documents, AnalyzeHealthcareEntitiesOptions options, Context context) { try { + throwIfTargetServiceVersionFound(this.serviceVersion, + Arrays.asList(TextAnalyticsServiceVersion.V3_0), + getUnsupportedServiceApiVersionMessage("beginAnalyzeHealthcareEntities", serviceVersion, + TextAnalyticsServiceVersion.V3_1)); + throwIfCallingNotAvailableFeatureInOptions(options); inputDocumentsValidation(documents); options = getNotNullAnalyzeHealthcareEntitiesOptions(options); final Context finalContext = getNotNullContext(context) @@ -172,11 +191,13 @@ class AnalyzeHealthcareEntityAsyncClient { final boolean finalLoggingOptOut = options.isServiceLogsDisabled(); if (service != null) { + final String displayName = options.getDisplayName(); return new PollerFlux<>( DEFAULT_POLL_INTERVAL, activationOperation( service.submitJobWithResponseAsync( new AnalyzeTextJobsInput() + .setDisplayName(displayName) .setAnalysisInput( new MultiLanguageAnalysisInput().setDocuments(toMultiLanguageInput(documents))) .setTasks(Arrays.asList( @@ -526,7 +547,8 @@ private Mono> processAnal status = LongRunningOperationStatus.fromString( analyzeOperationResultResponse.getValue().getStatus().toString(), true); } - + AnalyzeHealthcareEntitiesOperationDetailPropertiesHelper.setDisplayName(operationResultPollResponse.getValue(), + analyzeOperationResultResponse.getValue().getDisplayName()); AnalyzeHealthcareEntitiesOperationDetailPropertiesHelper.setCreatedAt(operationResultPollResponse.getValue(), analyzeOperationResultResponse.getValue().getCreatedDateTime()); AnalyzeHealthcareEntitiesOperationDetailPropertiesHelper.setLastModifiedAt( @@ -540,4 +562,13 @@ private AnalyzeHealthcareEntitiesOptions getNotNullAnalyzeHealthcareEntitiesOpti AnalyzeHealthcareEntitiesOptions options) { return options == null ? new AnalyzeHealthcareEntitiesOptions() : options; } + + private void throwIfCallingNotAvailableFeatureInOptions(AnalyzeHealthcareEntitiesOptions options) { + if (options != null && options.getDisplayName() != null) { + throwIfTargetServiceVersionFound(serviceVersion, + Arrays.asList(TextAnalyticsServiceVersion.V3_1), + getUnsupportedServiceApiVersionMessage("AnalyzeHealthcareEntitiesOptions.displayName", + serviceVersion, TextAnalyticsServiceVersion.V2022_05_01)); + } + } } diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/AnalyzeSentimentAsyncClient.java b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/AnalyzeSentimentAsyncClient.java index 9268917eb0a84..499ac274ad4ab 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/AnalyzeSentimentAsyncClient.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/AnalyzeSentimentAsyncClient.java @@ -21,10 +21,14 @@ import com.azure.core.util.logging.ClientLogger; import reactor.core.publisher.Mono; +import java.util.Arrays; + import static com.azure.ai.textanalytics.TextAnalyticsAsyncClient.COGNITIVE_TRACING_NAMESPACE_VALUE; import static com.azure.ai.textanalytics.implementation.Utility.getDocumentCount; import static com.azure.ai.textanalytics.implementation.Utility.getNotNullContext; +import static com.azure.ai.textanalytics.implementation.Utility.getUnsupportedServiceApiVersionMessage; import static com.azure.ai.textanalytics.implementation.Utility.inputDocumentsValidation; +import static com.azure.ai.textanalytics.implementation.Utility.throwIfTargetServiceVersionFound; import static com.azure.ai.textanalytics.implementation.Utility.toMultiLanguageInput; import static com.azure.core.util.FluxUtil.monoError; import static com.azure.core.util.FluxUtil.withContext; @@ -38,14 +42,19 @@ class AnalyzeSentimentAsyncClient { private final TextAnalyticsClientImpl legacyService; private final MicrosoftCognitiveLanguageServiceTextAnalysisImpl service; - AnalyzeSentimentAsyncClient(TextAnalyticsClientImpl legacyService) { + private final TextAnalyticsServiceVersion serviceVersion; + + AnalyzeSentimentAsyncClient(TextAnalyticsClientImpl legacyService, TextAnalyticsServiceVersion serviceVersion) { this.legacyService = legacyService; this.service = null; + this.serviceVersion = serviceVersion; } - AnalyzeSentimentAsyncClient(MicrosoftCognitiveLanguageServiceTextAnalysisImpl service) { + AnalyzeSentimentAsyncClient(MicrosoftCognitiveLanguageServiceTextAnalysisImpl service, + TextAnalyticsServiceVersion serviceVersion) { this.legacyService = null; this.service = service; + this.serviceVersion = serviceVersion; } /** @@ -64,7 +73,6 @@ class AnalyzeSentimentAsyncClient { public Mono> analyzeSentimentBatch( Iterable documents, AnalyzeSentimentOptions options) { try { - inputDocumentsValidation(documents); return withContext(context -> getAnalyzedSentimentResponse(documents, options, context)); } catch (RuntimeException ex) { return monoError(logger, ex); @@ -85,7 +93,6 @@ public Mono> analyzeSentimentBatch( Mono> analyzeSentimentBatchWithContext( Iterable documents, AnalyzeSentimentOptions options, Context context) { try { - inputDocumentsValidation(documents); return getAnalyzedSentimentResponse(documents, options, context); } catch (RuntimeException ex) { return monoError(logger, ex); @@ -105,6 +112,8 @@ Mono> analyzeSentimentBatchWithContex */ private Mono> getAnalyzedSentimentResponse( Iterable documents, AnalyzeSentimentOptions options, Context context) { + throwIfCallingNotAvailableFeatureInOptions(options); + inputDocumentsValidation(documents); options = options == null ? new AnalyzeSentimentOptions() : options; if (service != null) { @@ -146,4 +155,20 @@ private Mono> getAnalyzedSentimentRes .map(Utility::toAnalyzeSentimentResultCollectionResponse) .onErrorMap(Utility::mapToHttpResponseExceptionIfExists); } + + private void throwIfCallingNotAvailableFeatureInOptions(AnalyzeSentimentOptions options) { + if (options == null) { + return; + } + if (options.isIncludeOpinionMining()) { + throwIfTargetServiceVersionFound(this.serviceVersion, Arrays.asList(TextAnalyticsServiceVersion.V3_0), + getUnsupportedServiceApiVersionMessage("AnalyzeSentimentOptions.includeOpinionMining", + serviceVersion, TextAnalyticsServiceVersion.V3_1)); + } + if (options.isServiceLogsDisabled()) { + throwIfTargetServiceVersionFound(this.serviceVersion, Arrays.asList(TextAnalyticsServiceVersion.V3_0), + getUnsupportedServiceApiVersionMessage("TextAnalyticsRequestOptions.disableServiceLogs", + serviceVersion, TextAnalyticsServiceVersion.V3_1)); + } + } } diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/DetectLanguageAsyncClient.java b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/DetectLanguageAsyncClient.java index fc4fb4342cb1b..7bd95f8dd4316 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/DetectLanguageAsyncClient.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/DetectLanguageAsyncClient.java @@ -21,10 +21,14 @@ import com.azure.core.util.logging.ClientLogger; import reactor.core.publisher.Mono; +import java.util.Arrays; + import static com.azure.ai.textanalytics.TextAnalyticsAsyncClient.COGNITIVE_TRACING_NAMESPACE_VALUE; import static com.azure.ai.textanalytics.implementation.Utility.getDocumentCount; import static com.azure.ai.textanalytics.implementation.Utility.getNotNullContext; +import static com.azure.ai.textanalytics.implementation.Utility.getUnsupportedServiceApiVersionMessage; import static com.azure.ai.textanalytics.implementation.Utility.inputDocumentsValidation; +import static com.azure.ai.textanalytics.implementation.Utility.throwIfTargetServiceVersionFound; import static com.azure.ai.textanalytics.implementation.Utility.toLanguageInput; import static com.azure.core.util.FluxUtil.monoError; import static com.azure.core.util.FluxUtil.withContext; @@ -38,14 +42,19 @@ class DetectLanguageAsyncClient { private final TextAnalyticsClientImpl legacyService; private final MicrosoftCognitiveLanguageServiceTextAnalysisImpl service; - DetectLanguageAsyncClient(TextAnalyticsClientImpl legacyService) { + private final TextAnalyticsServiceVersion serviceVersion; + + DetectLanguageAsyncClient(TextAnalyticsClientImpl legacyService, TextAnalyticsServiceVersion serviceVersion) { this.legacyService = legacyService; this.service = null; + this.serviceVersion = serviceVersion; } - DetectLanguageAsyncClient(MicrosoftCognitiveLanguageServiceTextAnalysisImpl service) { + DetectLanguageAsyncClient(MicrosoftCognitiveLanguageServiceTextAnalysisImpl service, + TextAnalyticsServiceVersion serviceVersion) { this.legacyService = null; this.service = service; + this.serviceVersion = serviceVersion; } /** @@ -59,7 +68,6 @@ class DetectLanguageAsyncClient { Mono> detectLanguageBatch( Iterable documents, TextAnalyticsRequestOptions options) { try { - inputDocumentsValidation(documents); return withContext(context -> getDetectedLanguageResponse(documents, options, context)); } catch (RuntimeException ex) { return monoError(logger, ex); @@ -78,7 +86,6 @@ Mono> detectLanguageBatch( Mono> detectLanguageBatchWithContext( Iterable documents, TextAnalyticsRequestOptions options, Context context) { try { - inputDocumentsValidation(documents); return getDetectedLanguageResponse(documents, options, context); } catch (RuntimeException ex) { return monoError(logger, ex); @@ -97,6 +104,8 @@ Mono> detectLanguageBatchWithContext( */ private Mono> getDetectedLanguageResponse( Iterable documents, TextAnalyticsRequestOptions options, Context context) { + throwIfCallingNotAvailableFeatureInOptions(options); + inputDocumentsValidation(documents); options = options == null ? new TextAnalyticsRequestOptions() : options; if (service != null) { return service @@ -135,4 +144,12 @@ private Mono> getDetectedLanguageRespon .map(Utility::toDetectLanguageResultCollectionResponse) .onErrorMap(Utility::mapToHttpResponseExceptionIfExists); } + + private void throwIfCallingNotAvailableFeatureInOptions(TextAnalyticsRequestOptions options) { + if (options != null && options.isServiceLogsDisabled()) { + throwIfTargetServiceVersionFound(this.serviceVersion, Arrays.asList(TextAnalyticsServiceVersion.V3_0), + getUnsupportedServiceApiVersionMessage("TextAnalyticsRequestOptions.disableServiceLogs", + serviceVersion, TextAnalyticsServiceVersion.V3_1)); + } + } } diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/ExtractKeyPhraseAsyncClient.java b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/ExtractKeyPhraseAsyncClient.java index 8a90137b95fcd..a84eaf7215c7d 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/ExtractKeyPhraseAsyncClient.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/ExtractKeyPhraseAsyncClient.java @@ -22,13 +22,16 @@ import com.azure.core.util.logging.ClientLogger; import reactor.core.publisher.Mono; +import java.util.Arrays; import java.util.Collections; import java.util.Objects; import static com.azure.ai.textanalytics.TextAnalyticsAsyncClient.COGNITIVE_TRACING_NAMESPACE_VALUE; import static com.azure.ai.textanalytics.implementation.Utility.getDocumentCount; import static com.azure.ai.textanalytics.implementation.Utility.getNotNullContext; +import static com.azure.ai.textanalytics.implementation.Utility.getUnsupportedServiceApiVersionMessage; import static com.azure.ai.textanalytics.implementation.Utility.inputDocumentsValidation; +import static com.azure.ai.textanalytics.implementation.Utility.throwIfTargetServiceVersionFound; import static com.azure.ai.textanalytics.implementation.Utility.toMultiLanguageInput; import static com.azure.ai.textanalytics.implementation.Utility.toTextAnalyticsException; import static com.azure.core.util.FluxUtil.monoError; @@ -43,14 +46,19 @@ class ExtractKeyPhraseAsyncClient { private final TextAnalyticsClientImpl legacyService; private final MicrosoftCognitiveLanguageServiceTextAnalysisImpl service; - ExtractKeyPhraseAsyncClient(TextAnalyticsClientImpl legacyService) { + private final TextAnalyticsServiceVersion serviceVersion; + + ExtractKeyPhraseAsyncClient(TextAnalyticsClientImpl legacyService, TextAnalyticsServiceVersion serviceVersion) { this.legacyService = legacyService; this.service = null; + this.serviceVersion = serviceVersion; } - ExtractKeyPhraseAsyncClient(MicrosoftCognitiveLanguageServiceTextAnalysisImpl service) { + ExtractKeyPhraseAsyncClient(MicrosoftCognitiveLanguageServiceTextAnalysisImpl service, + TextAnalyticsServiceVersion serviceVersion) { this.legacyService = null; this.service = service; + this.serviceVersion = serviceVersion; } /** @@ -96,7 +104,6 @@ Mono extractKeyPhrasesSingleText(String document, String l Mono> extractKeyPhrasesWithResponse( Iterable documents, TextAnalyticsRequestOptions options) { try { - inputDocumentsValidation(documents); return withContext(context -> getExtractedKeyPhrasesResponse(documents, options, context)); } catch (RuntimeException ex) { return monoError(logger, ex); @@ -116,7 +123,6 @@ Mono> extractKeyPhrasesWithResponse( Mono> extractKeyPhrasesBatchWithContext( Iterable documents, TextAnalyticsRequestOptions options, Context context) { try { - inputDocumentsValidation(documents); return getExtractedKeyPhrasesResponse(documents, options, context); } catch (RuntimeException ex) { return monoError(logger, ex); @@ -135,6 +141,8 @@ Mono> extractKeyPhrasesBatchWithCont */ private Mono> getExtractedKeyPhrasesResponse( Iterable documents, TextAnalyticsRequestOptions options, Context context) { + throwIfCallingNotAvailableFeatureInOptions(options); + inputDocumentsValidation(documents); options = options == null ? new TextAnalyticsRequestOptions() : options; if (service != null) { @@ -171,4 +179,12 @@ private Mono> getExtractedKeyPhrases .map(Utility::toExtractKeyPhrasesResultCollectionResponse) .onErrorMap(Utility::mapToHttpResponseExceptionIfExists); } + + private void throwIfCallingNotAvailableFeatureInOptions(TextAnalyticsRequestOptions options) { + if (options != null && options.isServiceLogsDisabled()) { + throwIfTargetServiceVersionFound(this.serviceVersion, Arrays.asList(TextAnalyticsServiceVersion.V3_0), + getUnsupportedServiceApiVersionMessage("TextAnalyticsRequestOptions.disableServiceLogs", + serviceVersion, TextAnalyticsServiceVersion.V3_1)); + } + } } diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/LabelClassifyAsyncClient.java b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/LabelClassifyAsyncClient.java index f7802827091a2..79e91024900ad 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/LabelClassifyAsyncClient.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/LabelClassifyAsyncClient.java @@ -58,9 +58,11 @@ import static com.azure.ai.textanalytics.TextAnalyticsAsyncClient.COGNITIVE_TRACING_NAMESPACE_VALUE; import static com.azure.ai.textanalytics.implementation.Utility.DEFAULT_POLL_INTERVAL; import static com.azure.ai.textanalytics.implementation.Utility.getNotNullContext; +import static com.azure.ai.textanalytics.implementation.Utility.getUnsupportedServiceApiVersionMessage; import static com.azure.ai.textanalytics.implementation.Utility.inputDocumentsValidation; import static com.azure.ai.textanalytics.implementation.Utility.parseNextLink; import static com.azure.ai.textanalytics.implementation.Utility.parseOperationId; +import static com.azure.ai.textanalytics.implementation.Utility.throwIfTargetServiceVersionFound; import static com.azure.ai.textanalytics.implementation.Utility.toLabelClassificationResultCollection; import static com.azure.ai.textanalytics.implementation.Utility.toMultiLanguageInput; import static com.azure.ai.textanalytics.implementation.models.State.CANCELLED; @@ -74,26 +76,35 @@ class LabelClassifyAsyncClient { private static final ClientLogger LOGGER = new ClientLogger(LabelClassifyAsyncClient.class); private final AnalyzeTextsImpl service; - LabelClassifyAsyncClient(AnalyzeTextsImpl service) { + private final TextAnalyticsServiceVersion serviceVersion; + + LabelClassifyAsyncClient(AnalyzeTextsImpl service, TextAnalyticsServiceVersion serviceVersion) { this.service = service; + this.serviceVersion = serviceVersion; } PollerFlux singleLabelClassify( Iterable documents, String projectName, String deploymentName, SingleLabelClassifyOptions options, Context context) { try { + throwIfTargetServiceVersionFound(this.serviceVersion, + Arrays.asList(TextAnalyticsServiceVersion.V3_0, TextAnalyticsServiceVersion.V3_1), + getUnsupportedServiceApiVersionMessage("beginSingleLabelClassify", serviceVersion, + TextAnalyticsServiceVersion.V2022_05_01)); inputDocumentsValidation(documents); options = getNotNullSingleLabelClassifyOptions(options); final Context finalContext = getNotNullContext(context) .addData(AZ_TRACING_NAMESPACE_KEY, COGNITIVE_TRACING_NAMESPACE_VALUE); final boolean finalLoggingOptOut = options.isServiceLogsDisabled(); final boolean finalIncludeStatistics = options.isIncludeStatistics(); + final String displayName = options.getDisplayName(); return new PollerFlux<>( DEFAULT_POLL_INTERVAL, activationOperation( service.submitJobWithResponseAsync( new AnalyzeTextJobsInput() + .setDisplayName(displayName) .setAnalysisInput( new MultiLanguageAnalysisInput().setDocuments(toMultiLanguageInput(documents))) .setTasks(Arrays.asList( @@ -129,18 +140,24 @@ PollerFlux singl Iterable documents, String projectName, String deploymentName, SingleLabelClassifyOptions options, Context context) { try { + throwIfTargetServiceVersionFound(this.serviceVersion, + Arrays.asList(TextAnalyticsServiceVersion.V3_0, TextAnalyticsServiceVersion.V3_1), + getUnsupportedServiceApiVersionMessage("beginSingleLabelClassify", serviceVersion, + TextAnalyticsServiceVersion.V2022_05_01)); inputDocumentsValidation(documents); options = getNotNullSingleLabelClassifyOptions(options); final Context finalContext = getNotNullContext(context) .addData(AZ_TRACING_NAMESPACE_KEY, COGNITIVE_TRACING_NAMESPACE_VALUE); final boolean finalIncludeStatistics = options.isIncludeStatistics(); final boolean finalLoggingOptOut = options.isServiceLogsDisabled(); + final String displayName = options.getDisplayName(); return new PollerFlux<>( DEFAULT_POLL_INTERVAL, activationOperation( service.submitJobWithResponseAsync( new AnalyzeTextJobsInput() + .setDisplayName(displayName) .setAnalysisInput( new MultiLanguageAnalysisInput().setDocuments(toMultiLanguageInput(documents))) .setTasks(Arrays.asList( @@ -176,18 +193,24 @@ PollerFlux multiLabe Iterable documents, String projectName, String deploymentName, MultiLabelClassifyOptions options, Context context) { try { + throwIfTargetServiceVersionFound(this.serviceVersion, + Arrays.asList(TextAnalyticsServiceVersion.V3_0, TextAnalyticsServiceVersion.V3_1), + getUnsupportedServiceApiVersionMessage("beginMultiLabelClassify", serviceVersion, + TextAnalyticsServiceVersion.V2022_05_01)); inputDocumentsValidation(documents); options = getNotNullMultiLabelClassifyOptions(options); final Context finalContext = getNotNullContext(context) .addData(AZ_TRACING_NAMESPACE_KEY, COGNITIVE_TRACING_NAMESPACE_VALUE); final boolean finalLoggingOptOut = options.isServiceLogsDisabled(); final boolean finalIncludeStatistics = options.isIncludeStatistics(); + final String displayName = options.getDisplayName(); return new PollerFlux<>( DEFAULT_POLL_INTERVAL, activationOperation( service.submitJobWithResponseAsync( new AnalyzeTextJobsInput() + .setDisplayName(displayName) .setAnalysisInput( new MultiLanguageAnalysisInput().setDocuments(toMultiLanguageInput(documents))) .setTasks(Arrays.asList( @@ -223,18 +246,24 @@ PollerFlux multi Iterable documents, String projectName, String deploymentName, MultiLabelClassifyOptions options, Context context) { try { + throwIfTargetServiceVersionFound(this.serviceVersion, + Arrays.asList(TextAnalyticsServiceVersion.V3_0, TextAnalyticsServiceVersion.V3_1), + getUnsupportedServiceApiVersionMessage("beginMultiLabelClassify", serviceVersion, + TextAnalyticsServiceVersion.V2022_05_01)); inputDocumentsValidation(documents); options = getNotNullMultiLabelClassifyOptions(options); final Context finalContext = getNotNullContext(context) .addData(AZ_TRACING_NAMESPACE_KEY, COGNITIVE_TRACING_NAMESPACE_VALUE); final boolean finalIncludeStatistics = options.isIncludeStatistics(); final boolean finalLoggingOptOut = options.isServiceLogsDisabled(); + final String displayName = options.getDisplayName(); return new PollerFlux<>( DEFAULT_POLL_INTERVAL, activationOperation( service.submitJobWithResponseAsync( new AnalyzeTextJobsInput() + .setDisplayName(displayName) .setAnalysisInput( new MultiLanguageAnalysisInput().setDocuments(toMultiLanguageInput(documents))) .setTasks(Arrays.asList( @@ -443,7 +472,8 @@ private Mono> processAnalyzeTextMo status = LongRunningOperationStatus.fromString( analyzeOperationResultResponse.getValue().getStatus().toString(), true); } - + ClassifyDocumentOperationDetailPropertiesHelper.setDisplayName(operationResultPollResponse.getValue(), + analyzeOperationResultResponse.getValue().getDisplayName()); ClassifyDocumentOperationDetailPropertiesHelper.setCreatedAt(operationResultPollResponse.getValue(), analyzeOperationResultResponse.getValue().getCreatedDateTime()); ClassifyDocumentOperationDetailPropertiesHelper.setLastModifiedAt( diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/RecognizeCustomEntitiesAsyncClient.java b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/RecognizeCustomEntitiesAsyncClient.java index 6bff6a5ff68fd..b1c398db5e4ac 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/RecognizeCustomEntitiesAsyncClient.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/RecognizeCustomEntitiesAsyncClient.java @@ -55,9 +55,11 @@ import static com.azure.ai.textanalytics.TextAnalyticsAsyncClient.COGNITIVE_TRACING_NAMESPACE_VALUE; import static com.azure.ai.textanalytics.implementation.Utility.DEFAULT_POLL_INTERVAL; import static com.azure.ai.textanalytics.implementation.Utility.getNotNullContext; +import static com.azure.ai.textanalytics.implementation.Utility.getUnsupportedServiceApiVersionMessage; import static com.azure.ai.textanalytics.implementation.Utility.inputDocumentsValidation; import static com.azure.ai.textanalytics.implementation.Utility.parseNextLink; import static com.azure.ai.textanalytics.implementation.Utility.parseOperationId; +import static com.azure.ai.textanalytics.implementation.Utility.throwIfTargetServiceVersionFound; import static com.azure.ai.textanalytics.implementation.Utility.toMultiLanguageInput; import static com.azure.ai.textanalytics.implementation.Utility.toRecognizeCustomEntitiesResultCollection; import static com.azure.ai.textanalytics.implementation.models.State.CANCELLED; @@ -71,14 +73,22 @@ class RecognizeCustomEntitiesAsyncClient { private final ClientLogger logger = new ClientLogger(RecognizeCustomEntitiesAsyncClient.class); private final AnalyzeTextsImpl service; - RecognizeCustomEntitiesAsyncClient(AnalyzeTextsImpl service) { + private final TextAnalyticsServiceVersion serviceVersion; + + RecognizeCustomEntitiesAsyncClient(AnalyzeTextsImpl service, + TextAnalyticsServiceVersion serviceVersion) { this.service = service; + this.serviceVersion = serviceVersion; } PollerFlux recognizeCustomEntities( Iterable documents, String projectName, String deploymentName, RecognizeCustomEntitiesOptions options, Context context) { try { + throwIfTargetServiceVersionFound(this.serviceVersion, + Arrays.asList(TextAnalyticsServiceVersion.V3_0, TextAnalyticsServiceVersion.V3_1), + getUnsupportedServiceApiVersionMessage("beginRecognizeCustomEntities", serviceVersion, + TextAnalyticsServiceVersion.V2022_05_01)); inputDocumentsValidation(documents); options = getNotNullRecognizeCustomEntitiesOptions(options); final Context finalContext = getNotNullContext(context) @@ -86,12 +96,14 @@ PollerFlux( DEFAULT_POLL_INTERVAL, activationOperation( service.submitJobWithResponseAsync( new AnalyzeTextJobsInput() + .setDisplayName(displayName) .setAnalysisInput( new MultiLanguageAnalysisInput().setDocuments(toMultiLanguageInput(documents))) .setTasks(Arrays.asList( @@ -127,6 +139,10 @@ PollerFlux documents, String projectName, String deploymentName, RecognizeCustomEntitiesOptions options, Context context) { try { + throwIfTargetServiceVersionFound(this.serviceVersion, + Arrays.asList(TextAnalyticsServiceVersion.V3_0, TextAnalyticsServiceVersion.V3_1), + getUnsupportedServiceApiVersionMessage("beginRecognizeCustomEntities", serviceVersion, + TextAnalyticsServiceVersion.V2022_05_01)); inputDocumentsValidation(documents); options = getNotNullRecognizeCustomEntitiesOptions(options); final Context finalContext = getNotNullContext(context) @@ -134,12 +150,14 @@ PollerFlux( DEFAULT_POLL_INTERVAL, activationOperation( service.submitJobWithResponseAsync( new AnalyzeTextJobsInput() + .setDisplayName(displayName) .setAnalysisInput( new MultiLanguageAnalysisInput().setDocuments(toMultiLanguageInput(documents))) .setTasks(Arrays.asList( @@ -338,7 +356,8 @@ private Mono> processAnalyz status = LongRunningOperationStatus.fromString( analyzeOperationResultResponse.getValue().getStatus().toString(), true); } - + RecognizeCustomEntitiesOperationDetailPropertiesHelper.setDisplayName(operationResultPollResponse.getValue(), + analyzeOperationResultResponse.getValue().getDisplayName()); RecognizeCustomEntitiesOperationDetailPropertiesHelper.setCreatedAt(operationResultPollResponse.getValue(), analyzeOperationResultResponse.getValue().getCreatedDateTime()); RecognizeCustomEntitiesOperationDetailPropertiesHelper.setLastModifiedAt( diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/RecognizeEntityAsyncClient.java b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/RecognizeEntityAsyncClient.java index d79e88fab8154..11a9010f464af 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/RecognizeEntityAsyncClient.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/RecognizeEntityAsyncClient.java @@ -23,13 +23,16 @@ import com.azure.core.util.logging.ClientLogger; import reactor.core.publisher.Mono; +import java.util.Arrays; import java.util.Collections; import java.util.Objects; import static com.azure.ai.textanalytics.TextAnalyticsAsyncClient.COGNITIVE_TRACING_NAMESPACE_VALUE; import static com.azure.ai.textanalytics.implementation.Utility.getDocumentCount; import static com.azure.ai.textanalytics.implementation.Utility.getNotNullContext; +import static com.azure.ai.textanalytics.implementation.Utility.getUnsupportedServiceApiVersionMessage; import static com.azure.ai.textanalytics.implementation.Utility.inputDocumentsValidation; +import static com.azure.ai.textanalytics.implementation.Utility.throwIfTargetServiceVersionFound; import static com.azure.ai.textanalytics.implementation.Utility.toMultiLanguageInput; import static com.azure.ai.textanalytics.implementation.Utility.toTextAnalyticsException; import static com.azure.core.util.FluxUtil.monoError; @@ -44,14 +47,19 @@ class RecognizeEntityAsyncClient { private final TextAnalyticsClientImpl legacyService; private final MicrosoftCognitiveLanguageServiceTextAnalysisImpl service; - RecognizeEntityAsyncClient(TextAnalyticsClientImpl legacyService) { + private final TextAnalyticsServiceVersion serviceVersion; + + RecognizeEntityAsyncClient(TextAnalyticsClientImpl legacyService, TextAnalyticsServiceVersion serviceVersion) { this.legacyService = legacyService; this.service = null; + this.serviceVersion = serviceVersion; } - RecognizeEntityAsyncClient(MicrosoftCognitiveLanguageServiceTextAnalysisImpl service) { + RecognizeEntityAsyncClient(MicrosoftCognitiveLanguageServiceTextAnalysisImpl service, + TextAnalyticsServiceVersion serviceVersion) { this.legacyService = null; this.service = service; + this.serviceVersion = serviceVersion; } /** @@ -97,7 +105,6 @@ Mono recognizeEntities(String document, String lang Mono> recognizeEntitiesBatch( Iterable documents, TextAnalyticsRequestOptions options) { try { - inputDocumentsValidation(documents); return withContext(context -> getRecognizedEntitiesResponse(documents, options, context)); } catch (RuntimeException ex) { return monoError(logger, ex); @@ -116,7 +123,6 @@ Mono> recognizeEntitiesBatch( Mono> recognizeEntitiesBatchWithContext( Iterable documents, TextAnalyticsRequestOptions options, Context context) { try { - inputDocumentsValidation(documents); return getRecognizedEntitiesResponse(documents, options, context); } catch (RuntimeException ex) { return monoError(logger, ex); @@ -135,6 +141,8 @@ Mono> recognizeEntitiesBatchWithCont */ private Mono> getRecognizedEntitiesResponse( Iterable documents, TextAnalyticsRequestOptions options, Context context) { + throwIfCallingNotAvailableFeatureInOptions(options); + inputDocumentsValidation(documents); options = options == null ? new TextAnalyticsRequestOptions() : options; final Context finalContext = getNotNullContext(context) .addData(AZ_TRACING_NAMESPACE_KEY, COGNITIVE_TRACING_NAMESPACE_VALUE); @@ -180,4 +188,12 @@ private Mono> getRecognizedEntitiesR .map(Utility::toRecognizeEntitiesResultCollection) .onErrorMap(Utility::mapToHttpResponseExceptionIfExists); } + + private void throwIfCallingNotAvailableFeatureInOptions(TextAnalyticsRequestOptions options) { + if (options != null && options.isServiceLogsDisabled()) { + throwIfTargetServiceVersionFound(this.serviceVersion, Arrays.asList(TextAnalyticsServiceVersion.V3_0), + getUnsupportedServiceApiVersionMessage("TextAnalyticsRequestOptions.disableServiceLogs", + serviceVersion, TextAnalyticsServiceVersion.V3_1)); + } + } } diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/RecognizeLinkedEntityAsyncClient.java b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/RecognizeLinkedEntityAsyncClient.java index 3c3d86bb95b46..e0c826c2ebc37 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/RecognizeLinkedEntityAsyncClient.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/RecognizeLinkedEntityAsyncClient.java @@ -23,13 +23,16 @@ import com.azure.core.util.logging.ClientLogger; import reactor.core.publisher.Mono; +import java.util.Arrays; import java.util.Collections; import java.util.Objects; import static com.azure.ai.textanalytics.TextAnalyticsAsyncClient.COGNITIVE_TRACING_NAMESPACE_VALUE; import static com.azure.ai.textanalytics.implementation.Utility.getDocumentCount; import static com.azure.ai.textanalytics.implementation.Utility.getNotNullContext; +import static com.azure.ai.textanalytics.implementation.Utility.getUnsupportedServiceApiVersionMessage; import static com.azure.ai.textanalytics.implementation.Utility.inputDocumentsValidation; +import static com.azure.ai.textanalytics.implementation.Utility.throwIfTargetServiceVersionFound; import static com.azure.ai.textanalytics.implementation.Utility.toMultiLanguageInput; import static com.azure.ai.textanalytics.implementation.Utility.toTextAnalyticsException; import static com.azure.core.util.FluxUtil.monoError; @@ -44,14 +47,20 @@ class RecognizeLinkedEntityAsyncClient { private final TextAnalyticsClientImpl legacyService; private final MicrosoftCognitiveLanguageServiceTextAnalysisImpl service; - RecognizeLinkedEntityAsyncClient(TextAnalyticsClientImpl legacyService) { + private final TextAnalyticsServiceVersion serviceVersion; + + RecognizeLinkedEntityAsyncClient(TextAnalyticsClientImpl legacyService, + TextAnalyticsServiceVersion serviceVersion) { this.legacyService = legacyService; this.service = null; + this.serviceVersion = serviceVersion; } - RecognizeLinkedEntityAsyncClient(MicrosoftCognitiveLanguageServiceTextAnalysisImpl service) { + RecognizeLinkedEntityAsyncClient(MicrosoftCognitiveLanguageServiceTextAnalysisImpl service, + TextAnalyticsServiceVersion serviceVersion) { this.legacyService = null; this.service = service; + this.serviceVersion = serviceVersion; } /** @@ -97,7 +106,6 @@ Mono recognizeLinkedEntities(String document, String lan Mono> recognizeLinkedEntitiesBatch( Iterable documents, TextAnalyticsRequestOptions options) { try { - inputDocumentsValidation(documents); return withContext(context -> getRecognizedLinkedEntitiesResponse(documents, options, context)); } catch (RuntimeException ex) { return monoError(logger, ex); @@ -118,7 +126,6 @@ Mono> recognizeLinkedEntitiesB recognizeLinkedEntitiesBatchWithContext(Iterable documents, TextAnalyticsRequestOptions options, Context context) { try { - inputDocumentsValidation(documents); return getRecognizedLinkedEntitiesResponse(documents, options, context); } catch (RuntimeException ex) { return monoError(logger, ex); @@ -136,6 +143,8 @@ Mono> recognizeLinkedEntitiesB */ private Mono> getRecognizedLinkedEntitiesResponse( Iterable documents, TextAnalyticsRequestOptions options, Context context) { + throwIfCallingNotAvailableFeatureInOptions(options); + inputDocumentsValidation(documents); options = options == null ? new TextAnalyticsRequestOptions() : options; final Context finalContext = getNotNullContext(context) .addData(AZ_TRACING_NAMESPACE_KEY, COGNITIVE_TRACING_NAMESPACE_VALUE); @@ -180,4 +189,12 @@ private Mono> getRecognizedLin .map(Utility::toRecognizeLinkedEntitiesResultCollectionResponse) .onErrorMap(Utility::mapToHttpResponseExceptionIfExists); } + + private void throwIfCallingNotAvailableFeatureInOptions(TextAnalyticsRequestOptions options) { + if (options != null && options.isServiceLogsDisabled()) { + throwIfTargetServiceVersionFound(this.serviceVersion, Arrays.asList(TextAnalyticsServiceVersion.V3_0), + getUnsupportedServiceApiVersionMessage("TextAnalyticsRequestOptions.disableServiceLogs", + serviceVersion, TextAnalyticsServiceVersion.V3_1)); + } + } } diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/RecognizePiiEntityAsyncClient.java b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/RecognizePiiEntityAsyncClient.java index 1d0038585f610..e690c8439239d 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/RecognizePiiEntityAsyncClient.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/RecognizePiiEntityAsyncClient.java @@ -24,12 +24,15 @@ import com.azure.core.util.logging.ClientLogger; import reactor.core.publisher.Mono; +import java.util.Arrays; import java.util.Collections; import java.util.Objects; import static com.azure.ai.textanalytics.TextAnalyticsAsyncClient.COGNITIVE_TRACING_NAMESPACE_VALUE; import static com.azure.ai.textanalytics.implementation.Utility.getNotNullContext; +import static com.azure.ai.textanalytics.implementation.Utility.getUnsupportedServiceApiVersionMessage; import static com.azure.ai.textanalytics.implementation.Utility.inputDocumentsValidation; +import static com.azure.ai.textanalytics.implementation.Utility.throwIfTargetServiceVersionFound; import static com.azure.ai.textanalytics.implementation.Utility.toCategoriesFilter; import static com.azure.ai.textanalytics.implementation.Utility.toMultiLanguageInput; import static com.azure.ai.textanalytics.implementation.Utility.toTextAnalyticsException; @@ -45,14 +48,19 @@ class RecognizePiiEntityAsyncClient { private final TextAnalyticsClientImpl legacyService; private final MicrosoftCognitiveLanguageServiceTextAnalysisImpl service; - RecognizePiiEntityAsyncClient(TextAnalyticsClientImpl legacyService) { + private final TextAnalyticsServiceVersion serviceVersion; + + RecognizePiiEntityAsyncClient(TextAnalyticsClientImpl legacyService, TextAnalyticsServiceVersion serviceVersion) { this.legacyService = legacyService; this.service = null; + this.serviceVersion = serviceVersion; } - RecognizePiiEntityAsyncClient(MicrosoftCognitiveLanguageServiceTextAnalysisImpl service) { + RecognizePiiEntityAsyncClient(MicrosoftCognitiveLanguageServiceTextAnalysisImpl service, + TextAnalyticsServiceVersion serviceVersion) { this.legacyService = null; this.service = service; + this.serviceVersion = serviceVersion; } /** @@ -69,6 +77,10 @@ class RecognizePiiEntityAsyncClient { Mono recognizePiiEntities(String document, String language, RecognizePiiEntitiesOptions options) { try { + throwIfTargetServiceVersionFound(this.serviceVersion, + Arrays.asList(TextAnalyticsServiceVersion.V3_0), + getUnsupportedServiceApiVersionMessage("recognizePiiEntitiesBatch", serviceVersion, + TextAnalyticsServiceVersion.V3_1)); Objects.requireNonNull(document, "'document' cannot be null."); return recognizePiiEntitiesBatch( Collections.singletonList(new TextDocumentInput("0", document).setLanguage(language)), options) @@ -102,7 +114,6 @@ Mono recognizePiiEntities(String document, String language, Mono> recognizePiiEntitiesBatch( Iterable documents, RecognizePiiEntitiesOptions options) { try { - inputDocumentsValidation(documents); return withContext(context -> getRecognizePiiEntitiesResponse(documents, options, context)); } catch (RuntimeException ex) { return monoError(logger, ex); @@ -122,7 +133,6 @@ Mono> recognizePiiEntitiesBatch( Mono> recognizePiiEntitiesBatchWithContext( Iterable documents, RecognizePiiEntitiesOptions options, Context context) { try { - inputDocumentsValidation(documents); return getRecognizePiiEntitiesResponse(documents, options, context); } catch (RuntimeException ex) { return monoError(logger, ex); @@ -139,9 +149,15 @@ Mono> recognizePiiEntitiesBatchWi * @param context Additional context that is passed through the Http pipeline during the service call. * * @return A mono {@link Response} that contains {@link RecognizePiiEntitiesResultCollection}. + * */ private Mono> getRecognizePiiEntitiesResponse( Iterable documents, RecognizePiiEntitiesOptions options, Context context) { + throwIfTargetServiceVersionFound(this.serviceVersion, + Arrays.asList(TextAnalyticsServiceVersion.V3_0), + getUnsupportedServiceApiVersionMessage("recognizePiiEntitiesBatch", serviceVersion, + TextAnalyticsServiceVersion.V3_1)); + inputDocumentsValidation(documents); options = options == null ? new RecognizePiiEntitiesOptions() : options; final Context finalContext = getNotNullContext(context) .addData(AZ_TRACING_NAMESPACE_KEY, COGNITIVE_TRACING_NAMESPACE_VALUE); diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/TextAnalyticsAsyncClient.java b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/TextAnalyticsAsyncClient.java index 07a4ba089f2a6..993bb174860ef 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/TextAnalyticsAsyncClient.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/TextAnalyticsAsyncClient.java @@ -8,6 +8,7 @@ import com.azure.ai.textanalytics.implementation.TextAnalyticsClientImpl; import com.azure.ai.textanalytics.models.AnalyzeActionsOperationDetail; import com.azure.ai.textanalytics.models.AnalyzeActionsOptions; +import com.azure.ai.textanalytics.models.AnalyzeHealthcareEntitiesAction; import com.azure.ai.textanalytics.models.AnalyzeHealthcareEntitiesOperationDetail; import com.azure.ai.textanalytics.models.AnalyzeHealthcareEntitiesOptions; import com.azure.ai.textanalytics.models.AnalyzeSentimentOptions; @@ -20,11 +21,14 @@ import com.azure.ai.textanalytics.models.DocumentSentiment; import com.azure.ai.textanalytics.models.KeyPhrasesCollection; import com.azure.ai.textanalytics.models.LinkedEntityCollection; +import com.azure.ai.textanalytics.models.MultiLabelClassifyAction; import com.azure.ai.textanalytics.models.MultiLabelClassifyOptions; import com.azure.ai.textanalytics.models.PiiEntityCollection; +import com.azure.ai.textanalytics.models.RecognizeCustomEntitiesAction; import com.azure.ai.textanalytics.models.RecognizeCustomEntitiesOperationDetail; import com.azure.ai.textanalytics.models.RecognizeCustomEntitiesOptions; import com.azure.ai.textanalytics.models.RecognizePiiEntitiesOptions; +import com.azure.ai.textanalytics.models.SingleLabelClassifyAction; import com.azure.ai.textanalytics.models.SingleLabelClassifyOptions; import com.azure.ai.textanalytics.models.TextAnalyticsActions; import com.azure.ai.textanalytics.models.TextAnalyticsError; @@ -121,16 +125,16 @@ public final class TextAnalyticsAsyncClient { this.serviceVersion = serviceVersion; this.defaultCountryHint = defaultCountryHint; this.defaultLanguage = defaultLanguage; - this.detectLanguageAsyncClient = new DetectLanguageAsyncClient(legacyService); - this.analyzeSentimentAsyncClient = new AnalyzeSentimentAsyncClient(legacyService); - this.extractKeyPhraseAsyncClient = new ExtractKeyPhraseAsyncClient(legacyService); - this.recognizeEntityAsyncClient = new RecognizeEntityAsyncClient(legacyService); - this.recognizePiiEntityAsyncClient = new RecognizePiiEntityAsyncClient(legacyService); - this.recognizeLinkedEntityAsyncClient = new RecognizeLinkedEntityAsyncClient(legacyService); - this.recognizeCustomEntitiesAsyncClient = new RecognizeCustomEntitiesAsyncClient(null); - this.analyzeHealthcareEntityAsyncClient = new AnalyzeHealthcareEntityAsyncClient(legacyService); - this.analyzeActionsAsyncClient = new AnalyzeActionsAsyncClient(legacyService); - this.labelClassifyAsyncClient = new LabelClassifyAsyncClient(null); + this.detectLanguageAsyncClient = new DetectLanguageAsyncClient(legacyService, serviceVersion); + this.analyzeSentimentAsyncClient = new AnalyzeSentimentAsyncClient(legacyService, serviceVersion); + this.extractKeyPhraseAsyncClient = new ExtractKeyPhraseAsyncClient(legacyService, serviceVersion); + this.recognizeEntityAsyncClient = new RecognizeEntityAsyncClient(legacyService, serviceVersion); + this.recognizePiiEntityAsyncClient = new RecognizePiiEntityAsyncClient(legacyService, serviceVersion); + this.recognizeLinkedEntityAsyncClient = new RecognizeLinkedEntityAsyncClient(legacyService, serviceVersion); + this.recognizeCustomEntitiesAsyncClient = new RecognizeCustomEntitiesAsyncClient(null, serviceVersion); + this.analyzeHealthcareEntityAsyncClient = new AnalyzeHealthcareEntityAsyncClient(legacyService, serviceVersion); + this.analyzeActionsAsyncClient = new AnalyzeActionsAsyncClient(legacyService, serviceVersion); + this.labelClassifyAsyncClient = new LabelClassifyAsyncClient(null, serviceVersion); } TextAnalyticsAsyncClient(MicrosoftCognitiveLanguageServiceTextAnalysisImpl service, @@ -140,16 +144,18 @@ public final class TextAnalyticsAsyncClient { this.serviceVersion = serviceVersion; this.defaultCountryHint = defaultCountryHint; this.defaultLanguage = defaultLanguage; - this.detectLanguageAsyncClient = new DetectLanguageAsyncClient(service); - this.analyzeSentimentAsyncClient = new AnalyzeSentimentAsyncClient(service); - this.extractKeyPhraseAsyncClient = new ExtractKeyPhraseAsyncClient(service); - this.recognizeEntityAsyncClient = new RecognizeEntityAsyncClient(service); - this.recognizePiiEntityAsyncClient = new RecognizePiiEntityAsyncClient(service); - this.recognizeLinkedEntityAsyncClient = new RecognizeLinkedEntityAsyncClient(service); - this.recognizeCustomEntitiesAsyncClient = new RecognizeCustomEntitiesAsyncClient(new AnalyzeTextsImpl(service)); - this.analyzeHealthcareEntityAsyncClient = new AnalyzeHealthcareEntityAsyncClient(new AnalyzeTextsImpl(service)); - this.analyzeActionsAsyncClient = new AnalyzeActionsAsyncClient(new AnalyzeTextsImpl(service)); - this.labelClassifyAsyncClient = new LabelClassifyAsyncClient(new AnalyzeTextsImpl(service)); + this.detectLanguageAsyncClient = new DetectLanguageAsyncClient(service, serviceVersion); + this.analyzeSentimentAsyncClient = new AnalyzeSentimentAsyncClient(service, serviceVersion); + this.extractKeyPhraseAsyncClient = new ExtractKeyPhraseAsyncClient(service, serviceVersion); + this.recognizeEntityAsyncClient = new RecognizeEntityAsyncClient(service, serviceVersion); + this.recognizePiiEntityAsyncClient = new RecognizePiiEntityAsyncClient(service, serviceVersion); + this.recognizeLinkedEntityAsyncClient = new RecognizeLinkedEntityAsyncClient(service, serviceVersion); + this.recognizeCustomEntitiesAsyncClient = new RecognizeCustomEntitiesAsyncClient( + new AnalyzeTextsImpl(service), serviceVersion); + this.analyzeHealthcareEntityAsyncClient = new AnalyzeHealthcareEntityAsyncClient(new AnalyzeTextsImpl(service), + serviceVersion); + this.analyzeActionsAsyncClient = new AnalyzeActionsAsyncClient(new AnalyzeTextsImpl(service), serviceVersion); + this.labelClassifyAsyncClient = new LabelClassifyAsyncClient(new AnalyzeTextsImpl(service), serviceVersion); } /** @@ -300,6 +306,9 @@ public Mono detectLanguage(String document, String countryHint * @return A {@link Mono} contains a {@link DetectLanguageResultCollection}. * * @throws NullPointerException if {@code documents} is null. + * @throws IllegalStateException if {@link TextAnalyticsRequestOptions#isServiceLogsDisabled()} is true in service + * API version {@link TextAnalyticsServiceVersion#V3_0}. {@code disableServiceLogs} is only available for API + * version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public Mono detectLanguageBatch( @@ -364,6 +373,9 @@ public Mono detectLanguageBatch( * @return A {@link Mono} contains a {@link Response} which contains a {@link DetectLanguageResultCollection}. * * @throws NullPointerException if {@code documents} is null. + * @throws IllegalStateException if {@link TextAnalyticsRequestOptions#isServiceLogsDisabled()} is true in service + * API version {@link TextAnalyticsServiceVersion#V3_0}. {@code disableServiceLogs} is only available for API + * version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public Mono> detectLanguageBatchWithResponse( @@ -490,6 +502,9 @@ public Mono recognizeEntities(String document, Stri * @return A {@link Mono} contains a {@link RecognizeEntitiesResultCollection}. * * @throws NullPointerException if {@code documents} is null. + * @throws IllegalStateException if {@link TextAnalyticsRequestOptions#isServiceLogsDisabled()} is true in service + * API version {@link TextAnalyticsServiceVersion#V3_0}. {@code disableServiceLogs} is only available for API + * version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public Mono recognizeEntitiesBatch( @@ -552,6 +567,9 @@ public Mono recognizeEntitiesBatch( * @return A {@link Mono} contains a {@link Response} which contains a {@link RecognizeEntitiesResultCollection}. * * @throws NullPointerException if {@code documents} is null. + * @throws IllegalStateException if {@link TextAnalyticsRequestOptions#isServiceLogsDisabled()} is true in service + * API version {@link TextAnalyticsServiceVersion#V3_0}. {@code disableServiceLogs} is only available for API + * version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public Mono> recognizeEntitiesBatchWithResponse( @@ -595,6 +613,9 @@ public Mono> recognizeEntitiesBatchW * * @throws NullPointerException if {@code document} is null. * @throws TextAnalyticsException if the response returned with an {@link TextAnalyticsError error}. + * @throws IllegalStateException if {@code recognizePiiEntities} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0}. {@code recognizePiiEntities} is only available for + * API version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public Mono recognizePiiEntities(String document) { @@ -635,6 +656,9 @@ public Mono recognizePiiEntities(String document) { * * @throws NullPointerException if {@code document} is null. * @throws TextAnalyticsException if the response returned with an {@link TextAnalyticsError error}. + * @throws IllegalStateException if {@code recognizePiiEntities} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0}. {@code recognizePiiEntities} is only available for + * API version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public Mono recognizePiiEntities(String document, String language) { @@ -679,6 +703,9 @@ public Mono recognizePiiEntities(String document, String la * * @throws NullPointerException if {@code document} is null. * @throws TextAnalyticsException if the response returned with an {@link TextAnalyticsError error}. + * @throws IllegalStateException if {@code recognizePiiEntities} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0}. {@code recognizePiiEntities} is only available for + * API version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public Mono recognizePiiEntities(String document, String language, @@ -735,6 +762,9 @@ public Mono recognizePiiEntities(String document, String la * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@code recognizePiiEntitiesBatch} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0}. {@code recognizePiiEntitiesBatch} is only available for + * API version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public Mono recognizePiiEntitiesBatch( @@ -801,6 +831,9 @@ public Mono recognizePiiEntitiesBatch( * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@code recognizePiiEntitiesBatchWithResponse} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0}. {@code recognizePiiEntitiesBatchWithResponse} is only available for + * API version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public Mono> recognizePiiEntitiesBatchWithResponse( @@ -938,6 +971,9 @@ public Mono recognizeLinkedEntities(String document, Str * @return A {@link Mono} contains a {@link RecognizeLinkedEntitiesResultCollection}. * * @throws NullPointerException if {@code documents} is null. + * @throws IllegalStateException if {@link TextAnalyticsRequestOptions#isServiceLogsDisabled()} is true in service + * API version {@link TextAnalyticsServiceVersion#V3_0}. {@code disableServiceLogs} is only available for API + * version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public Mono recognizeLinkedEntitiesBatch( @@ -1006,6 +1042,9 @@ public Mono recognizeLinkedEntitiesBatc * {@link RecognizeLinkedEntitiesResultCollection}. * * @throws NullPointerException if {@code documents} is null. + * @throws IllegalStateException if {@link TextAnalyticsRequestOptions#isServiceLogsDisabled()} is true in service + * API version {@link TextAnalyticsServiceVersion#V3_0}. {@code disableServiceLogs} is only available for API + * version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public Mono> recognizeLinkedEntitiesBatchWithResponse( @@ -1120,6 +1159,9 @@ public Mono extractKeyPhrases(String document, String lang * @return A {@link Mono} contains a {@link ExtractKeyPhrasesResultCollection}. * * @throws NullPointerException if {@code documents} is null. + * @throws IllegalStateException if {@link TextAnalyticsRequestOptions#isServiceLogsDisabled()} is true in service + * API version {@link TextAnalyticsServiceVersion#V3_0}. {@code disableServiceLogs} is only available for API + * version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public Mono extractKeyPhrasesBatch( @@ -1182,6 +1224,9 @@ public Mono extractKeyPhrasesBatch( * @return A {@link Mono} contains a {@link Response} that contains a {@link ExtractKeyPhrasesResultCollection}. * * @throws NullPointerException if {@code documents} is null. + * @throws IllegalStateException if {@link TextAnalyticsRequestOptions#isServiceLogsDisabled()} is true in service + * API version {@link TextAnalyticsServiceVersion#V3_0}. {@code disableServiceLogs} is only available for API + * version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public Mono> extractKeyPhrasesBatchWithResponse( @@ -1324,6 +1369,10 @@ public Mono analyzeSentiment(String document, String language * * @throws NullPointerException if {@code document} is null. * @throws TextAnalyticsException if the response returned with an {@link TextAnalyticsError error}. + * @throws IllegalStateException if {@link AnalyzeSentimentOptions#isServiceLogsDisabled()} or + * {@link AnalyzeSentimentOptions#isIncludeOpinionMining()} is true in service API version + * {@link TextAnalyticsServiceVersion#V3_0}. {@code disableServiceLogs} and {@code includeOpinionMining} are only + * available for API version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public Mono analyzeSentiment(String document, String language, AnalyzeSentimentOptions options) { @@ -1479,6 +1528,10 @@ public Mono analyzeSentimentBatch( * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@link AnalyzeSentimentOptions#isServiceLogsDisabled()} or + * {@link AnalyzeSentimentOptions#isIncludeOpinionMining()} is true in service API version + * {@link TextAnalyticsServiceVersion#V3_0}. {@code disableServiceLogs} and {@code includeOpinionMining} are only + * available for API version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public Mono analyzeSentimentBatch(Iterable documents, @@ -1624,6 +1677,10 @@ public Mono> analyzeSentimentBatchWit * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@link AnalyzeSentimentOptions#isServiceLogsDisabled()} or + * {@link AnalyzeSentimentOptions#isIncludeOpinionMining()} is true in service API version + * {@link TextAnalyticsServiceVersion#V3_0}. {@code disableServiceLogs} and {@code includeOpinionMining} are only + * available for API version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public Mono> analyzeSentimentBatchWithResponse( @@ -1651,6 +1708,9 @@ public Mono> analyzeSentimentBatchWit * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@code beginAnalyzeHealthcareEntities} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0}. {@code beginAnalyzeHealthcareEntities} is only available for API + * version v3.1 and newer. * @throws TextAnalyticsException If analyze operation fails. */ @ServiceMethod(returns = ReturnType.COLLECTION) @@ -1752,6 +1812,9 @@ public Mono> analyzeSentimentBatchWit * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@code beginAnalyzeHealthcareEntities} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0}. {@code beginAnalyzeHealthcareEntities} is only available for API + * version v3.1 and newer. * @throws TextAnalyticsException If analyze operation fails. */ @ServiceMethod(returns = ReturnType.COLLECTION) @@ -1829,6 +1892,9 @@ public Mono> analyzeSentimentBatchWit * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@code beginRecognizeCustomEntities} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0} or {@link TextAnalyticsServiceVersion#V3_1}. + * {@code beginRecognizeCustomEntities} is only available for API version 2022-05-01 and newer. * @throws TextAnalyticsException If analyze operation fails. */ @ServiceMethod(returns = ReturnType.COLLECTION) @@ -1906,6 +1972,9 @@ public Mono> analyzeSentimentBatchWit * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@code beginRecognizeCustomEntities} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0} or {@link TextAnalyticsServiceVersion#V3_1}. + * {@code beginRecognizeCustomEntities} is only available for API version 2022-05-01 and newer. * @throws TextAnalyticsException If analyze operation fails. */ @ServiceMethod(returns = ReturnType.COLLECTION) @@ -1987,6 +2056,9 @@ public Mono> analyzeSentimentBatchWit * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@code beginSingleLabelClassify} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0} or {@link TextAnalyticsServiceVersion#V3_1}. + * {@code beginSingleLabelClassify} is only available for API version 2022-05-01 and newer. * @throws TextAnalyticsException If analyze operation fails. */ @ServiceMethod(returns = ReturnType.COLLECTION) @@ -2065,6 +2137,9 @@ public PollerFlux be * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@code beginSingleLabelClassify} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0} or {@link TextAnalyticsServiceVersion#V3_1}. + * {@code beginSingleLabelClassify} is only available for API version 2022-05-01 and newer. * @throws TextAnalyticsException If analyze operation fails. */ @ServiceMethod(returns = ReturnType.COLLECTION) @@ -2141,6 +2216,9 @@ public PollerFlux be * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@code beginMultiLabelClassify} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0} or {@link TextAnalyticsServiceVersion#V3_1}. + * {@code beginMultiLabelClassify} is only available for API version 2022-05-01 and newer. * @throws TextAnalyticsException If analyze operation fails. */ @ServiceMethod(returns = ReturnType.COLLECTION) @@ -2215,6 +2293,9 @@ public PollerFlux be * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@code beginMultiLabelClassify} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0} or {@link TextAnalyticsServiceVersion#V3_1}. + * {@code beginMultiLabelClassify} is only available for API version 2022-05-01 and newer. * @throws TextAnalyticsException If analyze operation fails. */ @ServiceMethod(returns = ReturnType.COLLECTION) @@ -2291,6 +2372,13 @@ public PollerFlux be * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@code beginAnalyzeActions} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0}. {@code beginAnalyzeActions} is only available for API version + * v3.1 and newer. + * @throws IllegalStateException if request {@link AnalyzeHealthcareEntitiesAction}, + * {@link RecognizeCustomEntitiesAction}, {@link SingleLabelClassifyAction}, or {@link MultiLabelClassifyAction} + * in service API version {@link TextAnalyticsServiceVersion#V3_0} or {@link TextAnalyticsServiceVersion#V3_1}. + * Those actions are only available for API version 2022-05-01 and newer. * @throws TextAnalyticsException If analyze operation fails. */ @ServiceMethod(returns = ReturnType.COLLECTION) @@ -2367,6 +2455,13 @@ public PollerFlux * * @throws NullPointerException if {@code documents} or {@code actions} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@code beginAnalyzeActions} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0}. {@code beginAnalyzeActions} is only available for API version + * v3.1 and newer. + * @throws IllegalStateException if request {@link AnalyzeHealthcareEntitiesAction}, + * {@link RecognizeCustomEntitiesAction}, {@link SingleLabelClassifyAction}, or {@link MultiLabelClassifyAction} + * in service API version {@link TextAnalyticsServiceVersion#V3_0} or {@link TextAnalyticsServiceVersion#V3_1}. + * Those actions are only available for API version 2022-05-01 and newer. * @throws TextAnalyticsException If analyze operation fails. */ @ServiceMethod(returns = ReturnType.COLLECTION) diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/TextAnalyticsClient.java b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/TextAnalyticsClient.java index 1fbd69dc6935e..d41e1600ca031 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/TextAnalyticsClient.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/TextAnalyticsClient.java @@ -5,6 +5,7 @@ import com.azure.ai.textanalytics.models.AnalyzeActionsOperationDetail; import com.azure.ai.textanalytics.models.AnalyzeActionsOptions; +import com.azure.ai.textanalytics.models.AnalyzeHealthcareEntitiesAction; import com.azure.ai.textanalytics.models.AnalyzeHealthcareEntitiesOperationDetail; import com.azure.ai.textanalytics.models.AnalyzeHealthcareEntitiesOptions; import com.azure.ai.textanalytics.models.AnalyzeSentimentOptions; @@ -17,11 +18,14 @@ import com.azure.ai.textanalytics.models.KeyPhrasesCollection; import com.azure.ai.textanalytics.models.LinkedEntity; import com.azure.ai.textanalytics.models.LinkedEntityCollection; +import com.azure.ai.textanalytics.models.MultiLabelClassifyAction; import com.azure.ai.textanalytics.models.MultiLabelClassifyOptions; import com.azure.ai.textanalytics.models.PiiEntityCollection; +import com.azure.ai.textanalytics.models.RecognizeCustomEntitiesAction; import com.azure.ai.textanalytics.models.RecognizeCustomEntitiesOperationDetail; import com.azure.ai.textanalytics.models.RecognizeCustomEntitiesOptions; import com.azure.ai.textanalytics.models.RecognizePiiEntitiesOptions; +import com.azure.ai.textanalytics.models.SingleLabelClassifyAction; import com.azure.ai.textanalytics.models.SingleLabelClassifyOptions; import com.azure.ai.textanalytics.models.TextAnalyticsActions; import com.azure.ai.textanalytics.models.TextAnalyticsError; @@ -247,6 +251,9 @@ public DetectedLanguage detectLanguage(String document, String countryHint) { * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@link TextAnalyticsRequestOptions#isServiceLogsDisabled()} is true in service + * API version {@link TextAnalyticsServiceVersion#V3_0}. {@code disableServiceLogs} is only available for API + * version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public DetectLanguageResultCollection detectLanguageBatch( @@ -306,6 +313,9 @@ public DetectLanguageResultCollection detectLanguageBatch( * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@link TextAnalyticsRequestOptions#isServiceLogsDisabled()} is true in service + * API version {@link TextAnalyticsServiceVersion#V3_0}. {@code disableServiceLogs} is only available for API + * version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public Response detectLanguageBatchWithResponse( @@ -427,6 +437,9 @@ public CategorizedEntityCollection recognizeEntities(String document, String lan * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@link TextAnalyticsRequestOptions#isServiceLogsDisabled()} is true in service + * API version {@link TextAnalyticsServiceVersion#V3_0}. {@code disableServiceLogs} is only available for API + * version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public RecognizeEntitiesResultCollection recognizeEntitiesBatch( @@ -481,6 +494,9 @@ public RecognizeEntitiesResultCollection recognizeEntitiesBatch( * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@link TextAnalyticsRequestOptions#isServiceLogsDisabled()} is true in service + * API version {@link TextAnalyticsServiceVersion#V3_0}. {@code disableServiceLogs} is only available for API + * version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public Response recognizeEntitiesBatchWithResponse( @@ -522,6 +538,9 @@ public Response recognizeEntitiesBatchWithRes * * @throws NullPointerException if {@code document} is null. * @throws TextAnalyticsException if the response returned with an {@link TextAnalyticsError error}. + * @throws IllegalStateException if {@code recognizePiiEntities} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0}. {@code recognizePiiEntities} is only available for + * API version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public PiiEntityCollection recognizePiiEntities(String document) { @@ -559,6 +578,9 @@ public PiiEntityCollection recognizePiiEntities(String document) { * * @throws NullPointerException if {@code document} is null. * @throws TextAnalyticsException if the response returned with an {@link TextAnalyticsError error}. + * @throws IllegalStateException if {@code recognizePiiEntities} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0}. {@code recognizePiiEntities} is only available for + * API version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public PiiEntityCollection recognizePiiEntities(String document, String language) { @@ -600,6 +622,9 @@ public PiiEntityCollection recognizePiiEntities(String document, String language * * @throws NullPointerException if {@code document} is null. * @throws TextAnalyticsException if the response returned with an {@link TextAnalyticsError error}. + * @throws IllegalStateException if {@code recognizePiiEntities} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0}. {@code recognizePiiEntities} is only available for + * API version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public PiiEntityCollection recognizePiiEntities(String document, String language, @@ -652,6 +677,9 @@ public PiiEntityCollection recognizePiiEntities(String document, String language * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@code recognizePiiEntitiesBatch} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0}. {@code recognizePiiEntitiesBatch} is only available for + * API version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public RecognizePiiEntitiesResultCollection recognizePiiEntitiesBatch( @@ -707,6 +735,9 @@ public RecognizePiiEntitiesResultCollection recognizePiiEntitiesBatch( * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@code recognizePiiEntitiesBatchWithResponse} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0}. {@code recognizePiiEntitiesBatchWithResponse} is only available for + * API version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public Response recognizePiiEntitiesBatchWithResponse( @@ -843,6 +874,9 @@ public LinkedEntityCollection recognizeLinkedEntities(String document, String la * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@link TextAnalyticsRequestOptions#isServiceLogsDisabled()} is true in service + * API version {@link TextAnalyticsServiceVersion#V3_0}. {@code disableServiceLogs} is only available for API + * version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public RecognizeLinkedEntitiesResultCollection recognizeLinkedEntitiesBatch( @@ -905,6 +939,9 @@ public RecognizeLinkedEntitiesResultCollection recognizeLinkedEntitiesBatch( * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@link TextAnalyticsRequestOptions#isServiceLogsDisabled()} is true in service + * API version {@link TextAnalyticsServiceVersion#V3_0}. {@code disableServiceLogs} is only available for API + * version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public Response recognizeLinkedEntitiesBatchWithResponse( @@ -1025,6 +1062,9 @@ public KeyPhrasesCollection extractKeyPhrases(String document, String language) * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@link TextAnalyticsRequestOptions#isServiceLogsDisabled()} is true in service + * API version {@link TextAnalyticsServiceVersion#V3_0}. {@code disableServiceLogs} is only available for API + * version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public ExtractKeyPhrasesResultCollection extractKeyPhrasesBatch( @@ -1086,6 +1126,9 @@ public ExtractKeyPhrasesResultCollection extractKeyPhrasesBatch( * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@link TextAnalyticsRequestOptions#isServiceLogsDisabled()} is true in service + * API version {@link TextAnalyticsServiceVersion#V3_0}. {@code disableServiceLogs} is only available for API + * version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public Response extractKeyPhrasesBatchWithResponse( @@ -1233,6 +1276,10 @@ public DocumentSentiment analyzeSentiment(String document, String language) { * * @throws NullPointerException if {@code document} is null. * @throws TextAnalyticsException if the response returned with an {@link TextAnalyticsError error}. + * @throws IllegalStateException if {@link AnalyzeSentimentOptions#isServiceLogsDisabled()} or + * {@link AnalyzeSentimentOptions#isIncludeOpinionMining()} is true in service API version + * {@link TextAnalyticsServiceVersion#V3_0}. {@code disableServiceLogs} and {@code includeOpinionMining} are only + * available for API version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public DocumentSentiment analyzeSentiment(String document, String language, AnalyzeSentimentOptions options) { @@ -1360,6 +1407,10 @@ public AnalyzeSentimentResultCollection analyzeSentimentBatch( * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@link AnalyzeSentimentOptions#isServiceLogsDisabled()} or + * {@link AnalyzeSentimentOptions#isIncludeOpinionMining()} is true in service API version + * {@link TextAnalyticsServiceVersion#V3_0}. {@code disableServiceLogs} and {@code includeOpinionMining} are only + * available for API version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public AnalyzeSentimentResultCollection analyzeSentimentBatch(Iterable documents, @@ -1515,6 +1566,10 @@ public Response analyzeSentimentBatchWithRespo * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@link AnalyzeSentimentOptions#isServiceLogsDisabled()} or + * {@link AnalyzeSentimentOptions#isIncludeOpinionMining()} is true in service API version + * {@link TextAnalyticsServiceVersion#V3_0}. {@code disableServiceLogs} and {@code includeOpinionMining} are only + * available for API version v3.1 and newer. */ @ServiceMethod(returns = ReturnType.SINGLE) public Response analyzeSentimentBatchWithResponse( @@ -1541,6 +1596,9 @@ public Response analyzeSentimentBatchWithRespo * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@code beginAnalyzeHealthcareEntities} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0}. {@code beginAnalyzeHealthcareEntities} is only available for API + * version v3.1 and newer. * @throws TextAnalyticsException If analyze operation fails. */ @ServiceMethod(returns = ReturnType.COLLECTION) @@ -1642,6 +1700,9 @@ public Response analyzeSentimentBatchWithRespo * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@code beginAnalyzeHealthcareEntities} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0}. {@code beginAnalyzeHealthcareEntities} is only available for API + * version v3.1 and newer. * @throws TextAnalyticsException If analyze operation fails. */ @ServiceMethod(returns = ReturnType.COLLECTION) @@ -1706,6 +1767,9 @@ public Response analyzeSentimentBatchWithRespo * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@code beginRecognizeCustomEntities} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0} or {@link TextAnalyticsServiceVersion#V3_1}. + * {@code beginRecognizeCustomEntities} is only available for API version 2022-05-01 and newer. * @throws TextAnalyticsException If analyze operation fails. */ @ServiceMethod(returns = ReturnType.COLLECTION) @@ -1774,6 +1838,9 @@ public Response analyzeSentimentBatchWithRespo * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@code beginRecognizeCustomEntities} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0} or {@link TextAnalyticsServiceVersion#V3_1}. + * {@code beginRecognizeCustomEntities} is only available for API version 2022-05-01 and newer. * @throws TextAnalyticsException If analyze operation fails. */ @ServiceMethod(returns = ReturnType.COLLECTION) @@ -1841,6 +1908,9 @@ public Response analyzeSentimentBatchWithRespo * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@code beginSingleLabelClassify} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0} or {@link TextAnalyticsServiceVersion#V3_1}. + * {@code beginSingleLabelClassify} is only available for API version 2022-05-01 and newer. * @throws TextAnalyticsException If analyze operation fails. */ @ServiceMethod(returns = ReturnType.COLLECTION) @@ -1907,6 +1977,9 @@ public Response analyzeSentimentBatchWithRespo * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@code beginSingleLabelClassify} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0} or {@link TextAnalyticsServiceVersion#V3_1}. + * {@code beginSingleLabelClassify} is only available for API version 2022-05-01 and newer. * @throws TextAnalyticsException If analyze operation fails. */ @ServiceMethod(returns = ReturnType.COLLECTION) @@ -1968,6 +2041,9 @@ public Response analyzeSentimentBatchWithRespo * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@code beginMultiLabelClassify} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0} or {@link TextAnalyticsServiceVersion#V3_1}. + * {@code beginMultiLabelClassify} is only available for API version 2022-05-01 and newer. * @throws TextAnalyticsException If analyze operation fails. */ @ServiceMethod(returns = ReturnType.COLLECTION) @@ -2030,6 +2106,9 @@ public Response analyzeSentimentBatchWithRespo * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@code beginMultiLabelClassify} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0} or {@link TextAnalyticsServiceVersion#V3_1}. + * {@code beginMultiLabelClassify} is only available for API version 2022-05-01 and newer. * @throws TextAnalyticsException If analyze operation fails. */ @ServiceMethod(returns = ReturnType.COLLECTION) @@ -2109,6 +2188,13 @@ public Response analyzeSentimentBatchWithRespo * * @throws NullPointerException if {@code documents} is null. * @throws IllegalArgumentException if {@code documents} is empty. + * @throws IllegalStateException if {@code beginAnalyzeActions} is called with service API version + * {@link TextAnalyticsServiceVersion#V3_0}. {@code beginAnalyzeActions} is only available for API version + * v3.1 and newer. + * @throws IllegalStateException if request {@link AnalyzeHealthcareEntitiesAction}, + * {@link RecognizeCustomEntitiesAction}, {@link SingleLabelClassifyAction}, or {@link MultiLabelClassifyAction} + * in service API version {@link TextAnalyticsServiceVersion#V3_0} or {@link TextAnalyticsServiceVersion#V3_1}. + * Those actions are only available for API version 2022-05-01 and newer. * @throws TextAnalyticsException If analyze operation fails. */ @ServiceMethod(returns = ReturnType.COLLECTION) @@ -2188,6 +2274,13 @@ public SyncPoller targetVersions, + String errorMessage) { + for (TextAnalyticsServiceVersion targetVersion : targetVersions) { + if (targetVersion != null && sourceVersion != null + && targetVersion.getVersion().equals(sourceVersion.getVersion())) { + throw LOGGER.logExceptionAsError(new IllegalStateException(errorMessage)); + } + } + } + + /** + * Retrieve custom unsupported Service API version error message. + * + * @param unsupportedName The unsupported API or property name that the not available in 'minSupportedVersion'. + * @param sourceVersion The source service API version that client is using. + * @param minSupportedVersion The minimum supported Service API version. + * @return The error message. + */ + public static String getUnsupportedServiceApiVersionMessage(String unsupportedName, + TextAnalyticsServiceVersion sourceVersion, TextAnalyticsServiceVersion minSupportedVersion) { + return String.format("'%s' is not available in API version %s. Use service API version '%s' or newer.", + unsupportedName, sourceVersion, minSupportedVersion); + } } diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/AnalyzeHealthcareEntitiesOperationDetail.java b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/AnalyzeHealthcareEntitiesOperationDetail.java index b792b888ef28e..ac90fcf9e1f91 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/AnalyzeHealthcareEntitiesOperationDetail.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/AnalyzeHealthcareEntitiesOperationDetail.java @@ -14,6 +14,7 @@ @Immutable public final class AnalyzeHealthcareEntitiesOperationDetail { private String operationId; + private String displayName; private OffsetDateTime createdAt; private OffsetDateTime expiresAt; private OffsetDateTime lastModifiedAt; @@ -28,6 +29,11 @@ public void setOperationId(AnalyzeHealthcareEntitiesOperationDetail operationRes operationResult.setOperationId(operationId); } + @Override + public void setDisplayName(AnalyzeHealthcareEntitiesOperationDetail operationDetail, String name) { + operationDetail.setDisplayName(name); + } + @Override public void setExpiresAt(AnalyzeHealthcareEntitiesOperationDetail operationDetail, OffsetDateTime expiresAt) { @@ -58,6 +64,15 @@ public String getOperationId() { return operationId; } + /** + * Gets the displayName property of the {@link AnalyzeHealthcareEntitiesOperationDetail}. + * + * @return The displayName property of the {@link AnalyzeHealthcareEntitiesOperationDetail}. + */ + public String getDisplayName() { + return displayName; + } + /** * Gets the created time of an action. * @@ -89,6 +104,10 @@ private void setOperationId(String operationId) { this.operationId = operationId; } + private void setDisplayName(String displayName) { + this.displayName = displayName; + } + private void setCreatedAt(OffsetDateTime createdAt) { this.createdAt = createdAt; } diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/AnalyzeHealthcareEntitiesOptions.java b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/AnalyzeHealthcareEntitiesOptions.java index fe14b97b08d7e..8d3726497a51f 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/AnalyzeHealthcareEntitiesOptions.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/AnalyzeHealthcareEntitiesOptions.java @@ -10,8 +10,30 @@ */ @Fluent public final class AnalyzeHealthcareEntitiesOptions extends TextAnalyticsRequestOptions { + private String displayName; private Boolean disableServiceLogs; + /** + * Gets display name of the operation. + * + * @return Display name of the operation. + */ + public String getDisplayName() { + return displayName; + } + + /** + * Sets display name of the operation. + * + * @param displayName Display name of the operation. + * + * @return The {@link AnalyzeHealthcareEntitiesOptions} object itself. + */ + public AnalyzeHealthcareEntitiesOptions setDisplayName(String displayName) { + this.displayName = displayName; + return this; + } + /** * Sets the model version. This value indicates which model will be used for scoring, e.g. "latest", "2019-10-01". * If a model-version is not specified, the API will default to the latest, non-preview version. diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/ClassifyDocumentOperationDetail.java b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/ClassifyDocumentOperationDetail.java index 84b144dc9558e..9956fa3af812e 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/ClassifyDocumentOperationDetail.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/ClassifyDocumentOperationDetail.java @@ -14,6 +14,7 @@ @Immutable public final class ClassifyDocumentOperationDetail { private String operationId; + private String displayName; private OffsetDateTime createdAt; private OffsetDateTime expiresAt; private OffsetDateTime lastModifiedAt; @@ -27,6 +28,11 @@ public void setOperationId(ClassifyDocumentOperationDetail operationResult, operationResult.setOperationId(operationId); } + @Override + public void setDisplayName(ClassifyDocumentOperationDetail operationDetail, String name) { + operationDetail.setDisplayName(name); + } + @Override public void setExpiresAt(ClassifyDocumentOperationDetail operationDetail, OffsetDateTime expiresAt) { @@ -57,6 +63,15 @@ public String getOperationId() { return operationId; } + /** + * Gets the displayName property of the {@link ClassifyDocumentOperationDetail}. + * + * @return The displayName property of the {@link ClassifyDocumentOperationDetail}. + */ + public String getDisplayName() { + return displayName; + } + /** * Gets the created time of an action. * @@ -88,6 +103,10 @@ private void setOperationId(String operationId) { this.operationId = operationId; } + private void setDisplayName(String displayName) { + this.displayName = displayName; + } + private void setCreatedAt(OffsetDateTime createdAt) { this.createdAt = createdAt; } diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/LinkedEntity.java b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/LinkedEntity.java index b25317c8e4ae3..73d15084243cb 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/LinkedEntity.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/LinkedEntity.java @@ -45,7 +45,7 @@ public final class LinkedEntity { /* * Bing Entity Search unique identifier of the recognized entity. Use in conjunction with * the Bing Entity Search API to fetch additional relevant information. Only available for API version - * v3.1 and up. + * v3.1 and newer. */ private String bingEntitySearchApiId; @@ -131,7 +131,7 @@ public String getDataSource() { /** * Gets the bingEntitySearchApiId property: Bing Entity Search unique identifier of the recognized entity. * Use in conjunction with the Bing Entity Search SDK to fetch additional relevant information. Only available - * for API version v3.1 and up. + * for API version v3.1 and newer. * * @return The bingEntitySearchApiId value. */ diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/MultiLabelClassifyOptions.java b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/MultiLabelClassifyOptions.java index e957c5dc37ed6..6011650072fe2 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/MultiLabelClassifyOptions.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/MultiLabelClassifyOptions.java @@ -10,9 +10,31 @@ */ @Fluent public final class MultiLabelClassifyOptions { + private String displayName; private boolean disableServiceLogs; private boolean includeStatistics; + /** + * Gets display name of the operation. + * + * @return Display name of the operation. + */ + public String getDisplayName() { + return displayName; + } + + /** + * Sets display name of the operation. + * + * @param displayName Display name of the operation. + * + * @return The {@link MultiLabelClassifyOptions} object itself. + */ + public MultiLabelClassifyOptions setDisplayName(String displayName) { + this.displayName = displayName; + return this; + } + /** * Get the value of {@code includeStatistics}. * diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/PiiEntityCollection.java b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/PiiEntityCollection.java index 9a4f9cc735d69..4b815103e94d6 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/PiiEntityCollection.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/PiiEntityCollection.java @@ -41,7 +41,7 @@ public IterableStream getWarnings() { /** * Get the property redactedText value. The text of the input document with all of the PII information redacted out. - * Only returned for API version v3.1 and up. + * Only returned for API version v3.1 and newer. * * @return The text of the input document with all of the PII information redacted out. */ diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/RecognizeCustomEntitiesOperationDetail.java b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/RecognizeCustomEntitiesOperationDetail.java index e31b068230a53..f8e7fa41e3dfe 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/RecognizeCustomEntitiesOperationDetail.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/RecognizeCustomEntitiesOperationDetail.java @@ -14,6 +14,7 @@ @Immutable public final class RecognizeCustomEntitiesOperationDetail { private String operationId; + private String displayName; private OffsetDateTime createdAt; private OffsetDateTime expiresAt; private OffsetDateTime lastModifiedAt; @@ -28,6 +29,11 @@ public void setOperationId(RecognizeCustomEntitiesOperationDetail operationResul operationResult.setOperationId(operationId); } + @Override + public void setDisplayName(RecognizeCustomEntitiesOperationDetail operationDetail, String name) { + operationDetail.setDisplayName(name); + } + @Override public void setExpiresAt(RecognizeCustomEntitiesOperationDetail operationDetail, OffsetDateTime expiresAt) { @@ -58,6 +64,15 @@ public String getOperationId() { return operationId; } + /** + * Gets the displayName property of the {@link RecognizeCustomEntitiesOperationDetail}. + * + * @return The displayName property of the {@link RecognizeCustomEntitiesOperationDetail}. + */ + public String getDisplayName() { + return displayName; + } + /** * Gets the created time of an action. * @@ -89,6 +104,10 @@ private void setOperationId(String operationId) { this.operationId = operationId; } + private void setDisplayName(String displayName) { + this.displayName = displayName; + } + private void setCreatedAt(OffsetDateTime createdAt) { this.createdAt = createdAt; } diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/RecognizeCustomEntitiesOptions.java b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/RecognizeCustomEntitiesOptions.java index b7c0c166b99af..e0ba43882c073 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/RecognizeCustomEntitiesOptions.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/RecognizeCustomEntitiesOptions.java @@ -10,9 +10,31 @@ */ @Fluent public final class RecognizeCustomEntitiesOptions { + private String displayName; private boolean includeStatistics; private boolean disableServiceLogs; + /** + * Gets display name of the operation. + * + * @return Display name of the operation. + */ + public String getDisplayName() { + return displayName; + } + + /** + * Sets display name of the operation. + * + * @param displayName Display name of the operation. + * + * @return The {@link RecognizeCustomEntitiesOptions} object itself. + */ + public RecognizeCustomEntitiesOptions setDisplayName(String displayName) { + this.displayName = displayName; + return this; + } + /** * Get the value of {@code includeStatistics}. * diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/SingleLabelClassifyOptions.java b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/SingleLabelClassifyOptions.java index 2ebb0c360e5f5..d2dca22272fba 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/SingleLabelClassifyOptions.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/main/java/com/azure/ai/textanalytics/models/SingleLabelClassifyOptions.java @@ -10,9 +10,31 @@ */ @Fluent public final class SingleLabelClassifyOptions { + private String displayName; private boolean disableServiceLogs; private boolean includeStatistics; + /** + * Gets display name of the operation. + * + * @return Display name of the operation. + */ + public String getDisplayName() { + return displayName; + } + + /** + * Sets display name of the operation. + * + * @param displayName Display name of the operation. + * + * @return The {@link SingleLabelClassifyOptions} object itself. + */ + public SingleLabelClassifyOptions setDisplayName(String displayName) { + this.displayName = displayName; + return this; + } + /** * Get the value of {@code includeStatistics}. * diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/test/java/com/azure/ai/textanalytics/ClientSideValidationUnitTests.java b/sdk/textanalytics/azure-ai-textanalytics/src/test/java/com/azure/ai/textanalytics/ClientSideValidationUnitTests.java new file mode 100644 index 0000000000000..056e078ae0dad --- /dev/null +++ b/sdk/textanalytics/azure-ai-textanalytics/src/test/java/com/azure/ai/textanalytics/ClientSideValidationUnitTests.java @@ -0,0 +1,410 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.ai.textanalytics; + +import com.azure.ai.textanalytics.models.AnalyzeHealthcareEntitiesAction; +import com.azure.ai.textanalytics.models.AnalyzeHealthcareEntitiesOptions; +import com.azure.ai.textanalytics.models.AnalyzeSentimentOptions; +import com.azure.ai.textanalytics.models.MultiLabelClassifyAction; +import com.azure.ai.textanalytics.models.RecognizeCustomEntitiesAction; +import com.azure.ai.textanalytics.models.SingleLabelClassifyAction; +import com.azure.ai.textanalytics.models.TextAnalyticsActions; +import com.azure.ai.textanalytics.models.TextAnalyticsRequestOptions; +import com.azure.core.credential.AzureKeyCredential; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import reactor.test.StepVerifier; + +import java.util.Arrays; +import java.util.List; + +import static com.azure.ai.textanalytics.TestUtils.VALID_HTTPS_LOCALHOST; +import static com.azure.ai.textanalytics.implementation.Utility.getUnsupportedServiceApiVersionMessage; +import static com.azure.ai.textanalytics.implementation.Utility.throwIfTargetServiceVersionFound; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Unit tests for Text Analytics client side validation + */ +public class ClientSideValidationUnitTests { + static TextAnalyticsClient clientV30; + static TextAnalyticsClient clientV31; + static TextAnalyticsAsyncClient asyncClientV30; + static TextAnalyticsAsyncClient asyncClientV31; + static List dummyDocument = Arrays.asList("A tree", "Be good"); + static final String DISABLE_SERVICE_LOGS_ERROR_MESSAGE = + getUnsupportedServiceApiVersionMessage("TextAnalyticsRequestOptions.disableServiceLogs", + TextAnalyticsServiceVersion.V3_0, TextAnalyticsServiceVersion.V3_1); + static final String RECOGNIZE_PII_ENTITIES_ERROR_MESSAGE = + getUnsupportedServiceApiVersionMessage("recognizePiiEntitiesBatch", TextAnalyticsServiceVersion.V3_0, + TextAnalyticsServiceVersion.V3_1); + static final String OPINION_MINING_ERROR_MESSAGE = + getUnsupportedServiceApiVersionMessage("AnalyzeSentimentOptions.includeOpinionMining", + TextAnalyticsServiceVersion.V3_0, TextAnalyticsServiceVersion.V3_1); + static final String ANALYZE_ACTIONS_ERROR_MESSAGE = + getUnsupportedServiceApiVersionMessage("beginAnalyzeActions", TextAnalyticsServiceVersion.V3_0, + TextAnalyticsServiceVersion.V3_1); + static final String HEALTHCARE_ENTITIES_ACTION_ERROR_MESSAGE = + getUnsupportedServiceApiVersionMessage("AnalyzeHealthcareEntitiesAction", TextAnalyticsServiceVersion.V3_1, + TextAnalyticsServiceVersion.V2022_05_01); + static final String CUSTOM_ENTITIES_ACTION_ERROR_MESSAGE = + getUnsupportedServiceApiVersionMessage("RecognizeCustomEntitiesAction", TextAnalyticsServiceVersion.V3_1, + TextAnalyticsServiceVersion.V2022_05_01); + static final String SINGLE_LABEL_ACTION_ERROR_MESSAGE = + getUnsupportedServiceApiVersionMessage("SingleLabelClassifyAction", TextAnalyticsServiceVersion.V3_1, + TextAnalyticsServiceVersion.V2022_05_01); + static final String MULTI_LABEL_ACTION_ERROR_MESSAGE = + getUnsupportedServiceApiVersionMessage("MultiLabelClassifyAction", TextAnalyticsServiceVersion.V3_1, + TextAnalyticsServiceVersion.V2022_05_01); + static final String ANALYZE_HEALTHCARE_ENTITIES_ERROR_MESSAGE = + getUnsupportedServiceApiVersionMessage("beginAnalyzeHealthcareEntities", + TextAnalyticsServiceVersion.V3_0, TextAnalyticsServiceVersion.V3_1); + static final String HEALTHCARE_ENTITIES_DISPLAY_NAME_ERROR_MESSAGE = + getUnsupportedServiceApiVersionMessage("AnalyzeHealthcareEntitiesOptions.displayName", + TextAnalyticsServiceVersion.V3_1, TextAnalyticsServiceVersion.V2022_05_01); + static final String RECOGNIZE_CUSTOM_ENTITIES_ERROR_MESSAGE_30 = + getUnsupportedServiceApiVersionMessage("beginRecognizeCustomEntities", + TextAnalyticsServiceVersion.V3_0, TextAnalyticsServiceVersion.V2022_05_01); + static final String RECOGNIZE_CUSTOM_ENTITIES_ERROR_MESSAGE_31 = + getUnsupportedServiceApiVersionMessage("beginRecognizeCustomEntities", + TextAnalyticsServiceVersion.V3_1, TextAnalyticsServiceVersion.V2022_05_01); + static final String SINGLE_LABEL_CLASSIFY_ERROR_MESSAGE_30 = + getUnsupportedServiceApiVersionMessage("beginSingleLabelClassify", TextAnalyticsServiceVersion.V3_0, + TextAnalyticsServiceVersion.V2022_05_01); + static final String SINGLE_LABEL_CLASSIFY_ERROR_MESSAGE_31 = + getUnsupportedServiceApiVersionMessage("beginSingleLabelClassify", TextAnalyticsServiceVersion.V3_1, + TextAnalyticsServiceVersion.V2022_05_01); + static final String MULTI_LABEL_CLASSIFY_ERROR_MESSAGE_30 = + getUnsupportedServiceApiVersionMessage("beginMultiLabelClassify", TextAnalyticsServiceVersion.V3_0, + TextAnalyticsServiceVersion.V2022_05_01); + static final String MULTI_LABEL_CLASSIFY_ERROR_MESSAGE_31 = + getUnsupportedServiceApiVersionMessage("beginMultiLabelClassify", TextAnalyticsServiceVersion.V3_1, + TextAnalyticsServiceVersion.V2022_05_01); + static final String PROJECT_NAME = "project-name"; + static final String DEPLOYMENT_NAME = "deployment-name"; + static final String LANGUAGE_EN = "en"; + + @BeforeAll + protected static void beforeTest() { + TextAnalyticsClientBuilder builder = new TextAnalyticsClientBuilder() + .endpoint(VALID_HTTPS_LOCALHOST) + .credential(new AzureKeyCredential("fakeKey")); + clientV30 = builder.serviceVersion(TextAnalyticsServiceVersion.V3_0).buildClient(); + asyncClientV30 = builder.serviceVersion(TextAnalyticsServiceVersion.V3_0).buildAsyncClient(); + clientV31 = builder.serviceVersion(TextAnalyticsServiceVersion.V3_1).buildClient(); + asyncClientV31 = builder.serviceVersion(TextAnalyticsServiceVersion.V3_1).buildAsyncClient(); + } + + @AfterAll + protected static void afterTest() { + clientV30 = null; + asyncClientV30 = null; + clientV31 = null; + asyncClientV31 = null; + } + + @Test + public void detectLanguageClientSideValidation() { + TextAnalyticsRequestOptions enableServiceLogsOption = new TextAnalyticsRequestOptions().setServiceLogsDisabled(true); + // Async + StepVerifier.create(asyncClientV30.detectLanguageBatch(dummyDocument, null, enableServiceLogsOption)) + .verifyErrorSatisfies(exception -> { + assertEquals(IllegalStateException.class, exception.getClass()); + assertEquals(DISABLE_SERVICE_LOGS_ERROR_MESSAGE, exception.getMessage()); + }); + + // Sync + IllegalStateException exception = assertThrows(IllegalStateException.class, + () -> clientV30.detectLanguageBatch(dummyDocument, null, enableServiceLogsOption)); + assertEquals(DISABLE_SERVICE_LOGS_ERROR_MESSAGE, exception.getMessage()); + } + + + @Test + public void recognizeEntitiesClientSideValidation() { + TextAnalyticsRequestOptions enableServiceLogsOption = new TextAnalyticsRequestOptions().setServiceLogsDisabled(true); + + // Async + StepVerifier.create(asyncClientV30.recognizeEntitiesBatch(dummyDocument, null, enableServiceLogsOption)) + .verifyErrorSatisfies(exception -> { + assertEquals(IllegalStateException.class, exception.getClass()); + assertTrue(DISABLE_SERVICE_LOGS_ERROR_MESSAGE.equals(exception.getMessage())); + }); + + // Sync + IllegalStateException exception = assertThrows(IllegalStateException.class, + () -> clientV30.recognizeEntitiesBatch(dummyDocument, null, enableServiceLogsOption)); + assertEquals(DISABLE_SERVICE_LOGS_ERROR_MESSAGE, exception.getMessage()); + } + + @Test + public void recognizePiiEntitiesClientSideValidation() { + // Async + StepVerifier.create(asyncClientV30.recognizePiiEntitiesBatch(dummyDocument, null, null)) + .verifyErrorSatisfies(exception -> { + assertEquals(IllegalStateException.class, exception.getClass()); + assertTrue(RECOGNIZE_PII_ENTITIES_ERROR_MESSAGE.equals(exception.getMessage())); + }); + + // Sync + IllegalStateException exception = assertThrows(IllegalStateException.class, + () -> clientV30.recognizePiiEntitiesBatch(dummyDocument, null, null)); + assertEquals(RECOGNIZE_PII_ENTITIES_ERROR_MESSAGE, exception.getMessage()); + } + + @Test + public void recognizeLinkedEntitiesClientSideValidation() { + TextAnalyticsRequestOptions enableServiceLogsOption = new TextAnalyticsRequestOptions().setServiceLogsDisabled(true); + + // Async + StepVerifier.create(asyncClientV30.recognizeLinkedEntitiesBatch(dummyDocument, null, enableServiceLogsOption)) + .verifyErrorSatisfies(exception -> { + assertEquals(IllegalStateException.class, exception.getClass()); + assertEquals(DISABLE_SERVICE_LOGS_ERROR_MESSAGE, exception.getMessage()); + }); + + // Sync + IllegalStateException exception = assertThrows(IllegalStateException.class, + () -> clientV30.recognizeLinkedEntitiesBatch(dummyDocument, null, enableServiceLogsOption)); + assertEquals(DISABLE_SERVICE_LOGS_ERROR_MESSAGE, exception.getMessage()); + } + + @Test + public void extractKeyPhrasesClientSideValidation() { + TextAnalyticsRequestOptions enableServiceLogsOption = new TextAnalyticsRequestOptions().setServiceLogsDisabled(true); + + // Async + StepVerifier.create(asyncClientV30.extractKeyPhrasesBatch(dummyDocument, null, enableServiceLogsOption)) + .verifyErrorSatisfies(exception -> { + assertEquals(IllegalStateException.class, exception.getClass()); + assertEquals(DISABLE_SERVICE_LOGS_ERROR_MESSAGE, exception.getMessage()); + }); + + // Sync + IllegalStateException exception = assertThrows(IllegalStateException.class, + () -> clientV30.extractKeyPhrasesBatch(dummyDocument, null, enableServiceLogsOption)); + assertEquals(DISABLE_SERVICE_LOGS_ERROR_MESSAGE, exception.getMessage()); + } + + @Test + public void analyzeSentimentClientSideValidation() { + AnalyzeSentimentOptions enableServiceLogsOption = new AnalyzeSentimentOptions().setServiceLogsDisabled(true); + + // Async + StepVerifier.create(asyncClientV30.analyzeSentimentBatch(dummyDocument, null, enableServiceLogsOption)) + .verifyErrorSatisfies(exception -> { + assertEquals(IllegalStateException.class, exception.getClass()); + assertEquals(DISABLE_SERVICE_LOGS_ERROR_MESSAGE, exception.getMessage()); + }); + + AnalyzeSentimentOptions includeOpinionMiningOption = new AnalyzeSentimentOptions().setIncludeOpinionMining(true); + StepVerifier.create(asyncClientV30.analyzeSentimentBatch(dummyDocument, null, includeOpinionMiningOption)) + .verifyErrorSatisfies(exception -> { + assertEquals(IllegalStateException.class, exception.getClass()); + assertEquals(OPINION_MINING_ERROR_MESSAGE, exception.getMessage()); + }); + + // Sync + IllegalStateException exception = assertThrows(IllegalStateException.class, + () -> clientV30.analyzeSentimentBatch(dummyDocument, null, enableServiceLogsOption)); + assertEquals(DISABLE_SERVICE_LOGS_ERROR_MESSAGE, exception.getMessage()); + + IllegalStateException includeOpinionMiningException = assertThrows(IllegalStateException.class, + () -> clientV30.analyzeSentimentBatch(dummyDocument, null, includeOpinionMiningOption)); + assertEquals(OPINION_MINING_ERROR_MESSAGE, includeOpinionMiningException.getMessage()); + } + + @Test + public void analyzeActionsClientSideValidation() { + TextAnalyticsActions actions = new TextAnalyticsActions(); + // Async + // beginAnalyzeActions is only supported in 3.1 and newer + StepVerifier.create(asyncClientV30.beginAnalyzeActions(dummyDocument, actions, LANGUAGE_EN, null)) + .verifyErrorSatisfies(exception -> { + assertEquals(IllegalStateException.class, exception.getClass()); + assertEquals(ANALYZE_ACTIONS_ERROR_MESSAGE, exception.getMessage()); + }); + // AnalyzeHealthcareEntitiesAction is only supported in 2022-05-01 and newer + TextAnalyticsActions healthcareEntitiesActions = + new TextAnalyticsActions() + .setAnalyzeHealthcareEntitiesActions(new AnalyzeHealthcareEntitiesAction()); + StepVerifier.create(asyncClientV31.beginAnalyzeActions(dummyDocument, healthcareEntitiesActions, LANGUAGE_EN, + null)) + .verifyErrorSatisfies(exception -> { + assertEquals(IllegalStateException.class, exception.getClass()); + assertEquals(HEALTHCARE_ENTITIES_ACTION_ERROR_MESSAGE, exception.getMessage()); + }); + // RecognizeCustomEntitiesAction is only supported in 2022-05-01 and newer + TextAnalyticsActions customEntitiesActions = + new TextAnalyticsActions() + .setRecognizeCustomEntitiesActions(new RecognizeCustomEntitiesAction(PROJECT_NAME, DEPLOYMENT_NAME)); + StepVerifier.create(asyncClientV31.beginAnalyzeActions(dummyDocument, customEntitiesActions, LANGUAGE_EN, + null)) + .verifyErrorSatisfies(exception -> { + assertEquals(IllegalStateException.class, exception.getClass()); + assertEquals(CUSTOM_ENTITIES_ACTION_ERROR_MESSAGE, exception.getMessage()); + }); + // SingleLabelClassifyAction is only supported in 2022-05-01 and newer + TextAnalyticsActions singleLabelClassifyActions = + new TextAnalyticsActions() + .setSingleLabelClassifyActions(new SingleLabelClassifyAction(PROJECT_NAME, DEPLOYMENT_NAME)); + StepVerifier.create(asyncClientV31.beginAnalyzeActions(dummyDocument, singleLabelClassifyActions, LANGUAGE_EN, + null)) + .verifyErrorSatisfies(exception -> { + assertEquals(IllegalStateException.class, exception.getClass()); + assertEquals(SINGLE_LABEL_ACTION_ERROR_MESSAGE, exception.getMessage()); + }); + // MultiLabelClassifyAction is only supported in 2022-05-01 and newer + TextAnalyticsActions multiLabelClassifyActions = + new TextAnalyticsActions() + .setMultiLabelClassifyActions(new MultiLabelClassifyAction(PROJECT_NAME, DEPLOYMENT_NAME)); + StepVerifier.create(asyncClientV31.beginAnalyzeActions(dummyDocument, multiLabelClassifyActions, LANGUAGE_EN, + null)) + .verifyErrorSatisfies(exception -> { + assertEquals(IllegalStateException.class, exception.getClass()); + assertEquals(MULTI_LABEL_ACTION_ERROR_MESSAGE, exception.getMessage()); + }); + + // Sync + // beginAnalyzeActions is only supported in 3.1 and newer + IllegalStateException exception = assertThrows(IllegalStateException.class, + () -> clientV30.beginAnalyzeActions(dummyDocument, actions, LANGUAGE_EN, null)); + assertEquals(ANALYZE_ACTIONS_ERROR_MESSAGE, exception.getMessage()); + // AnalyzeHealthcareEntitiesAction is only supported in 2022-05-01 and newer + IllegalStateException healthcareEntitiesActionsException = assertThrows(IllegalStateException.class, + () -> clientV31.beginAnalyzeActions(dummyDocument, healthcareEntitiesActions, LANGUAGE_EN, null)); + assertEquals(HEALTHCARE_ENTITIES_ACTION_ERROR_MESSAGE, healthcareEntitiesActionsException.getMessage()); + // RecognizeCustomEntitiesAction is only supported in 2022-05-01 and newer + IllegalStateException customEntitiesActionsException = assertThrows(IllegalStateException.class, + () -> clientV31.beginAnalyzeActions(dummyDocument, customEntitiesActions, LANGUAGE_EN, null)); + assertEquals(CUSTOM_ENTITIES_ACTION_ERROR_MESSAGE, customEntitiesActionsException.getMessage()); + // SingleLabelClassifyAction is only supported in 2022-05-01 and newer + IllegalStateException singleLabelClassifyActionsException = assertThrows(IllegalStateException.class, + () -> clientV31.beginAnalyzeActions(dummyDocument, singleLabelClassifyActions, LANGUAGE_EN, null)); + assertEquals(SINGLE_LABEL_ACTION_ERROR_MESSAGE, singleLabelClassifyActionsException.getMessage()); + // MultiLabelClassifyAction is only supported in 2022-05-01 and newer + IllegalStateException multiLabelClassifyActionsException = assertThrows(IllegalStateException.class, + () -> clientV31.beginAnalyzeActions(dummyDocument, multiLabelClassifyActions, LANGUAGE_EN, null)); + assertEquals(MULTI_LABEL_ACTION_ERROR_MESSAGE, multiLabelClassifyActionsException.getMessage()); + } + + @Test + public void analyzeHealthcareEntitiesClientSideValidation() { + // Async + StepVerifier.create(asyncClientV30.beginAnalyzeHealthcareEntities(dummyDocument, null, null)) + .verifyErrorSatisfies(exception -> { + assertEquals(IllegalStateException.class, exception.getClass()); + assertEquals(ANALYZE_HEALTHCARE_ENTITIES_ERROR_MESSAGE, exception.getMessage()); + }); + AnalyzeHealthcareEntitiesOptions displayNameOptions = new AnalyzeHealthcareEntitiesOptions() + .setDisplayName("operationName"); + StepVerifier.create(asyncClientV31.beginAnalyzeHealthcareEntities(dummyDocument, null, displayNameOptions)) + .verifyErrorSatisfies(exception -> { + assertEquals(IllegalStateException.class, exception.getClass()); + assertEquals(HEALTHCARE_ENTITIES_DISPLAY_NAME_ERROR_MESSAGE, exception.getMessage()); + }); + + // Sync + IllegalStateException exception = assertThrows(IllegalStateException.class, + () -> clientV30.beginAnalyzeHealthcareEntities(dummyDocument, null, null)); + assertEquals(ANALYZE_HEALTHCARE_ENTITIES_ERROR_MESSAGE, exception.getMessage()); + IllegalStateException displayNameException = assertThrows(IllegalStateException.class, + () -> clientV31.beginAnalyzeHealthcareEntities(dummyDocument, null, displayNameOptions)); + assertEquals(HEALTHCARE_ENTITIES_DISPLAY_NAME_ERROR_MESSAGE, displayNameException.getMessage()); + } + + @Test + public void recognizeCustomEntitiesClientSideValidation() { + // Async + StepVerifier.create(asyncClientV30.beginRecognizeCustomEntities(dummyDocument, PROJECT_NAME, DEPLOYMENT_NAME, + null, null)) + .verifyErrorSatisfies(exception -> { + assertEquals(IllegalStateException.class, exception.getClass()); + assertEquals(RECOGNIZE_CUSTOM_ENTITIES_ERROR_MESSAGE_30, exception.getMessage()); + }); + StepVerifier.create(asyncClientV31.beginRecognizeCustomEntities(dummyDocument, PROJECT_NAME, DEPLOYMENT_NAME, + null, null)) + .verifyErrorSatisfies(exception -> { + assertEquals(IllegalStateException.class, exception.getClass()); + assertEquals(RECOGNIZE_CUSTOM_ENTITIES_ERROR_MESSAGE_31, exception.getMessage()); + }); + // Sync + IllegalStateException exception30 = assertThrows(IllegalStateException.class, + () -> clientV30.beginRecognizeCustomEntities(dummyDocument, PROJECT_NAME, DEPLOYMENT_NAME, null, null)); + assertEquals(RECOGNIZE_CUSTOM_ENTITIES_ERROR_MESSAGE_30, exception30.getMessage()); + + IllegalStateException exception31 = assertThrows(IllegalStateException.class, + () -> clientV31.beginRecognizeCustomEntities(dummyDocument, PROJECT_NAME, DEPLOYMENT_NAME, null, null)); + assertEquals(RECOGNIZE_CUSTOM_ENTITIES_ERROR_MESSAGE_31, exception31.getMessage()); + } + + @Test + public void singleLabelClassificationClientSideValidation() { + // Async + StepVerifier.create(asyncClientV30.beginSingleLabelClassify(dummyDocument, PROJECT_NAME, DEPLOYMENT_NAME, + null, null)) + .verifyErrorSatisfies(exception -> { + assertEquals(IllegalStateException.class, exception.getClass()); + assertEquals(SINGLE_LABEL_CLASSIFY_ERROR_MESSAGE_30, exception.getMessage()); + }); + StepVerifier.create(asyncClientV31.beginSingleLabelClassify(dummyDocument, PROJECT_NAME, DEPLOYMENT_NAME, + null, null)) + .verifyErrorSatisfies(exception -> { + assertEquals(IllegalStateException.class, exception.getClass()); + assertEquals(SINGLE_LABEL_CLASSIFY_ERROR_MESSAGE_31, exception.getMessage()); + }); + + // Sync + IllegalStateException exception30 = assertThrows(IllegalStateException.class, + () -> clientV30.beginSingleLabelClassify(dummyDocument, PROJECT_NAME, DEPLOYMENT_NAME, null, null)); + assertEquals(SINGLE_LABEL_CLASSIFY_ERROR_MESSAGE_30, exception30.getMessage()); + + IllegalStateException exception31 = assertThrows(IllegalStateException.class, + () -> clientV31.beginSingleLabelClassify(dummyDocument, PROJECT_NAME, DEPLOYMENT_NAME, null, null)); + assertEquals(SINGLE_LABEL_CLASSIFY_ERROR_MESSAGE_31, exception31.getMessage()); + } + + @Test + public void multiLabelClassificationClientSideValidation() { + // Async + StepVerifier.create(asyncClientV30.beginMultiLabelClassify(dummyDocument, PROJECT_NAME, DEPLOYMENT_NAME, + null, null)) + .verifyErrorSatisfies(exception -> { + assertEquals(IllegalStateException.class, exception.getClass()); + assertEquals(MULTI_LABEL_CLASSIFY_ERROR_MESSAGE_30, exception.getMessage()); + }); + StepVerifier.create(asyncClientV31.beginMultiLabelClassify(dummyDocument, PROJECT_NAME, DEPLOYMENT_NAME, + null, null)) + .verifyErrorSatisfies(exception -> { + assertEquals(IllegalStateException.class, exception.getClass()); + assertEquals(MULTI_LABEL_CLASSIFY_ERROR_MESSAGE_31, exception.getMessage()); + }); + + // Sync + IllegalStateException exception30 = assertThrows(IllegalStateException.class, + () -> clientV30.beginMultiLabelClassify(dummyDocument, PROJECT_NAME, DEPLOYMENT_NAME, null, null)); + assertEquals(MULTI_LABEL_CLASSIFY_ERROR_MESSAGE_30, exception30.getMessage()); + + IllegalStateException exception31 = assertThrows(IllegalStateException.class, + () -> clientV31.beginMultiLabelClassify(dummyDocument, PROJECT_NAME, DEPLOYMENT_NAME, null, null)); + assertEquals(MULTI_LABEL_CLASSIFY_ERROR_MESSAGE_31, exception31.getMessage()); + } + + + @Test + public void test() { + for (int i = 0; i < 5; i++) { + try { + throwIfTargetServiceVersionFound(TextAnalyticsServiceVersion.V3_0, + Arrays.asList(TextAnalyticsServiceVersion.V3_0, TextAnalyticsServiceVersion.V3_0), + "a message"); + } catch (IllegalStateException ex) { + System.out.println("i = " + i); + } + } + } +} diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/test/java/com/azure/ai/textanalytics/TestUtils.java b/sdk/textanalytics/azure-ai-textanalytics/src/test/java/com/azure/ai/textanalytics/TestUtils.java index 65c02552a4b7e..a1b1f2d3c325b 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/test/java/com/azure/ai/textanalytics/TestUtils.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/test/java/com/azure/ai/textanalytics/TestUtils.java @@ -899,24 +899,15 @@ static AnalyzeHealthcareEntitiesResult getRecognizeHealthcareEntitiesResult2() { HealthcareEntityPropertiesHelper.setDataSources(healthcareEntity2, IterableStream.of(Collections.emptyList())); final HealthcareEntity healthcareEntity3 = new HealthcareEntity(); - HealthcareEntityPropertiesHelper.setText(healthcareEntity3, "ST depressions"); - HealthcareEntityPropertiesHelper.setNormalizedText(healthcareEntity3, "ST segment depression (finding)"); + HealthcareEntityPropertiesHelper.setText(healthcareEntity3, "ST depressions in the anterior lateral leads"); +// HealthcareEntityPropertiesHelper.setNormalizedText(healthcareEntity3, null); HealthcareEntityPropertiesHelper.setCategory(healthcareEntity3, HealthcareEntityCategory.SYMPTOM_OR_SIGN); HealthcareEntityPropertiesHelper.setConfidenceScore(healthcareEntity3, 1.0); HealthcareEntityPropertiesHelper.setOffset(healthcareEntity3, 46); - HealthcareEntityPropertiesHelper.setLength(healthcareEntity3, 14); + HealthcareEntityPropertiesHelper.setLength(healthcareEntity3, 44); // there are too many healthcare entity data sources, we can just assert it is not null. HealthcareEntityPropertiesHelper.setDataSources(healthcareEntity3, IterableStream.of(Collections.emptyList())); - final HealthcareEntity healthcareEntity4 = new HealthcareEntity(); - HealthcareEntityPropertiesHelper.setText(healthcareEntity4, "anterior lateral"); - HealthcareEntityPropertiesHelper.setCategory(healthcareEntity4, HealthcareEntityCategory.DIRECTION); - HealthcareEntityPropertiesHelper.setConfidenceScore(healthcareEntity4, 0.6); - HealthcareEntityPropertiesHelper.setOffset(healthcareEntity4, 68); - HealthcareEntityPropertiesHelper.setLength(healthcareEntity4, 16); - // there are too many healthcare entity data sources, we can just assert it is not null. - HealthcareEntityPropertiesHelper.setDataSources(healthcareEntity4, - IterableStream.of(Collections.emptyList())); final HealthcareEntity healthcareEntity5 = new HealthcareEntity(); HealthcareEntityPropertiesHelper.setText(healthcareEntity5, "fatigue"); HealthcareEntityPropertiesHelper.setNormalizedText(healthcareEntity5, "Fatigue"); @@ -952,7 +943,7 @@ static AnalyzeHealthcareEntitiesResult getRecognizeHealthcareEntitiesResult2() { final AnalyzeHealthcareEntitiesResult healthcareEntitiesResult = new AnalyzeHealthcareEntitiesResult("1", textDocumentStatistics, null); AnalyzeHealthcareEntitiesResultPropertiesHelper.setEntities(healthcareEntitiesResult, - new IterableStream<>(asList(healthcareEntity1, healthcareEntity2, healthcareEntity3, healthcareEntity4, + new IterableStream<>(asList(healthcareEntity1, healthcareEntity2, healthcareEntity3, healthcareEntity5, healthcareEntity6, healthcareEntity7))); // HealthcareEntityRelations @@ -976,18 +967,8 @@ static AnalyzeHealthcareEntitiesResult getRecognizeHealthcareEntitiesResult2() { HealthcareEntityRelationType.QUALIFIER_OF_CONDITION); HealthcareEntityRelationPropertiesHelper.setRoles(healthcareEntityRelation2, IterableStream.of(asList(role3, role2))); - - final HealthcareEntityRelation healthcareEntityRelation3 = new HealthcareEntityRelation(); - final HealthcareEntityRelationRole role4 = new HealthcareEntityRelationRole(); - HealthcareEntityRelationRolePropertiesHelper.setName(role4, "Direction"); - HealthcareEntityRelationRolePropertiesHelper.setEntity(role4, healthcareEntity4); - HealthcareEntityRelationPropertiesHelper.setRelationType(healthcareEntityRelation3, - HealthcareEntityRelationType.DIRECTION_OF_CONDITION); - HealthcareEntityRelationPropertiesHelper.setRoles(healthcareEntityRelation3, - IterableStream.of(asList(role2, role4))); - AnalyzeHealthcareEntitiesResultPropertiesHelper.setEntityRelations(healthcareEntitiesResult, - IterableStream.of(asList(healthcareEntityRelation1, healthcareEntityRelation2, healthcareEntityRelation3))); + IterableStream.of(asList(healthcareEntityRelation1, healthcareEntityRelation2))); return healthcareEntitiesResult; } diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/test/java/com/azure/ai/textanalytics/TextAnalyticsAsyncClientTest.java b/sdk/textanalytics/azure-ai-textanalytics/src/test/java/com/azure/ai/textanalytics/TextAnalyticsAsyncClientTest.java index 7b0a158153657..38c0145d728db 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/test/java/com/azure/ai/textanalytics/TextAnalyticsAsyncClientTest.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/test/java/com/azure/ai/textanalytics/TextAnalyticsAsyncClientTest.java @@ -11,11 +11,14 @@ import com.azure.ai.textanalytics.models.ClassifyDocumentOperationDetail; import com.azure.ai.textanalytics.models.EntityConditionality; import com.azure.ai.textanalytics.models.HealthcareEntityAssertion; +import com.azure.ai.textanalytics.models.MultiLabelClassifyOptions; import com.azure.ai.textanalytics.models.PiiEntityCategory; import com.azure.ai.textanalytics.models.PiiEntityDomain; import com.azure.ai.textanalytics.models.RecognizeCustomEntitiesOperationDetail; +import com.azure.ai.textanalytics.models.RecognizeCustomEntitiesOptions; import com.azure.ai.textanalytics.models.RecognizeEntitiesAction; import com.azure.ai.textanalytics.models.RecognizePiiEntitiesOptions; +import com.azure.ai.textanalytics.models.SingleLabelClassifyOptions; import com.azure.ai.textanalytics.models.TargetSentiment; import com.azure.ai.textanalytics.models.TextAnalyticsActions; import com.azure.ai.textanalytics.models.TextAnalyticsError; @@ -30,6 +33,7 @@ import com.azure.core.http.HttpClient; import com.azure.core.util.IterableStream; import com.azure.core.util.polling.LongRunningOperationStatus; +import com.azure.core.util.polling.PollResponse; import com.azure.core.util.polling.SyncPoller; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assertions; @@ -1899,10 +1903,18 @@ public void healthcareLroPagination(HttpClient httpClient, TextAnalyticsServiceV public void healthcareLroWithOptions(HttpClient httpClient, TextAnalyticsServiceVersion serviceVersion) { client = getTextAnalyticsAsyncClient(httpClient, serviceVersion); healthcareLroRunner((documents, options) -> { + boolean isValidApiVersionForDisplayName = serviceVersion != TextAnalyticsServiceVersion.V3_0 + && serviceVersion != TextAnalyticsServiceVersion.V3_1; + if (isValidApiVersionForDisplayName) { + options.setDisplayName("operationName"); + } SyncPoller syncPoller = client.beginAnalyzeHealthcareEntities(documents, options).getSyncPoller(); syncPoller = setPollInterval(syncPoller); - syncPoller.waitForCompletion(); + PollResponse pollResponse = syncPoller.waitForCompletion(); + if (isValidApiVersionForDisplayName) { + assertEquals(options.getDisplayName(), pollResponse.getValue().getDisplayName()); + } AnalyzeHealthcareEntitiesPagedFlux analyzeHealthcareEntitiesPagedFlux = syncPoller.getFinalResult(); validateAnalyzeHealthcareEntitiesResultCollectionList( options.isIncludeStatistics(), @@ -2531,13 +2543,15 @@ public void multiCategoryClassifyAction(HttpClient httpClient, TextAnalyticsServ public void recognizeCustomEntities(HttpClient httpClient, TextAnalyticsServiceVersion serviceVersion) { client = getTextAnalyticsAsyncClient(httpClient, serviceVersion); recognizeCustomEntitiesRunner((documents, parameters) -> { + RecognizeCustomEntitiesOptions options = new RecognizeCustomEntitiesOptions() + .setDisplayName("operationName"); SyncPoller syncPoller = - client.beginRecognizeCustomEntities(documents, parameters.get(0), parameters.get(1), "en", - null).getSyncPoller(); + client.beginRecognizeCustomEntities(documents, parameters.get(0), parameters.get(1), "en", options) + .getSyncPoller(); syncPoller = setPollInterval(syncPoller); - syncPoller.waitForCompletion(); + PollResponse pollResponse = syncPoller.waitForCompletion(); + assertEquals(options.getDisplayName(), pollResponse.getValue().getDisplayName()); RecognizeCustomEntitiesPagedFlux pagedFlux = syncPoller.getFinalResult(); - pagedFlux.toStream().collect(Collectors.toList()).forEach(resultCollection -> resultCollection.forEach(documentResult -> validateCategorizedEntities(documentResult.getEntities().stream().collect(Collectors.toList())))); @@ -2549,11 +2563,13 @@ public void recognizeCustomEntities(HttpClient httpClient, TextAnalyticsServiceV public void singleLabelClassification(HttpClient httpClient, TextAnalyticsServiceVersion serviceVersion) { client = getTextAnalyticsAsyncClient(httpClient, serviceVersion); classifyCustomSingleLabelRunner((documents, parameters) -> { + SingleLabelClassifyOptions options = new SingleLabelClassifyOptions().setDisplayName("operationName"); SyncPoller syncPoller = - client.beginSingleLabelClassify(documents, parameters.get(0), parameters.get(1), "en", - null).getSyncPoller(); + client.beginSingleLabelClassify(documents, parameters.get(0), parameters.get(1), "en", options) + .getSyncPoller(); syncPoller = setPollInterval(syncPoller); - syncPoller.waitForCompletion(); + PollResponse pollResponse = syncPoller.waitForCompletion(); + assertEquals(options.getDisplayName(), pollResponse.getValue().getDisplayName()); ClassifyDocumentPagedFlux pagedFlux = syncPoller.getFinalResult(); pagedFlux.toStream().collect(Collectors.toList()).forEach(resultCollection -> resultCollection.forEach(documentResult -> validateLabelClassificationResult(documentResult))); @@ -2565,10 +2581,13 @@ public void singleLabelClassification(HttpClient httpClient, TextAnalyticsServic public void multiLabelClassification(HttpClient httpClient, TextAnalyticsServiceVersion serviceVersion) { client = getTextAnalyticsAsyncClient(httpClient, serviceVersion); classifyCustomMultiLabelRunner((documents, parameters) -> { + MultiLabelClassifyOptions options = new MultiLabelClassifyOptions().setDisplayName("operationName"); SyncPoller syncPoller = - client.beginMultiLabelClassify(documents, parameters.get(0), parameters.get(1), "en", null).getSyncPoller(); + client.beginMultiLabelClassify(documents, parameters.get(0), parameters.get(1), "en", options) + .getSyncPoller(); syncPoller = setPollInterval(syncPoller); - syncPoller.waitForCompletion(); + PollResponse pollResponse = syncPoller.waitForCompletion(); + assertEquals(options.getDisplayName(), pollResponse.getValue().getDisplayName()); ClassifyDocumentPagedFlux pagedFlux = syncPoller.getFinalResult(); pagedFlux.toStream().collect(Collectors.toList()).forEach(resultCollection -> resultCollection.forEach(documentResult -> validateLabelClassificationResult(documentResult))); diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/test/java/com/azure/ai/textanalytics/TextAnalyticsClientTest.java b/sdk/textanalytics/azure-ai-textanalytics/src/test/java/com/azure/ai/textanalytics/TextAnalyticsClientTest.java index e47b94f4170da..4ef89a965ede5 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/test/java/com/azure/ai/textanalytics/TextAnalyticsClientTest.java +++ b/sdk/textanalytics/azure-ai-textanalytics/src/test/java/com/azure/ai/textanalytics/TextAnalyticsClientTest.java @@ -15,12 +15,15 @@ import com.azure.ai.textanalytics.models.HealthcareEntityAssertion; import com.azure.ai.textanalytics.models.KeyPhrasesCollection; import com.azure.ai.textanalytics.models.LinkedEntity; +import com.azure.ai.textanalytics.models.MultiLabelClassifyOptions; import com.azure.ai.textanalytics.models.PiiEntityCategory; import com.azure.ai.textanalytics.models.PiiEntityCollection; import com.azure.ai.textanalytics.models.PiiEntityDomain; import com.azure.ai.textanalytics.models.RecognizeCustomEntitiesOperationDetail; +import com.azure.ai.textanalytics.models.RecognizeCustomEntitiesOptions; import com.azure.ai.textanalytics.models.RecognizeEntitiesAction; import com.azure.ai.textanalytics.models.RecognizePiiEntitiesOptions; +import com.azure.ai.textanalytics.models.SingleLabelClassifyOptions; import com.azure.ai.textanalytics.models.TargetSentiment; import com.azure.ai.textanalytics.models.TextAnalyticsActions; import com.azure.ai.textanalytics.models.TextAnalyticsError; @@ -39,6 +42,7 @@ import com.azure.core.util.Context; import com.azure.core.util.IterableStream; import com.azure.core.util.polling.LongRunningOperationStatus; +import com.azure.core.util.polling.PollResponse; import com.azure.core.util.polling.SyncPoller; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Disabled; @@ -438,7 +442,6 @@ public void recognizeEntitiesEmojiFamily(HttpClient httpClient, TextAnalyticsSer CATEGORIZED_ENTITY_INPUTS.get(1) ); } - @ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS) @MethodSource("com.azure.ai.textanalytics.TestUtils#getTestParameters") public void recognizeEntitiesEmojiFamilyWIthSkinToneModifier(HttpClient httpClient, @@ -1815,10 +1818,18 @@ public void analyzeSentimentZalgoText(HttpClient httpClient, TextAnalyticsServic public void healthcareLroWithOptions(HttpClient httpClient, TextAnalyticsServiceVersion serviceVersion) { client = getTextAnalyticsClient(httpClient, serviceVersion); healthcareLroRunner((documents, options) -> { + boolean isValidApiVersionForDisplayName = serviceVersion != TextAnalyticsServiceVersion.V3_0 + && serviceVersion != TextAnalyticsServiceVersion.V3_1; + if (isValidApiVersionForDisplayName) { + options.setDisplayName("operationName"); + } SyncPoller syncPoller = client.beginAnalyzeHealthcareEntities(documents, options, Context.NONE); syncPoller = setPollInterval(syncPoller); - syncPoller.waitForCompletion(); + PollResponse pollResponse = syncPoller.waitForCompletion(); + if (isValidApiVersionForDisplayName) { + assertEquals(options.getDisplayName(), pollResponse.getValue().getDisplayName()); + } AnalyzeHealthcareEntitiesPagedIterable analyzeHealthcareEntitiesPagedIterable = syncPoller.getFinalResult(); validateAnalyzeHealthcareEntitiesResultCollectionList( options.isIncludeStatistics(), @@ -2470,10 +2481,13 @@ public void multiCategoryClassifyAction(HttpClient httpClient, public void recognizeCustomEntities(HttpClient httpClient, TextAnalyticsServiceVersion serviceVersion) { client = getTextAnalyticsClient(httpClient, serviceVersion); recognizeCustomEntitiesRunner((documents, parameters) -> { + RecognizeCustomEntitiesOptions options = new RecognizeCustomEntitiesOptions() + .setDisplayName("operationName"); SyncPoller syncPoller = - client.beginRecognizeCustomEntities(documents, parameters.get(0), parameters.get(1), "en", null); + client.beginRecognizeCustomEntities(documents, parameters.get(0), parameters.get(1), "en", options); syncPoller = setPollInterval(syncPoller); - syncPoller.waitForCompletion(); + PollResponse pollResponse = syncPoller.waitForCompletion(); + assertEquals(options.getDisplayName(), pollResponse.getValue().getDisplayName()); RecognizeCustomEntitiesPagedIterable pagedIterable = syncPoller.getFinalResult(); pagedIterable.forEach(resultCollection -> resultCollection.forEach(documentResult -> @@ -2486,10 +2500,12 @@ public void recognizeCustomEntities(HttpClient httpClient, TextAnalyticsServiceV public void singleLabelClassification(HttpClient httpClient, TextAnalyticsServiceVersion serviceVersion) { client = getTextAnalyticsClient(httpClient, serviceVersion); classifyCustomSingleLabelRunner((documents, parameters) -> { + SingleLabelClassifyOptions options = new SingleLabelClassifyOptions().setDisplayName("operationName"); SyncPoller syncPoller = - client.beginSingleLabelClassify(documents, parameters.get(0), parameters.get(1), "en", null); + client.beginSingleLabelClassify(documents, parameters.get(0), parameters.get(1), "en", options); syncPoller = setPollInterval(syncPoller); - syncPoller.waitForCompletion(); + PollResponse pollResponse = syncPoller.waitForCompletion(); + assertEquals(options.getDisplayName(), pollResponse.getValue().getDisplayName()); ClassifyDocumentPagedIterable pagedIterable = syncPoller.getFinalResult(); pagedIterable.forEach(resultCollection -> resultCollection.forEach(documentResult -> validateLabelClassificationResult(documentResult))); @@ -2501,10 +2517,12 @@ public void singleLabelClassification(HttpClient httpClient, TextAnalyticsServic public void multiLabelClassification(HttpClient httpClient, TextAnalyticsServiceVersion serviceVersion) { client = getTextAnalyticsClient(httpClient, serviceVersion); classifyCustomMultiLabelRunner((documents, parameters) -> { + MultiLabelClassifyOptions options = new MultiLabelClassifyOptions().setDisplayName("operationName"); SyncPoller syncPoller = - client.beginMultiLabelClassify(documents, parameters.get(0), parameters.get(1), "en", null); + client.beginMultiLabelClassify(documents, parameters.get(0), parameters.get(1), "en", options); syncPoller = setPollInterval(syncPoller); - syncPoller.waitForCompletion(); + PollResponse pollResponse = syncPoller.waitForCompletion(); + assertEquals(options.getDisplayName(), pollResponse.getValue().getDisplayName()); ClassifyDocumentPagedIterable pagedIterable = syncPoller.getFinalResult(); pagedIterable.forEach(resultCollection -> resultCollection.forEach(documentResult -> validateLabelClassificationResult(documentResult))); diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/TextAnalyticsAsyncClientTest.multiLabelClassification[1].json b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/TextAnalyticsAsyncClientTest.multiLabelClassification[1].json index a9de5e2387d56..4a3bfa3561de3 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/TextAnalyticsAsyncClientTest.multiLabelClassification[1].json +++ b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/TextAnalyticsAsyncClientTest.multiLabelClassification[1].json @@ -3,59 +3,59 @@ "Method" : "POST", "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs?api-version=2022-05-01", "Headers" : { - "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.4 (11.0.10; Windows 10; 10.0)", - "x-ms-client-request-id" : "f53ab57a-2ef5-449f-a2c2-43f772352bc5", + "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.5 (11.0.6; Windows 10; 10.0)", + "x-ms-client-request-id" : "916e5787-979c-493c-8bb2-ae719e79aab7", "Content-Type" : "application/json" }, "Response" : { "content-length" : "0", - "x-envoy-upstream-service-time" : "509", + "x-envoy-upstream-service-time" : "515", "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", - "operation-location" : "https://javatextanalyticstestresources.cognitiveservices.azure.com/language/analyze-text/jobs/fb41649a-4f2a-4a79-b2b6-3f10c8c89407?api-version=2022-05-01", + "operation-location" : "https://javatextanalyticstestresources.cognitiveservices.azure.com/language/analyze-text/jobs/b8ae4b11-f490-4467-8acd-405e3e52e595?api-version=2022-05-01", "x-content-type-options" : "nosniff", - "apim-request-id" : "079e274c-ee49-4842-8f60-232060e6b851", + "apim-request-id" : "8e94997d-ba80-4fb7-a47c-d1985b8eb03b", "retry-after" : "0", "StatusCode" : "202", - "Date" : "Thu, 11 Aug 2022 18:08:59 GMT" + "Date" : "Thu, 01 Sep 2022 07:36:52 GMT" }, "Exception" : null }, { "Method" : "GET", - "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs/fb41649a-4f2a-4a79-b2b6-3f10c8c89407?api-version=2022-05-01&showStats=false", + "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs/b8ae4b11-f490-4467-8acd-405e3e52e595?api-version=2022-05-01&showStats=false", "Headers" : { - "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.4 (11.0.10; Windows 10; 10.0)", - "x-ms-client-request-id" : "5a38509b-1269-4005-8aa6-e1733abb2492" + "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.5 (11.0.6; Windows 10; 10.0)", + "x-ms-client-request-id" : "4b32e681-f544-4b7b-8aaa-4e410fb31ad5" }, "Response" : { - "content-length" : "641", - "x-envoy-upstream-service-time" : "32", + "content-length" : "671", + "x-envoy-upstream-service-time" : "93", "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", "x-content-type-options" : "nosniff", - "apim-request-id" : "1009ca9a-cce1-473b-b364-b77fbf4b35aa", + "apim-request-id" : "8f11db43-d55b-4a76-9eca-3ac9cb61d1e2", "retry-after" : "0", "StatusCode" : "200", - "Body" : "{\"jobId\":\"fb41649a-4f2a-4a79-b2b6-3f10c8c89407\",\"lastUpdatedDateTime\":\"2022-08-11T18:09:01Z\",\"createdDateTime\":\"2022-08-11T18:09:00Z\",\"expirationDateTime\":\"2022-08-12T18:09:00Z\",\"status\":\"succeeded\",\"errors\":[],\"tasks\":{\"completed\":1,\"failed\":0,\"inProgress\":0,\"total\":1,\"items\":[{\"kind\":\"CustomMultiLabelClassificationLROResults\",\"lastUpdateDateTime\":\"2022-08-11T18:09:01.1086171Z\",\"status\":\"succeeded\",\"results\":{\"documents\":[{\"id\":\"0\",\"class\":[{\"category\":\"BookRestaurant\",\"confidenceScore\":0.97}],\"warnings\":[]}],\"errors\":[],\"projectName\":\"7cdace98-537b-494a-b69a-c19754718025\",\"deploymentName\":\"7cdace98-537b-494a-b69a-c19754718025\"}}]}}", - "Date" : "Thu, 11 Aug 2022 18:09:30 GMT", + "Body" : "{\"jobId\":\"b8ae4b11-f490-4467-8acd-405e3e52e595\",\"lastUpdatedDateTime\":\"2022-09-01T07:36:54Z\",\"createdDateTime\":\"2022-09-01T07:36:53Z\",\"expirationDateTime\":\"2022-09-02T07:36:53Z\",\"status\":\"succeeded\",\"errors\":[],\"displayName\":\"operationName\",\"tasks\":{\"completed\":1,\"failed\":0,\"inProgress\":0,\"total\":1,\"items\":[{\"kind\":\"CustomMultiLabelClassificationLROResults\",\"lastUpdateDateTime\":\"2022-09-01T07:36:54.2430088Z\",\"status\":\"succeeded\",\"results\":{\"documents\":[{\"id\":\"0\",\"class\":[{\"category\":\"BookRestaurant\",\"confidenceScore\":0.97}],\"warnings\":[]}],\"errors\":[],\"projectName\":\"7cdace98-537b-494a-b69a-c19754718025\",\"deploymentName\":\"7cdace98-537b-494a-b69a-c19754718025\"}}]}}", + "Date" : "Thu, 01 Sep 2022 07:37:23 GMT", "Content-Type" : "application/json; charset=utf-8" }, "Exception" : null }, { "Method" : "GET", - "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs/fb41649a-4f2a-4a79-b2b6-3f10c8c89407?api-version=2022-05-01&showStats=false", + "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs/b8ae4b11-f490-4467-8acd-405e3e52e595?api-version=2022-05-01&showStats=false", "Headers" : { - "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.4 (11.0.10; Windows 10; 10.0)", - "x-ms-client-request-id" : "f357d703-486b-494b-979c-9225be8da9fb" + "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.5 (11.0.6; Windows 10; 10.0)", + "x-ms-client-request-id" : "0164272d-5e0f-4ef6-8311-9f3640dd582e" }, "Response" : { - "content-length" : "641", - "x-envoy-upstream-service-time" : "29", + "content-length" : "671", + "x-envoy-upstream-service-time" : "36", "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", "x-content-type-options" : "nosniff", - "apim-request-id" : "638fcb1e-628f-4004-896b-88f379547935", + "apim-request-id" : "bec6b3ec-6099-4a44-a30d-af73da6f8d02", "retry-after" : "0", "StatusCode" : "200", - "Body" : "{\"jobId\":\"fb41649a-4f2a-4a79-b2b6-3f10c8c89407\",\"lastUpdatedDateTime\":\"2022-08-11T18:09:01Z\",\"createdDateTime\":\"2022-08-11T18:09:00Z\",\"expirationDateTime\":\"2022-08-12T18:09:00Z\",\"status\":\"succeeded\",\"errors\":[],\"tasks\":{\"completed\":1,\"failed\":0,\"inProgress\":0,\"total\":1,\"items\":[{\"kind\":\"CustomMultiLabelClassificationLROResults\",\"lastUpdateDateTime\":\"2022-08-11T18:09:01.1086171Z\",\"status\":\"succeeded\",\"results\":{\"documents\":[{\"id\":\"0\",\"class\":[{\"category\":\"BookRestaurant\",\"confidenceScore\":0.97}],\"warnings\":[]}],\"errors\":[],\"projectName\":\"7cdace98-537b-494a-b69a-c19754718025\",\"deploymentName\":\"7cdace98-537b-494a-b69a-c19754718025\"}}]}}", - "Date" : "Thu, 11 Aug 2022 18:09:30 GMT", + "Body" : "{\"jobId\":\"b8ae4b11-f490-4467-8acd-405e3e52e595\",\"lastUpdatedDateTime\":\"2022-09-01T07:36:54Z\",\"createdDateTime\":\"2022-09-01T07:36:53Z\",\"expirationDateTime\":\"2022-09-02T07:36:53Z\",\"status\":\"succeeded\",\"errors\":[],\"displayName\":\"operationName\",\"tasks\":{\"completed\":1,\"failed\":0,\"inProgress\":0,\"total\":1,\"items\":[{\"kind\":\"CustomMultiLabelClassificationLROResults\",\"lastUpdateDateTime\":\"2022-09-01T07:36:54.2430088Z\",\"status\":\"succeeded\",\"results\":{\"documents\":[{\"id\":\"0\",\"class\":[{\"category\":\"BookRestaurant\",\"confidenceScore\":0.97}],\"warnings\":[]}],\"errors\":[],\"projectName\":\"7cdace98-537b-494a-b69a-c19754718025\",\"deploymentName\":\"7cdace98-537b-494a-b69a-c19754718025\"}}]}}", + "Date" : "Thu, 01 Sep 2022 07:37:23 GMT", "Content-Type" : "application/json; charset=utf-8" }, "Exception" : null diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/TextAnalyticsAsyncClientTest.recognizeCustomEntities[1].json b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/TextAnalyticsAsyncClientTest.recognizeCustomEntities[1].json index 1b798e2cc5162..030248c645e7e 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/TextAnalyticsAsyncClientTest.recognizeCustomEntities[1].json +++ b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/TextAnalyticsAsyncClientTest.recognizeCustomEntities[1].json @@ -3,59 +3,59 @@ "Method" : "POST", "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs?api-version=2022-05-01", "Headers" : { - "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.4 (11.0.10; Windows 10; 10.0)", - "x-ms-client-request-id" : "8d7803d1-85bc-487f-a60e-0c3913b25be3", + "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.5 (11.0.6; Windows 10; 10.0)", + "x-ms-client-request-id" : "fbc1851f-4d88-405c-aeb1-f6efb9e96043", "Content-Type" : "application/json" }, "Response" : { "content-length" : "0", - "x-envoy-upstream-service-time" : "170", + "x-envoy-upstream-service-time" : "268", "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", - "operation-location" : "https://javatextanalyticstestresources.cognitiveservices.azure.com/language/analyze-text/jobs/6afcaf9a-b0b7-49ec-aad6-05d24abb6b36?api-version=2022-05-01", + "operation-location" : "https://javatextanalyticstestresources.cognitiveservices.azure.com/language/analyze-text/jobs/17082e50-4823-4f0f-83ae-a2a7a52e689d?api-version=2022-05-01", "x-content-type-options" : "nosniff", - "apim-request-id" : "4e76b7ca-ed4d-4dae-a5b9-be205126539f", + "apim-request-id" : "39461fae-319a-4306-b33a-d5d8945ef513", "retry-after" : "0", "StatusCode" : "202", - "Date" : "Thu, 11 Aug 2022 18:05:55 GMT" + "Date" : "Thu, 01 Sep 2022 07:40:18 GMT" }, "Exception" : null }, { "Method" : "GET", - "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs/6afcaf9a-b0b7-49ec-aad6-05d24abb6b36?api-version=2022-05-01&showStats=false", + "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs/17082e50-4823-4f0f-83ae-a2a7a52e689d?api-version=2022-05-01&showStats=false", "Headers" : { - "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.4 (11.0.10; Windows 10; 10.0)", - "x-ms-client-request-id" : "7402d5ee-370b-4acf-8284-2f11ca11b44f" + "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.5 (11.0.6; Windows 10; 10.0)", + "x-ms-client-request-id" : "2feeb6cf-8cef-4b18-99c2-4d11fe5309fd" }, "Response" : { - "content-length" : "1244", - "x-envoy-upstream-service-time" : "29", + "content-length" : "1274", + "x-envoy-upstream-service-time" : "69", "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", "x-content-type-options" : "nosniff", - "apim-request-id" : "fd61b8c1-ea70-46b7-a147-47a43896ba15", + "apim-request-id" : "c2689873-a120-4411-999f-5ee6097d1658", "retry-after" : "0", "StatusCode" : "200", - "Body" : "{\"jobId\":\"6afcaf9a-b0b7-49ec-aad6-05d24abb6b36\",\"lastUpdatedDateTime\":\"2022-08-11T18:05:56Z\",\"createdDateTime\":\"2022-08-11T18:05:55Z\",\"expirationDateTime\":\"2022-08-12T18:05:55Z\",\"status\":\"succeeded\",\"errors\":[],\"tasks\":{\"completed\":1,\"failed\":0,\"inProgress\":0,\"total\":1,\"items\":[{\"kind\":\"CustomEntityRecognitionLROResults\",\"lastUpdateDateTime\":\"2022-08-11T18:05:56.8652002Z\",\"status\":\"succeeded\",\"results\":{\"documents\":[{\"id\":\"0\",\"entities\":[{\"text\":\"David Schmidt\",\"category\":\"artist\",\"offset\":0,\"length\":13,\"confidenceScore\":0.8},{\"text\":\"Food\",\"category\":\"service\",\"offset\":38,\"length\":4,\"confidenceScore\":0.03},{\"text\":\"Safety\",\"category\":\"geographic_poi\",\"offset\":43,\"length\":6,\"confidenceScore\":0.06},{\"text\":\"International Food\",\"category\":\"geographic_poi\",\"offset\":51,\"length\":18,\"confidenceScore\":0.07},{\"text\":\"Information Council\",\"category\":\"restaurant_name\",\"offset\":70,\"length\":19,\"confidenceScore\":0.1},{\"text\":\"IFIC\",\"category\":\"geographic_poi\",\"offset\":91,\"length\":4,\"confidenceScore\":0.05},{\"text\":\"Washington, D.C.\",\"category\":\"state\",\"offset\":98,\"length\":16,\"confidenceScore\":0.49}],\"warnings\":[]}],\"errors\":[],\"projectName\":\"88ee0f78-fbca-444d-98e2-7c4c8631e494\",\"deploymentName\":\"88ee0f78-fbca-444d-98e2-7c4c8631e494\"}}]}}", - "Date" : "Thu, 11 Aug 2022 18:06:26 GMT", + "Body" : "{\"jobId\":\"17082e50-4823-4f0f-83ae-a2a7a52e689d\",\"lastUpdatedDateTime\":\"2022-09-01T07:40:19Z\",\"createdDateTime\":\"2022-09-01T07:40:18Z\",\"expirationDateTime\":\"2022-09-02T07:40:18Z\",\"status\":\"succeeded\",\"errors\":[],\"displayName\":\"operationName\",\"tasks\":{\"completed\":1,\"failed\":0,\"inProgress\":0,\"total\":1,\"items\":[{\"kind\":\"CustomEntityRecognitionLROResults\",\"lastUpdateDateTime\":\"2022-09-01T07:40:19.2774536Z\",\"status\":\"succeeded\",\"results\":{\"documents\":[{\"id\":\"0\",\"entities\":[{\"text\":\"David Schmidt\",\"category\":\"artist\",\"offset\":0,\"length\":13,\"confidenceScore\":0.8},{\"text\":\"Food\",\"category\":\"service\",\"offset\":38,\"length\":4,\"confidenceScore\":0.03},{\"text\":\"Safety\",\"category\":\"geographic_poi\",\"offset\":43,\"length\":6,\"confidenceScore\":0.06},{\"text\":\"International Food\",\"category\":\"geographic_poi\",\"offset\":51,\"length\":18,\"confidenceScore\":0.07},{\"text\":\"Information Council\",\"category\":\"restaurant_name\",\"offset\":70,\"length\":19,\"confidenceScore\":0.1},{\"text\":\"IFIC\",\"category\":\"geographic_poi\",\"offset\":91,\"length\":4,\"confidenceScore\":0.05},{\"text\":\"Washington, D.C.\",\"category\":\"state\",\"offset\":98,\"length\":16,\"confidenceScore\":0.49}],\"warnings\":[]}],\"errors\":[],\"projectName\":\"88ee0f78-fbca-444d-98e2-7c4c8631e494\",\"deploymentName\":\"88ee0f78-fbca-444d-98e2-7c4c8631e494\"}}]}}", + "Date" : "Thu, 01 Sep 2022 07:40:48 GMT", "Content-Type" : "application/json; charset=utf-8" }, "Exception" : null }, { "Method" : "GET", - "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs/6afcaf9a-b0b7-49ec-aad6-05d24abb6b36?api-version=2022-05-01&showStats=false", + "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs/17082e50-4823-4f0f-83ae-a2a7a52e689d?api-version=2022-05-01&showStats=false", "Headers" : { - "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.4 (11.0.10; Windows 10; 10.0)", - "x-ms-client-request-id" : "754aeb4b-8f66-441c-aeb6-2dedf7a28b3f" + "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.5 (11.0.6; Windows 10; 10.0)", + "x-ms-client-request-id" : "73d1e59d-2da3-4c64-8c84-b78eb26313ec" }, "Response" : { - "content-length" : "1244", - "x-envoy-upstream-service-time" : "34", + "content-length" : "1274", + "x-envoy-upstream-service-time" : "26", "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", "x-content-type-options" : "nosniff", - "apim-request-id" : "30705a54-2950-4769-820f-faa508086405", + "apim-request-id" : "ab0cfd06-99ef-4f14-b171-d2a495de1966", "retry-after" : "0", "StatusCode" : "200", - "Body" : "{\"jobId\":\"6afcaf9a-b0b7-49ec-aad6-05d24abb6b36\",\"lastUpdatedDateTime\":\"2022-08-11T18:05:56Z\",\"createdDateTime\":\"2022-08-11T18:05:55Z\",\"expirationDateTime\":\"2022-08-12T18:05:55Z\",\"status\":\"succeeded\",\"errors\":[],\"tasks\":{\"completed\":1,\"failed\":0,\"inProgress\":0,\"total\":1,\"items\":[{\"kind\":\"CustomEntityRecognitionLROResults\",\"lastUpdateDateTime\":\"2022-08-11T18:05:56.8652002Z\",\"status\":\"succeeded\",\"results\":{\"documents\":[{\"id\":\"0\",\"entities\":[{\"text\":\"David Schmidt\",\"category\":\"artist\",\"offset\":0,\"length\":13,\"confidenceScore\":0.8},{\"text\":\"Food\",\"category\":\"service\",\"offset\":38,\"length\":4,\"confidenceScore\":0.03},{\"text\":\"Safety\",\"category\":\"geographic_poi\",\"offset\":43,\"length\":6,\"confidenceScore\":0.06},{\"text\":\"International Food\",\"category\":\"geographic_poi\",\"offset\":51,\"length\":18,\"confidenceScore\":0.07},{\"text\":\"Information Council\",\"category\":\"restaurant_name\",\"offset\":70,\"length\":19,\"confidenceScore\":0.1},{\"text\":\"IFIC\",\"category\":\"geographic_poi\",\"offset\":91,\"length\":4,\"confidenceScore\":0.05},{\"text\":\"Washington, D.C.\",\"category\":\"state\",\"offset\":98,\"length\":16,\"confidenceScore\":0.49}],\"warnings\":[]}],\"errors\":[],\"projectName\":\"88ee0f78-fbca-444d-98e2-7c4c8631e494\",\"deploymentName\":\"88ee0f78-fbca-444d-98e2-7c4c8631e494\"}}]}}", - "Date" : "Thu, 11 Aug 2022 18:06:26 GMT", + "Body" : "{\"jobId\":\"17082e50-4823-4f0f-83ae-a2a7a52e689d\",\"lastUpdatedDateTime\":\"2022-09-01T07:40:19Z\",\"createdDateTime\":\"2022-09-01T07:40:18Z\",\"expirationDateTime\":\"2022-09-02T07:40:18Z\",\"status\":\"succeeded\",\"errors\":[],\"displayName\":\"operationName\",\"tasks\":{\"completed\":1,\"failed\":0,\"inProgress\":0,\"total\":1,\"items\":[{\"kind\":\"CustomEntityRecognitionLROResults\",\"lastUpdateDateTime\":\"2022-09-01T07:40:19.2774536Z\",\"status\":\"succeeded\",\"results\":{\"documents\":[{\"id\":\"0\",\"entities\":[{\"text\":\"David Schmidt\",\"category\":\"artist\",\"offset\":0,\"length\":13,\"confidenceScore\":0.8},{\"text\":\"Food\",\"category\":\"service\",\"offset\":38,\"length\":4,\"confidenceScore\":0.03},{\"text\":\"Safety\",\"category\":\"geographic_poi\",\"offset\":43,\"length\":6,\"confidenceScore\":0.06},{\"text\":\"International Food\",\"category\":\"geographic_poi\",\"offset\":51,\"length\":18,\"confidenceScore\":0.07},{\"text\":\"Information Council\",\"category\":\"restaurant_name\",\"offset\":70,\"length\":19,\"confidenceScore\":0.1},{\"text\":\"IFIC\",\"category\":\"geographic_poi\",\"offset\":91,\"length\":4,\"confidenceScore\":0.05},{\"text\":\"Washington, D.C.\",\"category\":\"state\",\"offset\":98,\"length\":16,\"confidenceScore\":0.49}],\"warnings\":[]}],\"errors\":[],\"projectName\":\"88ee0f78-fbca-444d-98e2-7c4c8631e494\",\"deploymentName\":\"88ee0f78-fbca-444d-98e2-7c4c8631e494\"}}]}}", + "Date" : "Thu, 01 Sep 2022 07:40:48 GMT", "Content-Type" : "application/json; charset=utf-8" }, "Exception" : null diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/TextAnalyticsAsyncClientTest.singleLabelClassification[1].json b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/TextAnalyticsAsyncClientTest.singleLabelClassification[1].json index cfcc57c0484d7..5fad6ccbe76bd 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/TextAnalyticsAsyncClientTest.singleLabelClassification[1].json +++ b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/TextAnalyticsAsyncClientTest.singleLabelClassification[1].json @@ -3,59 +3,59 @@ "Method" : "POST", "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs?api-version=2022-05-01", "Headers" : { - "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.4 (11.0.10; Windows 10; 10.0)", - "x-ms-client-request-id" : "a19f8c2d-a218-462d-a230-2bb6e95134a0", + "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.5 (11.0.6; Windows 10; 10.0)", + "x-ms-client-request-id" : "e398859f-3d43-4e70-b5ec-ad680b9b7081", "Content-Type" : "application/json" }, "Response" : { "content-length" : "0", - "x-envoy-upstream-service-time" : "207", + "x-envoy-upstream-service-time" : "220", "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", - "operation-location" : "https://javatextanalyticstestresources.cognitiveservices.azure.com/language/analyze-text/jobs/fba6dfad-4ed1-4796-aa7f-93fed9a1b3fc?api-version=2022-05-01", + "operation-location" : "https://javatextanalyticstestresources.cognitiveservices.azure.com/language/analyze-text/jobs/a48bd328-3e87-4490-b05f-d30e6522bbcd?api-version=2022-05-01", "x-content-type-options" : "nosniff", - "apim-request-id" : "0f7e1458-9544-430b-8abb-e8386e7b1806", + "apim-request-id" : "ee6147b8-64f3-401b-bab6-e29915e1c3e6", "retry-after" : "0", "StatusCode" : "202", - "Date" : "Thu, 11 Aug 2022 18:07:23 GMT" + "Date" : "Thu, 01 Sep 2022 07:38:25 GMT" }, "Exception" : null }, { "Method" : "GET", - "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs/fba6dfad-4ed1-4796-aa7f-93fed9a1b3fc?api-version=2022-05-01&showStats=false", + "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs/a48bd328-3e87-4490-b05f-d30e6522bbcd?api-version=2022-05-01&showStats=false", "Headers" : { - "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.4 (11.0.10; Windows 10; 10.0)", - "x-ms-client-request-id" : "321e692d-18fb-4ec8-8ffa-60091b34bd25" + "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.5 (11.0.6; Windows 10; 10.0)", + "x-ms-client-request-id" : "b36e7a9c-7879-493a-885f-e40d3487fc7b" }, "Response" : { - "content-length" : "636", - "x-envoy-upstream-service-time" : "85", + "content-length" : "666", + "x-envoy-upstream-service-time" : "84", "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", "x-content-type-options" : "nosniff", - "apim-request-id" : "44e492ce-4a60-4d48-874c-7cb09c9aa3c0", + "apim-request-id" : "6570b472-1e33-4215-a600-16e6adc377e8", "retry-after" : "0", "StatusCode" : "200", - "Body" : "{\"jobId\":\"fba6dfad-4ed1-4796-aa7f-93fed9a1b3fc\",\"lastUpdatedDateTime\":\"2022-08-11T18:07:24Z\",\"createdDateTime\":\"2022-08-11T18:07:23Z\",\"expirationDateTime\":\"2022-08-12T18:07:23Z\",\"status\":\"succeeded\",\"errors\":[],\"tasks\":{\"completed\":1,\"failed\":0,\"inProgress\":0,\"total\":1,\"items\":[{\"kind\":\"CustomSingleLabelClassificationLROResults\",\"lastUpdateDateTime\":\"2022-08-11T18:07:24.1054342Z\",\"status\":\"succeeded\",\"results\":{\"documents\":[{\"id\":\"0\",\"class\":[{\"category\":\"RateBook\",\"confidenceScore\":0.76}],\"warnings\":[]}],\"errors\":[],\"projectName\":\"659c1851-be0b-4142-b12a-087da9785926\",\"deploymentName\":\"659c1851-be0b-4142-b12a-087da9785926\"}}]}}", - "Date" : "Thu, 11 Aug 2022 18:07:53 GMT", + "Body" : "{\"jobId\":\"a48bd328-3e87-4490-b05f-d30e6522bbcd\",\"lastUpdatedDateTime\":\"2022-09-01T07:38:25Z\",\"createdDateTime\":\"2022-09-01T07:38:25Z\",\"expirationDateTime\":\"2022-09-02T07:38:25Z\",\"status\":\"succeeded\",\"errors\":[],\"displayName\":\"operationName\",\"tasks\":{\"completed\":1,\"failed\":0,\"inProgress\":0,\"total\":1,\"items\":[{\"kind\":\"CustomSingleLabelClassificationLROResults\",\"lastUpdateDateTime\":\"2022-09-01T07:38:25.9609802Z\",\"status\":\"succeeded\",\"results\":{\"documents\":[{\"id\":\"0\",\"class\":[{\"category\":\"RateBook\",\"confidenceScore\":0.76}],\"warnings\":[]}],\"errors\":[],\"projectName\":\"659c1851-be0b-4142-b12a-087da9785926\",\"deploymentName\":\"659c1851-be0b-4142-b12a-087da9785926\"}}]}}", + "Date" : "Thu, 01 Sep 2022 07:38:55 GMT", "Content-Type" : "application/json; charset=utf-8" }, "Exception" : null }, { "Method" : "GET", - "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs/fba6dfad-4ed1-4796-aa7f-93fed9a1b3fc?api-version=2022-05-01&showStats=false", + "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs/a48bd328-3e87-4490-b05f-d30e6522bbcd?api-version=2022-05-01&showStats=false", "Headers" : { - "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.4 (11.0.10; Windows 10; 10.0)", - "x-ms-client-request-id" : "d3422882-35d2-4a75-8ea0-3b46eb542140" + "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.5 (11.0.6; Windows 10; 10.0)", + "x-ms-client-request-id" : "c484eb61-4026-43cf-9993-1b43d1def169" }, "Response" : { - "content-length" : "636", - "x-envoy-upstream-service-time" : "30", + "content-length" : "666", + "x-envoy-upstream-service-time" : "40", "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", "x-content-type-options" : "nosniff", - "apim-request-id" : "7855c368-bd58-4d70-b89a-29babc2e5cd5", + "apim-request-id" : "310cf1c1-ddea-49ec-b0f9-de21f1ba0e17", "retry-after" : "0", "StatusCode" : "200", - "Body" : "{\"jobId\":\"fba6dfad-4ed1-4796-aa7f-93fed9a1b3fc\",\"lastUpdatedDateTime\":\"2022-08-11T18:07:24Z\",\"createdDateTime\":\"2022-08-11T18:07:23Z\",\"expirationDateTime\":\"2022-08-12T18:07:23Z\",\"status\":\"succeeded\",\"errors\":[],\"tasks\":{\"completed\":1,\"failed\":0,\"inProgress\":0,\"total\":1,\"items\":[{\"kind\":\"CustomSingleLabelClassificationLROResults\",\"lastUpdateDateTime\":\"2022-08-11T18:07:24.1054342Z\",\"status\":\"succeeded\",\"results\":{\"documents\":[{\"id\":\"0\",\"class\":[{\"category\":\"RateBook\",\"confidenceScore\":0.76}],\"warnings\":[]}],\"errors\":[],\"projectName\":\"659c1851-be0b-4142-b12a-087da9785926\",\"deploymentName\":\"659c1851-be0b-4142-b12a-087da9785926\"}}]}}", - "Date" : "Thu, 11 Aug 2022 18:07:53 GMT", + "Body" : "{\"jobId\":\"a48bd328-3e87-4490-b05f-d30e6522bbcd\",\"lastUpdatedDateTime\":\"2022-09-01T07:38:25Z\",\"createdDateTime\":\"2022-09-01T07:38:25Z\",\"expirationDateTime\":\"2022-09-02T07:38:25Z\",\"status\":\"succeeded\",\"errors\":[],\"displayName\":\"operationName\",\"tasks\":{\"completed\":1,\"failed\":0,\"inProgress\":0,\"total\":1,\"items\":[{\"kind\":\"CustomSingleLabelClassificationLROResults\",\"lastUpdateDateTime\":\"2022-09-01T07:38:25.9609802Z\",\"status\":\"succeeded\",\"results\":{\"documents\":[{\"id\":\"0\",\"class\":[{\"category\":\"RateBook\",\"confidenceScore\":0.76}],\"warnings\":[]}],\"errors\":[],\"projectName\":\"659c1851-be0b-4142-b12a-087da9785926\",\"deploymentName\":\"659c1851-be0b-4142-b12a-087da9785926\"}}]}}", + "Date" : "Thu, 01 Sep 2022 07:38:55 GMT", "Content-Type" : "application/json; charset=utf-8" }, "Exception" : null diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/TextAnalyticsClientTest.multiLabelClassification[1].json b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/TextAnalyticsClientTest.multiLabelClassification[1].json index f06de3005dff9..5524cc06656b1 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/TextAnalyticsClientTest.multiLabelClassification[1].json +++ b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/TextAnalyticsClientTest.multiLabelClassification[1].json @@ -3,59 +3,59 @@ "Method" : "POST", "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs?api-version=2022-05-01", "Headers" : { - "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.4 (11.0.10; Windows 10; 10.0)", - "x-ms-client-request-id" : "45d4ee22-71c8-4ce3-b32f-af1243086200", + "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.5 (11.0.6; Windows 10; 10.0)", + "x-ms-client-request-id" : "3858227c-5e8e-4cea-8d2a-8f195dbfeb08", "Content-Type" : "application/json" }, "Response" : { "content-length" : "0", - "x-envoy-upstream-service-time" : "160", + "x-envoy-upstream-service-time" : "353", "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", - "operation-location" : "https://javatextanalyticstestresources.cognitiveservices.azure.com/language/analyze-text/jobs/dc7cd7b5-6ed5-4e57-8030-a1d301ba9f5b?api-version=2022-05-01", + "operation-location" : "https://javatextanalyticstestresources.cognitiveservices.azure.com/language/analyze-text/jobs/2e40913c-90a7-4818-95ed-444f13f80607?api-version=2022-05-01", "x-content-type-options" : "nosniff", - "apim-request-id" : "eb427312-69de-4cb7-8a1d-e846f2a75274", + "apim-request-id" : "67e06ff1-25fa-4d7e-a9db-8c787ee53350", "retry-after" : "0", "StatusCode" : "202", - "Date" : "Thu, 11 Aug 2022 18:09:47 GMT" + "Date" : "Thu, 01 Sep 2022 05:40:33 GMT" }, "Exception" : null }, { "Method" : "GET", - "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs/dc7cd7b5-6ed5-4e57-8030-a1d301ba9f5b?api-version=2022-05-01&showStats=false", + "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs/2e40913c-90a7-4818-95ed-444f13f80607?api-version=2022-05-01&showStats=false", "Headers" : { - "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.4 (11.0.10; Windows 10; 10.0)", - "x-ms-client-request-id" : "d714b038-867f-45d8-90f5-0b960002216f" + "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.5 (11.0.6; Windows 10; 10.0)", + "x-ms-client-request-id" : "0357c5da-a298-4100-a96f-770876605a87" }, "Response" : { - "content-length" : "641", - "x-envoy-upstream-service-time" : "35", + "content-length" : "671", + "x-envoy-upstream-service-time" : "161", "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", "x-content-type-options" : "nosniff", - "apim-request-id" : "5076115d-b04a-4526-b70f-701520ec4d24", + "apim-request-id" : "fe90b9f9-0993-4454-bf9e-a527e25665e7", "retry-after" : "0", "StatusCode" : "200", - "Body" : "{\"jobId\":\"dc7cd7b5-6ed5-4e57-8030-a1d301ba9f5b\",\"lastUpdatedDateTime\":\"2022-08-11T18:09:48Z\",\"createdDateTime\":\"2022-08-11T18:09:47Z\",\"expirationDateTime\":\"2022-08-12T18:09:47Z\",\"status\":\"succeeded\",\"errors\":[],\"tasks\":{\"completed\":1,\"failed\":0,\"inProgress\":0,\"total\":1,\"items\":[{\"kind\":\"CustomMultiLabelClassificationLROResults\",\"lastUpdateDateTime\":\"2022-08-11T18:09:48.5525148Z\",\"status\":\"succeeded\",\"results\":{\"documents\":[{\"id\":\"0\",\"class\":[{\"category\":\"BookRestaurant\",\"confidenceScore\":0.97}],\"warnings\":[]}],\"errors\":[],\"projectName\":\"7cdace98-537b-494a-b69a-c19754718025\",\"deploymentName\":\"7cdace98-537b-494a-b69a-c19754718025\"}}]}}", - "Date" : "Thu, 11 Aug 2022 18:10:18 GMT", + "Body" : "{\"jobId\":\"2e40913c-90a7-4818-95ed-444f13f80607\",\"lastUpdatedDateTime\":\"2022-09-01T05:40:34Z\",\"createdDateTime\":\"2022-09-01T05:40:33Z\",\"expirationDateTime\":\"2022-09-02T05:40:33Z\",\"status\":\"succeeded\",\"errors\":[],\"displayName\":\"operationName\",\"tasks\":{\"completed\":1,\"failed\":0,\"inProgress\":0,\"total\":1,\"items\":[{\"kind\":\"CustomMultiLabelClassificationLROResults\",\"lastUpdateDateTime\":\"2022-09-01T05:40:34.5308547Z\",\"status\":\"succeeded\",\"results\":{\"documents\":[{\"id\":\"0\",\"class\":[{\"category\":\"BookRestaurant\",\"confidenceScore\":0.97}],\"warnings\":[]}],\"errors\":[],\"projectName\":\"7cdace98-537b-494a-b69a-c19754718025\",\"deploymentName\":\"7cdace98-537b-494a-b69a-c19754718025\"}}]}}", + "Date" : "Thu, 01 Sep 2022 05:41:04 GMT", "Content-Type" : "application/json; charset=utf-8" }, "Exception" : null }, { "Method" : "GET", - "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs/dc7cd7b5-6ed5-4e57-8030-a1d301ba9f5b?api-version=2022-05-01&showStats=false", + "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs/2e40913c-90a7-4818-95ed-444f13f80607?api-version=2022-05-01&showStats=false", "Headers" : { - "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.4 (11.0.10; Windows 10; 10.0)", - "x-ms-client-request-id" : "c474ab81-52b2-4658-a699-6c65edf7c8e5" + "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.5 (11.0.6; Windows 10; 10.0)", + "x-ms-client-request-id" : "0fad095e-8b2c-4a20-8d5b-2c34cea728ba" }, "Response" : { - "content-length" : "641", - "x-envoy-upstream-service-time" : "34", + "content-length" : "671", + "x-envoy-upstream-service-time" : "28", "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", "x-content-type-options" : "nosniff", - "apim-request-id" : "df0bba47-3684-433f-a53e-f6ec20b43377", + "apim-request-id" : "cd4a0a6b-facd-491e-a287-15ecb6438e62", "retry-after" : "0", "StatusCode" : "200", - "Body" : "{\"jobId\":\"dc7cd7b5-6ed5-4e57-8030-a1d301ba9f5b\",\"lastUpdatedDateTime\":\"2022-08-11T18:09:48Z\",\"createdDateTime\":\"2022-08-11T18:09:47Z\",\"expirationDateTime\":\"2022-08-12T18:09:47Z\",\"status\":\"succeeded\",\"errors\":[],\"tasks\":{\"completed\":1,\"failed\":0,\"inProgress\":0,\"total\":1,\"items\":[{\"kind\":\"CustomMultiLabelClassificationLROResults\",\"lastUpdateDateTime\":\"2022-08-11T18:09:48.5525148Z\",\"status\":\"succeeded\",\"results\":{\"documents\":[{\"id\":\"0\",\"class\":[{\"category\":\"BookRestaurant\",\"confidenceScore\":0.97}],\"warnings\":[]}],\"errors\":[],\"projectName\":\"7cdace98-537b-494a-b69a-c19754718025\",\"deploymentName\":\"7cdace98-537b-494a-b69a-c19754718025\"}}]}}", - "Date" : "Thu, 11 Aug 2022 18:10:18 GMT", + "Body" : "{\"jobId\":\"2e40913c-90a7-4818-95ed-444f13f80607\",\"lastUpdatedDateTime\":\"2022-09-01T05:40:34Z\",\"createdDateTime\":\"2022-09-01T05:40:33Z\",\"expirationDateTime\":\"2022-09-02T05:40:33Z\",\"status\":\"succeeded\",\"errors\":[],\"displayName\":\"operationName\",\"tasks\":{\"completed\":1,\"failed\":0,\"inProgress\":0,\"total\":1,\"items\":[{\"kind\":\"CustomMultiLabelClassificationLROResults\",\"lastUpdateDateTime\":\"2022-09-01T05:40:34.5308547Z\",\"status\":\"succeeded\",\"results\":{\"documents\":[{\"id\":\"0\",\"class\":[{\"category\":\"BookRestaurant\",\"confidenceScore\":0.97}],\"warnings\":[]}],\"errors\":[],\"projectName\":\"7cdace98-537b-494a-b69a-c19754718025\",\"deploymentName\":\"7cdace98-537b-494a-b69a-c19754718025\"}}]}}", + "Date" : "Thu, 01 Sep 2022 05:41:04 GMT", "Content-Type" : "application/json; charset=utf-8" }, "Exception" : null diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/TextAnalyticsClientTest.recognizeCustomEntities[1].json b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/TextAnalyticsClientTest.recognizeCustomEntities[1].json index c5123c2226176..3de8ad2aad4f8 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/TextAnalyticsClientTest.recognizeCustomEntities[1].json +++ b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/TextAnalyticsClientTest.recognizeCustomEntities[1].json @@ -3,59 +3,59 @@ "Method" : "POST", "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs?api-version=2022-05-01", "Headers" : { - "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.4 (11.0.10; Windows 10; 10.0)", - "x-ms-client-request-id" : "a6433106-5e16-4f88-b459-0af819517ec6", + "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.5 (11.0.6; Windows 10; 10.0)", + "x-ms-client-request-id" : "25bbda73-6652-4f2f-9b4d-451a92075f75", "Content-Type" : "application/json" }, "Response" : { "content-length" : "0", - "x-envoy-upstream-service-time" : "165", + "x-envoy-upstream-service-time" : "265", "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", - "operation-location" : "https://javatextanalyticstestresources.cognitiveservices.azure.com/language/analyze-text/jobs/ae7f4e69-f51a-4814-a9ad-0b1c32d7deee?api-version=2022-05-01", + "operation-location" : "https://javatextanalyticstestresources.cognitiveservices.azure.com/language/analyze-text/jobs/6d988ed7-f490-4b38-a708-53fa8c4aa60b?api-version=2022-05-01", "x-content-type-options" : "nosniff", - "apim-request-id" : "887b110a-e2e6-4dcb-ac3b-292818e862ec", + "apim-request-id" : "8b22955d-693d-4cc5-b6ea-53e96d114d9e", "retry-after" : "0", "StatusCode" : "202", - "Date" : "Thu, 11 Aug 2022 18:06:39 GMT" + "Date" : "Thu, 01 Sep 2022 07:55:46 GMT" }, "Exception" : null }, { "Method" : "GET", - "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs/ae7f4e69-f51a-4814-a9ad-0b1c32d7deee?api-version=2022-05-01&showStats=false", + "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs/6d988ed7-f490-4b38-a708-53fa8c4aa60b?api-version=2022-05-01&showStats=false", "Headers" : { - "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.4 (11.0.10; Windows 10; 10.0)", - "x-ms-client-request-id" : "2bb958e6-bf83-4975-aba7-ddfb4ddf6934" + "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.5 (11.0.6; Windows 10; 10.0)", + "x-ms-client-request-id" : "e74a8441-1a53-4bf3-8147-3ed576031d98" }, "Response" : { - "content-length" : "1243", - "x-envoy-upstream-service-time" : "39", + "content-length" : "1274", + "x-envoy-upstream-service-time" : "98", "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", "x-content-type-options" : "nosniff", - "apim-request-id" : "c2f559e2-8ab0-4992-8402-818bd2871653", + "apim-request-id" : "c2339c6f-7427-46a6-bd10-a3e392b84906", "retry-after" : "0", "StatusCode" : "200", - "Body" : "{\"jobId\":\"ae7f4e69-f51a-4814-a9ad-0b1c32d7deee\",\"lastUpdatedDateTime\":\"2022-08-11T18:06:40Z\",\"createdDateTime\":\"2022-08-11T18:06:39Z\",\"expirationDateTime\":\"2022-08-12T18:06:39Z\",\"status\":\"succeeded\",\"errors\":[],\"tasks\":{\"completed\":1,\"failed\":0,\"inProgress\":0,\"total\":1,\"items\":[{\"kind\":\"CustomEntityRecognitionLROResults\",\"lastUpdateDateTime\":\"2022-08-11T18:06:40.779186Z\",\"status\":\"succeeded\",\"results\":{\"documents\":[{\"id\":\"0\",\"entities\":[{\"text\":\"David Schmidt\",\"category\":\"artist\",\"offset\":0,\"length\":13,\"confidenceScore\":0.8},{\"text\":\"Food\",\"category\":\"service\",\"offset\":38,\"length\":4,\"confidenceScore\":0.03},{\"text\":\"Safety\",\"category\":\"geographic_poi\",\"offset\":43,\"length\":6,\"confidenceScore\":0.06},{\"text\":\"International Food\",\"category\":\"geographic_poi\",\"offset\":51,\"length\":18,\"confidenceScore\":0.07},{\"text\":\"Information Council\",\"category\":\"restaurant_name\",\"offset\":70,\"length\":19,\"confidenceScore\":0.1},{\"text\":\"IFIC\",\"category\":\"geographic_poi\",\"offset\":91,\"length\":4,\"confidenceScore\":0.05},{\"text\":\"Washington, D.C.\",\"category\":\"state\",\"offset\":98,\"length\":16,\"confidenceScore\":0.49}],\"warnings\":[]}],\"errors\":[],\"projectName\":\"88ee0f78-fbca-444d-98e2-7c4c8631e494\",\"deploymentName\":\"88ee0f78-fbca-444d-98e2-7c4c8631e494\"}}]}}", - "Date" : "Thu, 11 Aug 2022 18:07:10 GMT", + "Body" : "{\"jobId\":\"6d988ed7-f490-4b38-a708-53fa8c4aa60b\",\"lastUpdatedDateTime\":\"2022-09-01T07:55:48Z\",\"createdDateTime\":\"2022-09-01T07:55:47Z\",\"expirationDateTime\":\"2022-09-02T07:55:47Z\",\"status\":\"succeeded\",\"errors\":[],\"displayName\":\"operationName\",\"tasks\":{\"completed\":1,\"failed\":0,\"inProgress\":0,\"total\":1,\"items\":[{\"kind\":\"CustomEntityRecognitionLROResults\",\"lastUpdateDateTime\":\"2022-09-01T07:55:48.0894257Z\",\"status\":\"succeeded\",\"results\":{\"documents\":[{\"id\":\"0\",\"entities\":[{\"text\":\"David Schmidt\",\"category\":\"artist\",\"offset\":0,\"length\":13,\"confidenceScore\":0.8},{\"text\":\"Food\",\"category\":\"service\",\"offset\":38,\"length\":4,\"confidenceScore\":0.03},{\"text\":\"Safety\",\"category\":\"geographic_poi\",\"offset\":43,\"length\":6,\"confidenceScore\":0.06},{\"text\":\"International Food\",\"category\":\"geographic_poi\",\"offset\":51,\"length\":18,\"confidenceScore\":0.07},{\"text\":\"Information Council\",\"category\":\"restaurant_name\",\"offset\":70,\"length\":19,\"confidenceScore\":0.1},{\"text\":\"IFIC\",\"category\":\"geographic_poi\",\"offset\":91,\"length\":4,\"confidenceScore\":0.05},{\"text\":\"Washington, D.C.\",\"category\":\"state\",\"offset\":98,\"length\":16,\"confidenceScore\":0.49}],\"warnings\":[]}],\"errors\":[],\"projectName\":\"88ee0f78-fbca-444d-98e2-7c4c8631e494\",\"deploymentName\":\"88ee0f78-fbca-444d-98e2-7c4c8631e494\"}}]}}", + "Date" : "Thu, 01 Sep 2022 07:56:18 GMT", "Content-Type" : "application/json; charset=utf-8" }, "Exception" : null }, { "Method" : "GET", - "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs/ae7f4e69-f51a-4814-a9ad-0b1c32d7deee?api-version=2022-05-01&showStats=false", + "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs/6d988ed7-f490-4b38-a708-53fa8c4aa60b?api-version=2022-05-01&showStats=false", "Headers" : { - "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.4 (11.0.10; Windows 10; 10.0)", - "x-ms-client-request-id" : "c764b4dd-a6fe-44bf-8659-3985f7bf7889" + "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.5 (11.0.6; Windows 10; 10.0)", + "x-ms-client-request-id" : "0b5b11a6-fc6e-4f2a-b5e5-45c427506e18" }, "Response" : { - "content-length" : "1243", - "x-envoy-upstream-service-time" : "87", + "content-length" : "1274", + "x-envoy-upstream-service-time" : "90", "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", "x-content-type-options" : "nosniff", - "apim-request-id" : "cd472300-b80a-47b3-9541-fcf221672a24", + "apim-request-id" : "70a33c07-da33-4df5-9d3a-560999affb85", "retry-after" : "0", "StatusCode" : "200", - "Body" : "{\"jobId\":\"ae7f4e69-f51a-4814-a9ad-0b1c32d7deee\",\"lastUpdatedDateTime\":\"2022-08-11T18:06:40Z\",\"createdDateTime\":\"2022-08-11T18:06:39Z\",\"expirationDateTime\":\"2022-08-12T18:06:39Z\",\"status\":\"succeeded\",\"errors\":[],\"tasks\":{\"completed\":1,\"failed\":0,\"inProgress\":0,\"total\":1,\"items\":[{\"kind\":\"CustomEntityRecognitionLROResults\",\"lastUpdateDateTime\":\"2022-08-11T18:06:40.779186Z\",\"status\":\"succeeded\",\"results\":{\"documents\":[{\"id\":\"0\",\"entities\":[{\"text\":\"David Schmidt\",\"category\":\"artist\",\"offset\":0,\"length\":13,\"confidenceScore\":0.8},{\"text\":\"Food\",\"category\":\"service\",\"offset\":38,\"length\":4,\"confidenceScore\":0.03},{\"text\":\"Safety\",\"category\":\"geographic_poi\",\"offset\":43,\"length\":6,\"confidenceScore\":0.06},{\"text\":\"International Food\",\"category\":\"geographic_poi\",\"offset\":51,\"length\":18,\"confidenceScore\":0.07},{\"text\":\"Information Council\",\"category\":\"restaurant_name\",\"offset\":70,\"length\":19,\"confidenceScore\":0.1},{\"text\":\"IFIC\",\"category\":\"geographic_poi\",\"offset\":91,\"length\":4,\"confidenceScore\":0.05},{\"text\":\"Washington, D.C.\",\"category\":\"state\",\"offset\":98,\"length\":16,\"confidenceScore\":0.49}],\"warnings\":[]}],\"errors\":[],\"projectName\":\"88ee0f78-fbca-444d-98e2-7c4c8631e494\",\"deploymentName\":\"88ee0f78-fbca-444d-98e2-7c4c8631e494\"}}]}}", - "Date" : "Thu, 11 Aug 2022 18:07:10 GMT", + "Body" : "{\"jobId\":\"6d988ed7-f490-4b38-a708-53fa8c4aa60b\",\"lastUpdatedDateTime\":\"2022-09-01T07:55:48Z\",\"createdDateTime\":\"2022-09-01T07:55:47Z\",\"expirationDateTime\":\"2022-09-02T07:55:47Z\",\"status\":\"succeeded\",\"errors\":[],\"displayName\":\"operationName\",\"tasks\":{\"completed\":1,\"failed\":0,\"inProgress\":0,\"total\":1,\"items\":[{\"kind\":\"CustomEntityRecognitionLROResults\",\"lastUpdateDateTime\":\"2022-09-01T07:55:48.0894257Z\",\"status\":\"succeeded\",\"results\":{\"documents\":[{\"id\":\"0\",\"entities\":[{\"text\":\"David Schmidt\",\"category\":\"artist\",\"offset\":0,\"length\":13,\"confidenceScore\":0.8},{\"text\":\"Food\",\"category\":\"service\",\"offset\":38,\"length\":4,\"confidenceScore\":0.03},{\"text\":\"Safety\",\"category\":\"geographic_poi\",\"offset\":43,\"length\":6,\"confidenceScore\":0.06},{\"text\":\"International Food\",\"category\":\"geographic_poi\",\"offset\":51,\"length\":18,\"confidenceScore\":0.07},{\"text\":\"Information Council\",\"category\":\"restaurant_name\",\"offset\":70,\"length\":19,\"confidenceScore\":0.1},{\"text\":\"IFIC\",\"category\":\"geographic_poi\",\"offset\":91,\"length\":4,\"confidenceScore\":0.05},{\"text\":\"Washington, D.C.\",\"category\":\"state\",\"offset\":98,\"length\":16,\"confidenceScore\":0.49}],\"warnings\":[]}],\"errors\":[],\"projectName\":\"88ee0f78-fbca-444d-98e2-7c4c8631e494\",\"deploymentName\":\"88ee0f78-fbca-444d-98e2-7c4c8631e494\"}}]}}", + "Date" : "Thu, 01 Sep 2022 07:56:18 GMT", "Content-Type" : "application/json; charset=utf-8" }, "Exception" : null diff --git a/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/TextAnalyticsClientTest.singleLabelClassification[1].json b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/TextAnalyticsClientTest.singleLabelClassification[1].json index 59bcd61ca5a16..00325d1c26d1b 100644 --- a/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/TextAnalyticsClientTest.singleLabelClassification[1].json +++ b/sdk/textanalytics/azure-ai-textanalytics/src/test/resources/session-records/TextAnalyticsClientTest.singleLabelClassification[1].json @@ -3,59 +3,59 @@ "Method" : "POST", "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs?api-version=2022-05-01", "Headers" : { - "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.4 (11.0.10; Windows 10; 10.0)", - "x-ms-client-request-id" : "7e057d0d-d0b2-4e09-9aea-699726e4cc8f", + "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.5 (11.0.6; Windows 10; 10.0)", + "x-ms-client-request-id" : "2d9858f6-8247-48ce-9a7d-98540e493dd3", "Content-Type" : "application/json" }, "Response" : { "content-length" : "0", - "x-envoy-upstream-service-time" : "297", + "x-envoy-upstream-service-time" : "255", "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", - "operation-location" : "https://javatextanalyticstestresources.cognitiveservices.azure.com/language/analyze-text/jobs/408b6c7d-81d0-49a5-9a45-96ea6ca0627f?api-version=2022-05-01", + "operation-location" : "https://javatextanalyticstestresources.cognitiveservices.azure.com/language/analyze-text/jobs/fe56e4d1-fb20-43ed-baa3-bfc40cc5df10?api-version=2022-05-01", "x-content-type-options" : "nosniff", - "apim-request-id" : "18d378dd-4652-4273-a9f7-86e2c84049d6", + "apim-request-id" : "305a429a-9a9b-4f3d-87ef-fe45843c57a3", "retry-after" : "0", "StatusCode" : "202", - "Date" : "Thu, 11 Aug 2022 18:08:03 GMT" + "Date" : "Thu, 01 Sep 2022 05:45:15 GMT" }, "Exception" : null }, { "Method" : "GET", - "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs/408b6c7d-81d0-49a5-9a45-96ea6ca0627f?api-version=2022-05-01&showStats=false", + "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs/fe56e4d1-fb20-43ed-baa3-bfc40cc5df10?api-version=2022-05-01&showStats=false", "Headers" : { - "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.4 (11.0.10; Windows 10; 10.0)", - "x-ms-client-request-id" : "93d69bfa-e0fa-47dc-9c75-cff9c1205cff" + "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.5 (11.0.6; Windows 10; 10.0)", + "x-ms-client-request-id" : "423bf8c8-0d5c-46da-bb10-807b48399f2a" }, "Response" : { - "content-length" : "636", - "x-envoy-upstream-service-time" : "41", + "content-length" : "666", + "x-envoy-upstream-service-time" : "28", "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", "x-content-type-options" : "nosniff", - "apim-request-id" : "f85b7c04-e006-4d58-8014-7bce9f0ebe93", + "apim-request-id" : "1f956745-3f5e-4f48-89cf-7993da51fef6", "retry-after" : "0", "StatusCode" : "200", - "Body" : "{\"jobId\":\"408b6c7d-81d0-49a5-9a45-96ea6ca0627f\",\"lastUpdatedDateTime\":\"2022-08-11T18:08:05Z\",\"createdDateTime\":\"2022-08-11T18:08:04Z\",\"expirationDateTime\":\"2022-08-12T18:08:04Z\",\"status\":\"succeeded\",\"errors\":[],\"tasks\":{\"completed\":1,\"failed\":0,\"inProgress\":0,\"total\":1,\"items\":[{\"kind\":\"CustomSingleLabelClassificationLROResults\",\"lastUpdateDateTime\":\"2022-08-11T18:08:05.1332387Z\",\"status\":\"succeeded\",\"results\":{\"documents\":[{\"id\":\"0\",\"class\":[{\"category\":\"RateBook\",\"confidenceScore\":0.76}],\"warnings\":[]}],\"errors\":[],\"projectName\":\"659c1851-be0b-4142-b12a-087da9785926\",\"deploymentName\":\"659c1851-be0b-4142-b12a-087da9785926\"}}]}}", - "Date" : "Thu, 11 Aug 2022 18:08:34 GMT", + "Body" : "{\"jobId\":\"fe56e4d1-fb20-43ed-baa3-bfc40cc5df10\",\"lastUpdatedDateTime\":\"2022-09-01T05:45:16Z\",\"createdDateTime\":\"2022-09-01T05:45:16Z\",\"expirationDateTime\":\"2022-09-02T05:45:16Z\",\"status\":\"succeeded\",\"errors\":[],\"displayName\":\"operationName\",\"tasks\":{\"completed\":1,\"failed\":0,\"inProgress\":0,\"total\":1,\"items\":[{\"kind\":\"CustomSingleLabelClassificationLROResults\",\"lastUpdateDateTime\":\"2022-09-01T05:45:16.7028975Z\",\"status\":\"succeeded\",\"results\":{\"documents\":[{\"id\":\"0\",\"class\":[{\"category\":\"RateBook\",\"confidenceScore\":0.76}],\"warnings\":[]}],\"errors\":[],\"projectName\":\"659c1851-be0b-4142-b12a-087da9785926\",\"deploymentName\":\"659c1851-be0b-4142-b12a-087da9785926\"}}]}}", + "Date" : "Thu, 01 Sep 2022 05:45:46 GMT", "Content-Type" : "application/json; charset=utf-8" }, "Exception" : null }, { "Method" : "GET", - "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs/408b6c7d-81d0-49a5-9a45-96ea6ca0627f?api-version=2022-05-01&showStats=false", + "Uri" : "https://REDACTED.cognitiveservices.azure.com/language/analyze-text/jobs/fe56e4d1-fb20-43ed-baa3-bfc40cc5df10?api-version=2022-05-01&showStats=false", "Headers" : { - "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.4 (11.0.10; Windows 10; 10.0)", - "x-ms-client-request-id" : "dc2e57d7-cc45-4ad6-97ef-0d1312573e32" + "User-Agent" : "azsdk-java-azure-ai-textanalytics/5.2.0-beta.5 (11.0.6; Windows 10; 10.0)", + "x-ms-client-request-id" : "cfd09d9b-7bbc-47ff-9626-696d742c295e" }, "Response" : { - "content-length" : "636", - "x-envoy-upstream-service-time" : "26", + "content-length" : "666", + "x-envoy-upstream-service-time" : "25", "Strict-Transport-Security" : "max-age=31536000; includeSubDomains; preload", "x-content-type-options" : "nosniff", - "apim-request-id" : "b219ca73-4cad-407e-b0ac-ffab3977310f", + "apim-request-id" : "d5a3b9b9-defc-4a19-8570-879f88d2eabb", "retry-after" : "0", "StatusCode" : "200", - "Body" : "{\"jobId\":\"408b6c7d-81d0-49a5-9a45-96ea6ca0627f\",\"lastUpdatedDateTime\":\"2022-08-11T18:08:05Z\",\"createdDateTime\":\"2022-08-11T18:08:04Z\",\"expirationDateTime\":\"2022-08-12T18:08:04Z\",\"status\":\"succeeded\",\"errors\":[],\"tasks\":{\"completed\":1,\"failed\":0,\"inProgress\":0,\"total\":1,\"items\":[{\"kind\":\"CustomSingleLabelClassificationLROResults\",\"lastUpdateDateTime\":\"2022-08-11T18:08:05.1332387Z\",\"status\":\"succeeded\",\"results\":{\"documents\":[{\"id\":\"0\",\"class\":[{\"category\":\"RateBook\",\"confidenceScore\":0.76}],\"warnings\":[]}],\"errors\":[],\"projectName\":\"659c1851-be0b-4142-b12a-087da9785926\",\"deploymentName\":\"659c1851-be0b-4142-b12a-087da9785926\"}}]}}", - "Date" : "Thu, 11 Aug 2022 18:08:34 GMT", + "Body" : "{\"jobId\":\"fe56e4d1-fb20-43ed-baa3-bfc40cc5df10\",\"lastUpdatedDateTime\":\"2022-09-01T05:45:16Z\",\"createdDateTime\":\"2022-09-01T05:45:16Z\",\"expirationDateTime\":\"2022-09-02T05:45:16Z\",\"status\":\"succeeded\",\"errors\":[],\"displayName\":\"operationName\",\"tasks\":{\"completed\":1,\"failed\":0,\"inProgress\":0,\"total\":1,\"items\":[{\"kind\":\"CustomSingleLabelClassificationLROResults\",\"lastUpdateDateTime\":\"2022-09-01T05:45:16.7028975Z\",\"status\":\"succeeded\",\"results\":{\"documents\":[{\"id\":\"0\",\"class\":[{\"category\":\"RateBook\",\"confidenceScore\":0.76}],\"warnings\":[]}],\"errors\":[],\"projectName\":\"659c1851-be0b-4142-b12a-087da9785926\",\"deploymentName\":\"659c1851-be0b-4142-b12a-087da9785926\"}}]}}", + "Date" : "Thu, 01 Sep 2022 05:45:46 GMT", "Content-Type" : "application/json; charset=utf-8" }, "Exception" : null